@alfadocs/ui-kit-debug 1.10.1 → 1.12.4

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 (213) hide show
  1. package/dist/_chunks/{actions-cell-renderer-xfSYiTXQ.js → actions-cell-renderer-BCEjn3-f.js} +2 -2
  2. package/dist/_chunks/{actions-cell-renderer-xfSYiTXQ.js.map → actions-cell-renderer-BCEjn3-f.js.map} +1 -1
  3. package/dist/_chunks/{anamnesis-summary-rows-d44s_whc.js → anamnesis-summary-rows-BfhxWPO3.js} +1421 -1418
  4. package/dist/_chunks/anamnesis-summary-rows-BfhxWPO3.js.map +1 -0
  5. package/dist/_chunks/appointment-card-Dzr3GeVz.js.map +1 -1
  6. package/dist/_chunks/appointment-timeline-DCn0Jx55.js +403 -0
  7. package/dist/_chunks/appointment-timeline-DCn0Jx55.js.map +1 -0
  8. package/dist/_chunks/{balance-badge-cell-C_Qz76x7.js → balance-badge-cell-BrlikHfT.js} +317 -290
  9. package/dist/_chunks/balance-badge-cell-BrlikHfT.js.map +1 -0
  10. package/dist/_chunks/booking-CBHKdsZl.js +2906 -0
  11. package/dist/_chunks/booking-CBHKdsZl.js.map +1 -0
  12. package/dist/_chunks/{chart-Bkr1Sh4o.js → chart-C6eHTxkO.js} +2 -2
  13. package/dist/_chunks/{chart-Bkr1Sh4o.js.map → chart-C6eHTxkO.js.map} +1 -1
  14. package/dist/_chunks/{contact-profile-card-CE9OJKcl.js → contact-profile-card-BMIBr5s9.js} +104 -125
  15. package/dist/_chunks/contact-profile-card-BMIBr5s9.js.map +1 -0
  16. package/dist/_chunks/{control-room-rail-Cj2iX9h_.js → control-room-rail-iO_BCaq1.js} +2 -2
  17. package/dist/_chunks/{control-room-rail-Cj2iX9h_.js.map → control-room-rail-iO_BCaq1.js.map} +1 -1
  18. package/dist/_chunks/{editable-currency-cell-renderer-zLf_bXvL.js → editable-currency-cell-renderer-B7TVZ5ZJ.js} +2 -2
  19. package/dist/_chunks/{editable-currency-cell-renderer-zLf_bXvL.js.map → editable-currency-cell-renderer-B7TVZ5ZJ.js.map} +1 -1
  20. package/dist/_chunks/{face-scheme-BfDi4YkW.js → face-scheme-CZaKm6fG.js} +2 -2
  21. package/dist/_chunks/{face-scheme-BfDi4YkW.js.map → face-scheme-CZaKm6fG.js.map} +1 -1
  22. package/dist/_chunks/{file-manager-Df6hyUYg.js → file-manager-Moc7sUFj.js} +3 -3
  23. package/dist/_chunks/{file-manager-Df6hyUYg.js.map → file-manager-Moc7sUFj.js.map} +1 -1
  24. package/dist/_chunks/format-price-DNqXPa_q.js +61 -0
  25. package/dist/_chunks/format-price-DNqXPa_q.js.map +1 -0
  26. package/dist/_chunks/{header-settings-CVC_davE.js → header-settings-J-ZCAfir.js} +2 -2
  27. package/dist/_chunks/{header-settings-CVC_davE.js.map → header-settings-J-ZCAfir.js.map} +1 -1
  28. package/dist/_chunks/{icon-button-group-D6SVMteH.js → icon-button-group-VCCod3Hz.js} +154 -145
  29. package/dist/_chunks/icon-button-group-VCCod3Hz.js.map +1 -0
  30. package/dist/_chunks/{link-cell-renderer-Cp2MSlJl.js → link-cell-renderer-CenJx-_7.js} +197 -181
  31. package/dist/_chunks/link-cell-renderer-CenJx-_7.js.map +1 -0
  32. package/dist/_chunks/{marketplace-app-shell-Chfdia7m.js → marketplace-app-shell-DDQXQ8hX.js} +2 -2
  33. package/dist/_chunks/{marketplace-app-shell-Chfdia7m.js.map → marketplace-app-shell-DDQXQ8hX.js.map} +1 -1
  34. package/dist/_chunks/{notes-panel-e9cJWVRg.js → notes-panel-CymneXtl.js} +93 -91
  35. package/dist/_chunks/notes-panel-CymneXtl.js.map +1 -0
  36. package/dist/_chunks/{practice-results-BEsAdW-B.js → practice-results-D7ygCj_W.js} +333 -291
  37. package/dist/_chunks/practice-results-D7ygCj_W.js.map +1 -0
  38. package/dist/_chunks/{signature-request-CW30B77U.js → signature-request-DVDTKLjM.js} +2 -2
  39. package/dist/_chunks/{signature-request-CW30B77U.js.map → signature-request-DVDTKLjM.js.map} +1 -1
  40. package/dist/_chunks/{stepper-accordion-BeVMZPuG.js → stepper-accordion-DmVykr5F.js} +91 -88
  41. package/dist/_chunks/stepper-accordion-DmVykr5F.js.map +1 -0
  42. package/dist/_chunks/{theme-toggle-DuMhQNFS.js → theme-toggle-uEwoKjl3.js} +2 -2
  43. package/dist/_chunks/{theme-toggle-DuMhQNFS.js.map → theme-toggle-uEwoKjl3.js.map} +1 -1
  44. package/dist/_chunks/{tool-rail-CHyUmulN.js → tool-rail-8Scslq3X.js} +2 -2
  45. package/dist/_chunks/tool-rail-8Scslq3X.js.map +1 -0
  46. package/dist/_chunks/{whatsapp-button-Ca9towA4.js → whatsapp-button-CuFIHJzG.js} +27 -19
  47. package/dist/_chunks/{whatsapp-button-Ca9towA4.js.map → whatsapp-button-CuFIHJzG.js.map} +1 -1
  48. package/dist/agent-catalog.json +12 -5
  49. package/dist/agent-i18n/en.json +4 -3
  50. package/dist/components/_shared/format-price.d.ts +21 -0
  51. package/dist/components/_shared/format-price.d.ts.map +1 -0
  52. package/dist/components/_shared/index.d.ts +1 -0
  53. package/dist/components/_shared/index.d.ts.map +1 -1
  54. package/dist/components/_shared/stepper.d.ts +28 -2
  55. package/dist/components/_shared/stepper.d.ts.map +1 -1
  56. package/dist/components/appointment-card/appointment-card.d.ts +1 -1
  57. package/dist/components/appointment-card/appointment-card.d.ts.map +1 -1
  58. package/dist/components/appointment-timeline/appointment-timeline.agent.d.ts.map +1 -1
  59. package/dist/components/appointment-timeline/appointment-timeline.d.ts +8 -0
  60. package/dist/components/appointment-timeline/appointment-timeline.d.ts.map +1 -1
  61. package/dist/components/appointment-timeline/index.js +1 -1
  62. package/dist/components/booking/booking-types.d.ts +15 -2
  63. package/dist/components/booking/booking-types.d.ts.map +1 -1
  64. package/dist/components/booking/booking.agent.d.ts.map +1 -1
  65. package/dist/components/booking/booking.d.ts.map +1 -1
  66. package/dist/components/booking/index.js +1 -1
  67. package/dist/components/chart/index.js +1 -1
  68. package/dist/components/contact-profile-card/contact-profile-card.d.ts.map +1 -1
  69. package/dist/components/contact-profile-card/index.js +1 -1
  70. package/dist/components/control-room-rail/index.js +1 -1
  71. package/dist/components/data-table/filters/date-range-filter.d.ts +22 -0
  72. package/dist/components/data-table/filters/date-range-filter.d.ts.map +1 -1
  73. package/dist/components/data-table/index.js +3 -3
  74. package/dist/components/face-scheme/index.js +1 -1
  75. package/dist/components/file-manager/index.js +1 -1
  76. package/dist/components/header-settings/index.js +1 -1
  77. package/dist/components/icon-button-group/icon-button-group.d.ts.map +1 -1
  78. package/dist/components/icon-button-group/index.js +1 -1
  79. package/dist/components/notes-panel/index.js +1 -1
  80. package/dist/components/notes-panel/notes-panel.agent.d.ts.map +1 -1
  81. package/dist/components/notes-panel/notes-panel.d.ts +6 -0
  82. package/dist/components/notes-panel/notes-panel.d.ts.map +1 -1
  83. package/dist/components/patient-table/columns.d.ts.map +1 -1
  84. package/dist/components/patient-table/index.js +1 -1
  85. package/dist/components/practice-results/index.js +1 -1
  86. package/dist/components/practice-results/practice-results.d.ts +18 -0
  87. package/dist/components/practice-results/practice-results.d.ts.map +1 -1
  88. package/dist/components/stepper-accordion/index.js +1 -1
  89. package/dist/components/stepper-accordion/stepper-accordion.d.ts.map +1 -1
  90. package/dist/components/theme-toggle/index.js +1 -1
  91. package/dist/components/tool-rail/index.js +1 -1
  92. package/dist/components/tool-rail/tool-rail.d.ts +1 -1
  93. package/dist/components/tool-rail/tool-rail.d.ts.map +1 -1
  94. package/dist/components/whatsapp-button/index.js +1 -1
  95. package/dist/components/whatsapp-button/whatsapp-button.d.ts.map +1 -1
  96. package/dist/host-compat.css +7 -1
  97. package/dist/i18n/locales/ar.d.ts +4 -0
  98. package/dist/i18n/locales/ar.d.ts.map +1 -1
  99. package/dist/i18n/locales/ar.js +5 -1
  100. package/dist/i18n/locales/ar.js.map +1 -1
  101. package/dist/i18n/locales/de.d.ts +5 -1
  102. package/dist/i18n/locales/de.d.ts.map +1 -1
  103. package/dist/i18n/locales/de.js +6 -2
  104. package/dist/i18n/locales/de.js.map +1 -1
  105. package/dist/i18n/locales/el.d.ts +4 -0
  106. package/dist/i18n/locales/el.d.ts.map +1 -1
  107. package/dist/i18n/locales/el.js +5 -1
  108. package/dist/i18n/locales/el.js.map +1 -1
  109. package/dist/i18n/locales/en.d.ts +4 -0
  110. package/dist/i18n/locales/en.d.ts.map +1 -1
  111. package/dist/i18n/locales/en.js +5 -1
  112. package/dist/i18n/locales/en.js.map +1 -1
  113. package/dist/i18n/locales/es.d.ts +5 -1
  114. package/dist/i18n/locales/es.d.ts.map +1 -1
  115. package/dist/i18n/locales/es.js +6 -2
  116. package/dist/i18n/locales/es.js.map +1 -1
  117. package/dist/i18n/locales/fr.d.ts +5 -1
  118. package/dist/i18n/locales/fr.d.ts.map +1 -1
  119. package/dist/i18n/locales/fr.js +6 -2
  120. package/dist/i18n/locales/fr.js.map +1 -1
  121. package/dist/i18n/locales/hi.d.ts +4 -0
  122. package/dist/i18n/locales/hi.d.ts.map +1 -1
  123. package/dist/i18n/locales/hi.js +5 -1
  124. package/dist/i18n/locales/hi.js.map +1 -1
  125. package/dist/i18n/locales/it.d.ts +4 -0
  126. package/dist/i18n/locales/it.d.ts.map +1 -1
  127. package/dist/i18n/locales/it.js +5 -1
  128. package/dist/i18n/locales/it.js.map +1 -1
  129. package/dist/i18n/locales/ja.d.ts +4 -0
  130. package/dist/i18n/locales/ja.d.ts.map +1 -1
  131. package/dist/i18n/locales/ja.js +5 -1
  132. package/dist/i18n/locales/ja.js.map +1 -1
  133. package/dist/i18n/locales/nl.d.ts +5 -1
  134. package/dist/i18n/locales/nl.d.ts.map +1 -1
  135. package/dist/i18n/locales/nl.js +6 -2
  136. package/dist/i18n/locales/nl.js.map +1 -1
  137. package/dist/i18n/locales/pl.d.ts +4 -0
  138. package/dist/i18n/locales/pl.d.ts.map +1 -1
  139. package/dist/i18n/locales/pl.js +5 -1
  140. package/dist/i18n/locales/pl.js.map +1 -1
  141. package/dist/i18n/locales/pt.d.ts +5 -1
  142. package/dist/i18n/locales/pt.d.ts.map +1 -1
  143. package/dist/i18n/locales/pt.js +6 -2
  144. package/dist/i18n/locales/pt.js.map +1 -1
  145. package/dist/i18n/locales/ro.d.ts +4 -0
  146. package/dist/i18n/locales/ro.d.ts.map +1 -1
  147. package/dist/i18n/locales/ro.js +5 -1
  148. package/dist/i18n/locales/ro.js.map +1 -1
  149. package/dist/i18n/locales/ru.d.ts +4 -0
  150. package/dist/i18n/locales/ru.d.ts.map +1 -1
  151. package/dist/i18n/locales/ru.js +5 -1
  152. package/dist/i18n/locales/ru.js.map +1 -1
  153. package/dist/i18n/locales/sq.d.ts +4 -0
  154. package/dist/i18n/locales/sq.d.ts.map +1 -1
  155. package/dist/i18n/locales/sq.js +5 -1
  156. package/dist/i18n/locales/sq.js.map +1 -1
  157. package/dist/i18n/locales/sv.d.ts +4 -0
  158. package/dist/i18n/locales/sv.d.ts.map +1 -1
  159. package/dist/i18n/locales/sv.js +5 -1
  160. package/dist/i18n/locales/sv.js.map +1 -1
  161. package/dist/i18n/locales/tr.d.ts +4 -0
  162. package/dist/i18n/locales/tr.d.ts.map +1 -1
  163. package/dist/i18n/locales/tr.js +5 -1
  164. package/dist/i18n/locales/tr.js.map +1 -1
  165. package/dist/i18n/locales/zh.d.ts +4 -0
  166. package/dist/i18n/locales/zh.d.ts.map +1 -1
  167. package/dist/i18n/locales/zh.js +5 -1
  168. package/dist/i18n/locales/zh.js.map +1 -1
  169. package/dist/index.js +20 -20
  170. package/dist/locales/ar.json +5 -1
  171. package/dist/locales/de.json +6 -2
  172. package/dist/locales/el.json +5 -1
  173. package/dist/locales/en.json +5 -1
  174. package/dist/locales/es.json +6 -2
  175. package/dist/locales/fr.json +6 -2
  176. package/dist/locales/hi.json +5 -1
  177. package/dist/locales/it.json +5 -1
  178. package/dist/locales/ja.json +5 -1
  179. package/dist/locales/nl.json +6 -2
  180. package/dist/locales/pl.json +5 -1
  181. package/dist/locales/pt.json +6 -2
  182. package/dist/locales/ro.json +5 -1
  183. package/dist/locales/ru.json +5 -1
  184. package/dist/locales/sq.json +5 -1
  185. package/dist/locales/sv.json +5 -1
  186. package/dist/locales/tr.json +5 -1
  187. package/dist/locales/zh.json +5 -1
  188. package/dist/patterns/anamnesis/anamnesis-catalogue.d.ts.map +1 -1
  189. package/dist/patterns/anamnesis/anamnesis-compile.d.ts.map +1 -1
  190. package/dist/patterns/anamnesis/anamnesis-config.d.ts +18 -7
  191. package/dist/patterns/anamnesis/anamnesis-config.d.ts.map +1 -1
  192. package/dist/patterns/anamnesis/anamnesis-types.d.ts +8 -0
  193. package/dist/patterns/anamnesis/anamnesis-types.d.ts.map +1 -1
  194. package/dist/patterns/anamnesis/index.js +1 -1
  195. package/dist/patterns/marketplace-app-shell/index.js +1 -1
  196. package/dist/patterns/signature-request/index.js +1 -1
  197. package/dist/tokens.css +1 -1
  198. package/package.json +1 -1
  199. package/dist/_chunks/anamnesis-summary-rows-d44s_whc.js.map +0 -1
  200. package/dist/_chunks/appointment-timeline-0mwtpErq.js +0 -388
  201. package/dist/_chunks/appointment-timeline-0mwtpErq.js.map +0 -1
  202. package/dist/_chunks/balance-badge-cell-C_Qz76x7.js.map +0 -1
  203. package/dist/_chunks/booking-DHkKcUIl.js +0 -2713
  204. package/dist/_chunks/booking-DHkKcUIl.js.map +0 -1
  205. package/dist/_chunks/contact-profile-card-CE9OJKcl.js.map +0 -1
  206. package/dist/_chunks/icon-button-group-D6SVMteH.js.map +0 -1
  207. package/dist/_chunks/languages-CGLX6Qpe.js +0 -19
  208. package/dist/_chunks/languages-CGLX6Qpe.js.map +0 -1
  209. package/dist/_chunks/link-cell-renderer-Cp2MSlJl.js.map +0 -1
  210. package/dist/_chunks/notes-panel-e9cJWVRg.js.map +0 -1
  211. package/dist/_chunks/practice-results-BEsAdW-B.js.map +0 -1
  212. package/dist/_chunks/stepper-accordion-BeVMZPuG.js.map +0 -1
  213. package/dist/_chunks/tool-rail-CHyUmulN.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"anamnesis-summary-rows-d44s_whc.js","sources":["../../node_modules/lucide-react/dist/esm/icons/archive-restore.mjs","../../node_modules/lucide-react/dist/esm/icons/archive.mjs","../../node_modules/lucide-react/dist/esm/icons/send-horizontal.mjs","../../src/patterns/anamnesis/anamnesis-catalogue.ts","../../src/patterns/anamnesis/anamnesis-config.ts","../../src/patterns/anamnesis/anamnesis-derive.ts","../../src/patterns/anamnesis/anamnesis-format.ts","../../src/patterns/anamnesis/anamnesis-digest.tsx","../../src/patterns/anamnesis/anamnesis-indicators.tsx","../../src/patterns/anamnesis/anamnesis-summary.tsx","../../src/patterns/anamnesis/anamnesis-compile-blocks.ts","../../src/patterns/anamnesis/anamnesis-baseline.ts","../../src/patterns/anamnesis/anamnesis-events.ts","../../src/patterns/anamnesis/anamnesis-event-bar.tsx","../../src/patterns/anamnesis/anamnesis-visit-note.tsx","../../src/patterns/anamnesis/anamnesis-matrix.tsx","../../src/patterns/anamnesis/anamnesis-window.ts","../../src/patterns/anamnesis/anamnesis-evolution-grid.tsx","../../src/patterns/anamnesis/anamnesis-source-blocks.ts","../../src/patterns/anamnesis/anamnesis-evolution.tsx","../../src/patterns/anamnesis/anamnesis-disclosure.ts","../../src/patterns/anamnesis/anamnesis-export.ts","../../src/patterns/anamnesis/anamnesis-export-download.ts","../../src/patterns/anamnesis/anamnesis-export-pdf.ts","../../src/patterns/anamnesis/anamnesis-export-menu.tsx","../../src/patterns/anamnesis/anamnesis-highlight.ts","../../src/patterns/anamnesis/anamnesis-field.tsx","../../src/patterns/anamnesis/anamnesis-targets.ts","../../src/patterns/anamnesis/anamnesis-target-editor.tsx","../../src/patterns/_shared/target-tile.tsx","../../src/patterns/anamnesis/anamnesis-target-strip.tsx","../../src/patterns/anamnesis/anamnesis-compile.tsx","../../src/patterns/anamnesis/anamnesis-intake.tsx","../../src/patterns/anamnesis/anamnesis-readonly.tsx","../../src/patterns/anamnesis/anamnesis-questionnaire.tsx","../../src/patterns/anamnesis/anamnesis.tsx","../../src/patterns/anamnesis/anamnesis-reorder.tsx","../../src/patterns/anamnesis/anamnesis-config-editor.tsx","../../src/patterns/anamnesis/anamnesis-notes.ts","../../src/patterns/anamnesis/anamnesis-i18n.ts","../../src/patterns/anamnesis/anamnesis-summary-rows.ts"],"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 [\"rect\", { width: \"20\", height: \"5\", x: \"2\", y: \"3\", rx: \"1\", key: \"1wp1u1\" }],\n [\"path\", { d: \"M4 8v11a2 2 0 0 0 2 2h2\", key: \"tvwodi\" }],\n [\"path\", { d: \"M20 8v11a2 2 0 0 1-2 2h-2\", key: \"1gkqxj\" }],\n [\"path\", { d: \"m9 15 3-3 3 3\", key: \"1pd0qc\" }],\n [\"path\", { d: \"M12 12v9\", key: \"192myk\" }]\n];\nconst ArchiveRestore = createLucideIcon(\"archive-restore\", __iconNode);\n\nexport { __iconNode, ArchiveRestore as default };\n//# sourceMappingURL=archive-restore.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 [\"rect\", { width: \"20\", height: \"5\", x: \"2\", y: \"3\", rx: \"1\", key: \"1wp1u1\" }],\n [\"path\", { d: \"M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8\", key: \"1s80jp\" }],\n [\"path\", { d: \"M10 12h4\", key: \"a56b0p\" }]\n];\nconst Archive = createLucideIcon(\"archive\", __iconNode);\n\nexport { __iconNode, Archive as default };\n//# sourceMappingURL=archive.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: \"M3.714 3.048a.498.498 0 0 0-.683.627l2.843 7.627a2 2 0 0 1 0 1.396l-2.842 7.627a.498.498 0 0 0 .682.627l18-8.5a.5.5 0 0 0 0-.904z\",\n key: \"117uat\"\n }\n ],\n [\"path\", { d: \"M6 12h16\", key: \"s4cdu5\" }]\n];\nconst SendHorizontal = createLucideIcon(\"send-horizontal\", __iconNode);\n\nexport { __iconNode, SendHorizontal as default };\n//# sourceMappingURL=send-horizontal.mjs.map\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — configuration catalogues */\n/* */\n/* Language-neutral configuration: the numeric parameter definitions */\n/* (anthropometrics + a REPRESENTATIVE lab subset with reference ranges), */\n/* the mock pathology taxonomy, and the declarative intake field registry */\n/* that both the patient intake form and the clinician compile view render */\n/* from. This is deliberately a small, extensible slice — a real practice */\n/* would configure ~50 lab parameters and a full ICD-shaped taxonomy. */\n/* */\n/* Labels are resolved at render time via i18n keys derived from each */\n/* `key`/`code` (e.g. `anamnesis.param.<key>`), so nothing here is a */\n/* user-visible string. Unit SYMBOLS (kg, mg/dL, %) are locale-invariant */\n/* scientific notation and are carried as data on the definition. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport type {\n IntakeSectionDef,\n LabParameterDefinition,\n NumericParameterDef,\n PathologyCode,\n} from './anamnesis-types';\n\n/* ------------------------- Anthropometric params ------------------------ */\n\nexport const ANTHRO_PARAMETERS: NumericParameterDef[] = [\n {\n key: 'weight',\n goal: true,\n group: 'anthropometric',\n unit: 'kg',\n betterDirection: 'down',\n precision: 1,\n },\n {\n key: 'height',\n group: 'anthropometric',\n unit: 'cm',\n betterDirection: 'toRange',\n precision: 0,\n },\n // BMI is computed from weight + height; healthy band 18.5–24.9 (toRange).\n {\n key: 'bmi',\n goal: true,\n group: 'anthropometric',\n unit: 'kg/m²',\n betterDirection: 'toRange',\n referenceRange: { min: 18.5, max: 24.9 },\n precision: 1,\n computed: true,\n },\n {\n key: 'waist',\n group: 'anthropometric',\n unit: 'cm',\n betterDirection: 'down',\n precision: 0,\n },\n {\n key: 'hips',\n group: 'anthropometric',\n unit: 'cm',\n betterDirection: 'down',\n precision: 0,\n },\n {\n key: 'arm',\n group: 'anthropometric',\n unit: 'cm',\n betterDirection: 'down',\n precision: 1,\n },\n // Bioimpedance phase angle — higher is healthier (cellular integrity).\n {\n key: 'phaseAngle',\n group: 'anthropometric',\n unit: '°',\n betterDirection: 'up',\n precision: 1,\n },\n];\n\n/* ------------------------------ Lab params ------------------------------ */\n/* A representative 12-parameter subset. `betterDirection: 'toRange'` means\n * moving into the reference range is the improvement, so the sign of a delta\n * cannot say good/bad on its own — the crux the evolution grid demonstrates. */\n\nexport const LAB_PARAMETERS: LabParameterDefinition[] = [\n {\n key: 'fastingGlucose',\n group: 'lab',\n unit: 'mg/dL',\n referenceRange: { min: 70, max: 99 },\n betterDirection: 'toRange',\n precision: 0,\n },\n {\n key: 'hba1c',\n group: 'lab',\n unit: '%',\n referenceRange: { min: 4.0, max: 5.6 },\n betterDirection: 'toRange',\n precision: 1,\n },\n {\n key: 'totalCholesterol',\n group: 'lab',\n unit: 'mg/dL',\n referenceRange: { max: 200 },\n betterDirection: 'down',\n precision: 0,\n },\n {\n key: 'ldl',\n group: 'lab',\n unit: 'mg/dL',\n referenceRange: { max: 115 },\n betterDirection: 'down',\n precision: 0,\n },\n {\n key: 'hdl',\n group: 'lab',\n unit: 'mg/dL',\n referenceRange: { min: 50 },\n betterDirection: 'up',\n precision: 0,\n },\n {\n key: 'triglycerides',\n group: 'lab',\n unit: 'mg/dL',\n referenceRange: { max: 150 },\n betterDirection: 'down',\n precision: 0,\n },\n {\n key: 'haemoglobin',\n group: 'lab',\n unit: 'g/dL',\n referenceRange: { min: 12.0, max: 15.5 },\n betterDirection: 'toRange',\n precision: 1,\n },\n {\n key: 'vitaminD',\n group: 'lab',\n unit: 'ng/mL',\n referenceRange: { min: 30, max: 100 },\n betterDirection: 'up',\n precision: 0,\n },\n {\n key: 'tsh',\n group: 'lab',\n unit: 'mIU/L',\n referenceRange: { min: 0.4, max: 4.0 },\n betterDirection: 'toRange',\n precision: 1,\n },\n {\n key: 'ferritin',\n group: 'lab',\n unit: 'ng/mL',\n referenceRange: { min: 15, max: 150 },\n betterDirection: 'toRange',\n precision: 0,\n },\n {\n key: 'crp',\n group: 'lab',\n unit: 'mg/L',\n referenceRange: { max: 5 },\n betterDirection: 'down',\n precision: 1,\n },\n {\n key: 'creatinine',\n group: 'lab',\n unit: 'mg/dL',\n referenceRange: { min: 0.5, max: 1.1 },\n betterDirection: 'toRange',\n precision: 2,\n },\n];\n\n/* --------------------------- Dietary-intake params ---------------------- */\n/* What the patient EATS, estimated at each visit — the two figures a nutrition\n * plan is written in. Neither a measurement of the body nor a drawn sample, so\n * a third group with a storage array of its own. `betterDirection` differs per\n * parameter; see each. */\n\nexport const DIETARY_PARAMETERS: NumericParameterDef[] = [\n // No reference range, deliberately: 1,600 kcal/d is a success for one\n // patient and starvation for another, so the only honest reference is the\n // patient's own target and `toRange` reads every change as neutral.\n {\n key: 'energy',\n goal: true,\n group: 'dietary',\n unit: 'kcal/d',\n betterDirection: 'toRange',\n precision: 0,\n },\n // `up` against the RDA floor (≈0.8 g/kg/day) — the shape used for HDL and\n // vitamin D. In weight management the failure mode is eating too little.\n {\n key: 'protein',\n goal: true,\n group: 'dietary',\n unit: 'g/d',\n referenceRange: { min: 60 },\n betterDirection: 'up',\n precision: 0,\n },\n];\n\n/** Every numeric parameter, in evolution-grid row order (anthropometrics,\n * dietary intake, then labs). Callers can slice this to build a smaller grid.\n * Intake sits beside the anthropometrics it explains, and above the bloods\n * that are only drawn once or twice a year. */\nexport const ALL_NUMERIC_PARAMETERS: NumericParameterDef[] = [\n ...ANTHRO_PARAMETERS,\n ...DIETARY_PARAMETERS,\n ...LAB_PARAMETERS,\n];\n\n/** Fast lookup by key. */\nexport const PARAMETER_BY_KEY: Record<string, NumericParameterDef> =\n Object.fromEntries(ALL_NUMERIC_PARAMETERS.map((p) => [p.key, p]));\n\n/* --------------------------- Pathology taxonomy ------------------------- */\n/* 8 families, 2 of them (E66 Obesity, E11 Type 2 diabetes) carrying\n * sub-codes — enough to demonstrate code + sub-code selection, assigned-code\n * badges, and removal. A patient can hold several at once (many-to-many). */\n\nexport const PATHOLOGY_TAXONOMY: PathologyCode[] = [\n { code: 'E66' },\n { code: 'E66.0', parentCode: 'E66' },\n { code: 'E66.9', parentCode: 'E66' },\n { code: 'E11' },\n { code: 'E11.9', parentCode: 'E11' },\n { code: 'E11.6', parentCode: 'E11' },\n { code: 'E78' },\n { code: 'I10' },\n { code: 'E03' },\n { code: 'K58' },\n { code: 'D50' },\n { code: 'E55' },\n];\n\nexport const PATHOLOGY_BY_CODE: Record<string, PathologyCode> =\n Object.fromEntries(PATHOLOGY_TAXONOMY.map((p) => [p.code, p]));\n\n/** i18next uses '.' as its key separator, so a pathology code like `E66.0`\n * must be sanitised before it can be used as an i18n key segment. */\nexport const pathologyLabelKey = (code: string): string =>\n `anamnesis.pathology.${code.replace(/\\./g, '_')}`;\n\n/** Only the leaf/assignable codes (a parent family with sub-codes is a\n * heading, not itself assignable). Parents without sub-codes stay assignable. */\nexport const ASSIGNABLE_PATHOLOGY_CODES: string[] = PATHOLOGY_TAXONOMY.filter(\n (p) => !PATHOLOGY_TAXONOMY.some((c) => c.parentCode === p.code),\n).map((p) => p.code);\n\n/* --------------------------- Intake field registry ---------------------- */\n/* Declarative registry both intake and compile render from — one source of\n * truth for the patient-answerable questionnaire. Field/section/option labels\n * resolve via i18n keys derived from the keys below. */\n\nexport const INTAKE_SECTIONS: IntakeSectionDef[] = [\n {\n key: 'reason',\n fields: [{ key: 'reasonForVisit', required: true, type: 'textarea' }],\n },\n {\n key: 'pharmacological',\n fields: [\n { key: 'knownConditions', required: true, type: 'textarea' },\n { key: 'dailyMedications', required: true, type: 'textarea' },\n { key: 'currentSupplements', type: 'textarea' },\n ],\n },\n {\n key: 'familyHistory',\n fields: [\n { key: 'familyParents', type: 'text' },\n { key: 'familySiblings', type: 'text' },\n { key: 'familyGrandparents', type: 'text' },\n ],\n },\n {\n key: 'symptoms',\n fields: [\n { key: 'bloating', type: 'yesNoDetail', detail: true },\n // Flagged on \"yes\": the seed's one highlight rule, so every story\n // shows a highlighted answer the way a practice's rules would.\n {\n key: 'refluxGastritis',\n type: 'yesNoDetail',\n detail: true,\n highlight: 'whenYes',\n },\n { key: 'tiredness', type: 'yesNoDetail', detail: true },\n {\n key: 'sleepQuality',\n type: 'choice',\n options: ['good', 'fair', 'poor'],\n },\n { key: 'sleepDifficulty', type: 'yesNoDetail', detail: true },\n {\n key: 'bowelHabits',\n type: 'choice',\n options: ['regular', 'constipated', 'diarrhoeal', 'alternating'],\n },\n { key: 'stoolCharacteristics', type: 'text' },\n { key: 'haemorrhoids', type: 'yesNoDetail', detail: true },\n { key: 'diverticula', type: 'yesNoDetail', detail: true },\n { key: 'regularUrination', type: 'yesNoDetail', detail: true },\n {\n key: 'menstrualCycle',\n type: 'choice',\n options: ['regular', 'irregular', 'absent'],\n relevance: 'female',\n },\n ],\n },\n {\n key: 'otherHistory',\n fields: [\n {\n key: 'foodAllergies',\n required: true,\n type: 'yesNoDetail',\n detail: true,\n },\n { key: 'drugAllergies', type: 'yesNoDetail', detail: true },\n { key: 'otherAllergies', type: 'yesNoDetail', detail: true },\n { key: 'foodIntolerances', type: 'yesNoDetail', detail: true },\n {\n key: 'smoking',\n required: true,\n type: 'choice',\n options: ['never', 'former', 'current'],\n },\n { key: 'pastSurgery', type: 'yesNoDetail', detail: true },\n {\n key: 'pregnancies',\n type: 'yesNoDetail',\n detail: true,\n relevance: 'female',\n },\n ],\n },\n {\n key: 'dietaryHistory',\n fields: [\n { key: 'weightSelf', required: true, type: 'number' },\n { key: 'heightSelf', required: true, type: 'number' },\n { key: 'physicalActivity', type: 'textarea' },\n { key: 'lifestyle', type: 'textarea' },\n { key: 'waterPerDay', type: 'number' },\n {\n key: 'fizzyDrinks',\n type: 'choice',\n options: ['never', 'occasionally', 'daily'],\n },\n {\n key: 'alcohol',\n type: 'choice',\n options: ['never', 'occasionally', 'daily'],\n },\n { key: 'coffeePerDay', type: 'number' },\n { key: 'coffeeSugar', type: 'choice', options: ['yes', 'no'] },\n ],\n },\n {\n key: 'recall24h',\n fields: [\n { key: 'breakfast', required: true, type: 'meal' },\n { key: 'morningSnack', type: 'meal' },\n { key: 'lunch', required: true, type: 'meal' },\n { key: 'afternoonSnack', type: 'meal' },\n { key: 'dinner', required: true, type: 'meal' },\n { key: 'afterDinner', type: 'meal' },\n ],\n },\n {\n key: 'foodFrequency',\n fields: [\n { key: 'pulses', type: 'frequency' },\n { key: 'fish', type: 'frequency', detail: true },\n { key: 'eggs', type: 'frequency' },\n { key: 'meatCuredMeat', type: 'frequency', detail: true },\n { key: 'dairy', type: 'frequency', detail: true },\n ],\n },\n];\n\n/** Flat list of every intake field key (in registry order). */\nexport const INTAKE_FIELD_KEYS: string[] = INTAKE_SECTIONS.flatMap((s) =>\n s.fields.map((f) => f.key),\n);\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — practice configuration resolvers */\n/* */\n/* A practice owns its own vocabulary. The kit SEEDS a working default */\n/* (the catalogues) and the practice may relabel, reorder, add to and */\n/* archive it. Three keys are LOCKED — `weight`, `height`, `bmi` — because */\n/* the derivation engine hard-depends on them: BMI is computed from weight */\n/* + height, and the WHO banding only means anything for `bmi`. */\n/* */\n/* `locked` constrains EXISTENCE and IDENTITY, never presentation: a */\n/* locked parameter can be relabelled, given help text and reordered like */\n/* any other; it can never be archived, renamed or deleted. */\n/* */\n/* TWO resolver families, deliberately: */\n/* • configured* — CAPTURE surfaces. Archived descriptors are */\n/* dropped; nothing new can be recorded. */\n/* • all*IncludingArchived — HISTORY surfaces (read-only, evolution, */\n/* the clinician's review of past answers). */\n/* Archived descriptors stay, so archiving a */\n/* field never erases answers recorded under */\n/* it. */\n/* */\n/* Pure and i18n-free: label RESOLUTION (practice label vs i18n key) lives */\n/* in `anamnesis-format.ts`. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport {\n ALL_NUMERIC_PARAMETERS,\n INTAKE_SECTIONS,\n PATHOLOGY_TAXONOMY,\n} from './anamnesis-catalogue';\nimport type {\n ConfigurableDescriptor,\n IntakeFieldDef,\n IntakeSectionDef,\n NumericParameterDef,\n ParameterGroup,\n PathologyCode,\n} from './anamnesis-types';\n\n/* ------------------------------- Locked tier ---------------------------- */\n\n/** The only keys the derivation engine cannot lose. `bmi` is computed from\n * `weight` + `height`; every other key in the kit is read generically. */\nexport const LOCKED_PARAMETER_KEYS: ReadonlySet<string> = new Set([\n 'weight',\n 'height',\n 'bmi',\n]);\n\n/** Whether a numeric parameter is locked against archiving / deletion. */\nexport function isParameterLocked(key: string): boolean {\n return LOCKED_PARAMETER_KEYS.has(key);\n}\n\n/* ----------------------------- Targetable tier -------------------------- */\n\n/** Parameters a plan sets a per-patient GOAL for. Not every number is one: a\n * height is a fact about the patient, and a blood test carries a population\n * reference range rather than a target. The four the nutrition plan is written\n * in — weight, BMI, daily energy, protein — plus waist, which practices have\n * long set a goal for. */\nexport const TARGETABLE_PARAMETER_KEYS: ReadonlySet<string> = new Set([\n 'weight',\n 'bmi',\n 'waist',\n 'energy',\n 'protein',\n]);\n\n/** Whether a per-patient target can be set for this parameter. */\nexport function isParameterTargetable(key: string): boolean {\n return TARGETABLE_PARAMETER_KEYS.has(key);\n}\n\n/* ------------------------------- The config ----------------------------- */\n\n/** A practice's anamnesis vocabulary. Every list is optional: an omitted list\n * falls back to the kit-seeded catalogue, so `undefined` is a fully working\n * configuration and every existing mount keeps rendering unchanged. */\nexport interface PracticeAnamnesisConfig {\n /** Numeric parameters (anthropometrics + labs), in the practice's order. */\n parameters?: readonly NumericParameterDef[];\n /** The intake questionnaire — the practice's own form, transcribed. */\n intakeSections?: readonly IntakeSectionDef[];\n /** The coded pathology taxonomy. */\n pathologies?: readonly PathologyCode[];\n}\n\n/** What the kit ships when a practice has configured nothing. Seeded, not\n * empty — an empty vocabulary renders an empty record. */\nexport const SEEDED_ANAMNESIS_CONFIG: Required<PracticeAnamnesisConfig> = {\n parameters: ALL_NUMERIC_PARAMETERS,\n intakeSections: INTAKE_SECTIONS,\n pathologies: PATHOLOGY_TAXONOMY,\n};\n\n/** Fill every omitted list from the seed. */\nexport function resolveConfig(\n config?: PracticeAnamnesisConfig,\n): Required<PracticeAnamnesisConfig> {\n return {\n parameters: config?.parameters ?? SEEDED_ANAMNESIS_CONFIG.parameters,\n intakeSections:\n config?.intakeSections ?? SEEDED_ANAMNESIS_CONFIG.intakeSections,\n pathologies: config?.pathologies ?? SEEDED_ANAMNESIS_CONFIG.pathologies,\n };\n}\n\n/* --------------------------- Ordering + archiving ----------------------- */\n\n/** Stable sort by `order`, falling back to the descriptor's seeded position so\n * a partially-ordered list never scrambles. */\nfunction ordered<T extends ConfigurableDescriptor>(list: readonly T[]): T[] {\n return list\n .map((item, index) => ({ item, index }))\n .sort(\n (a, b) =>\n (a.item.order ?? a.index) - (b.item.order ?? b.index) ||\n a.index - b.index,\n )\n .map((entry) => entry.item);\n}\n\n/** A descriptor is live unless it was explicitly archived. `enabled` is\n * tri-state on purpose: `undefined` means \"never configured\", i.e. live. */\nfunction isLive(descriptor: ConfigurableDescriptor): boolean {\n return descriptor.enabled !== false;\n}\n\n/* ---------------------------- Numeric parameters ------------------------ */\n\n/** Stamp `locked` from the locked-key set so every consumer reads one source\n * of truth rather than trusting whatever the config claimed. */\nfunction stampLock(def: NumericParameterDef): NumericParameterDef {\n const locked = isParameterLocked(def.key);\n return def.locked === locked ? def : { ...def, locked };\n}\n\n/** Parameters grouped as the grid renders them: group blocks keep their order\n * of first appearance, and `order` sorts WITHIN a group. Sorting across groups\n * would interleave anthropometrics and labs under the grid's group banners. */\nfunction orderedParameters(\n list: readonly NumericParameterDef[],\n): NumericParameterDef[] {\n const groups: ParameterGroup[] = [];\n for (const def of list) {\n if (!groups.includes(def.group)) groups.push(def.group);\n }\n return groups.flatMap((group) =>\n ordered(list.filter((def) => def.group === group)),\n );\n}\n\n/** CAPTURE surfaces: live parameters only. A locked parameter is never\n * dropped, whatever the config says — archiving `weight` would silently break\n * BMI everywhere. */\nexport function configuredParameters(\n config?: PracticeAnamnesisConfig,\n group?: ParameterGroup,\n): NumericParameterDef[] {\n const all = resolveConfig(config).parameters.map(stampLock);\n const live = all.filter((def) => isLive(def) || def.locked);\n const scoped = group ? live.filter((def) => def.group === group) : live;\n return orderedParameters(scoped);\n}\n\n/** HISTORY surfaces: every parameter, archived ones included, so a value\n * recorded under an archived parameter still renders. */\nexport function allParametersIncludingArchived(\n config?: PracticeAnamnesisConfig,\n group?: ParameterGroup,\n): NumericParameterDef[] {\n const all = resolveConfig(config).parameters.map(stampLock);\n const scoped = group ? all.filter((def) => def.group === group) : all;\n return orderedParameters(scoped);\n}\n\n/** Lookup over every parameter, archived included — callers resolving a key\n * read from a record must never miss an archived one. */\nexport function parameterLookup(\n config?: PracticeAnamnesisConfig,\n): Record<string, NumericParameterDef> {\n return Object.fromEntries(\n allParametersIncludingArchived(config).map((def) => [def.key, def]),\n );\n}\n\n/* ---------------------------- Intake questionnaire ---------------------- */\n\nfunction orderedSection(section: IntakeSectionDef): IntakeSectionDef {\n return { ...section, fields: ordered(section.fields) };\n}\n\n/** CAPTURE: the questionnaire as the patient sees it — archived sections and\n * fields dropped, and a section left with no live field dropped with them. */\nexport function configuredSections(\n config?: PracticeAnamnesisConfig,\n): IntakeSectionDef[] {\n return ordered(resolveConfig(config).intakeSections)\n .filter(isLive)\n .map((section) => ({\n ...section,\n fields: ordered(section.fields.filter(isLive)),\n }))\n .filter((section) => section.fields.length > 0);\n}\n\n/** HISTORY: every section and field ever configured, so answers recorded under\n * a since-archived question still render in the record and the read-only view.\n * Using `configuredSections` here would erase them from the screen. */\nexport function allSectionsIncludingArchived(\n config?: PracticeAnamnesisConfig,\n): IntakeSectionDef[] {\n return ordered(resolveConfig(config).intakeSections).map(orderedSection);\n}\n\n/** Flat field lookup across every section, archived included. */\nexport function intakeFieldLookup(\n config?: PracticeAnamnesisConfig,\n): Record<string, IntakeFieldDef> {\n return Object.fromEntries(\n allSectionsIncludingArchived(config).flatMap((section) =>\n section.fields.map((field) => [field.key, field] as const),\n ),\n );\n}\n\n/* ---------------------------- Pathology taxonomy ------------------------ */\n\n/** CAPTURE: live codes, in configured order. */\nexport function configuredPathologies(\n config?: PracticeAnamnesisConfig,\n): PathologyCode[] {\n return ordered(resolveConfig(config).pathologies.filter(isLive));\n}\n\n/** HISTORY: every code, archived included. A code assigned last year must\n * still render its label this year. */\nexport function allPathologiesIncludingArchived(\n config?: PracticeAnamnesisConfig,\n): PathologyCode[] {\n return ordered(resolveConfig(config).pathologies);\n}\n\n/** Lookup by code over the FULL taxonomy. Without this, reading\n * `entry.parentCode` off a practice-added code throws. */\nexport function pathologyLookup(\n config?: PracticeAnamnesisConfig,\n): Record<string, PathologyCode> {\n return Object.fromEntries(\n allPathologiesIncludingArchived(config).map((entry) => [entry.code, entry]),\n );\n}\n\n/** Assignable codes: a family that carries sub-codes is a heading, not itself\n * assignable. Derived from the LIVE taxonomy so an archived code cannot be\n * newly assigned, but stays resolvable for history. */\nexport function assignablePathologyCodes(\n config?: PracticeAnamnesisConfig,\n): string[] {\n const live = configuredPathologies(config);\n return live\n .filter((entry) => !live.some((child) => child.parentCode === entry.code))\n .map((entry) => entry.code);\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — derivations */\n/* */\n/* Pure functions over the domain model. Everything here is DERIVED and */\n/* never stored on the record: BMI, patient age, out-of-range flags, the */\n/* per-visit deltas (with direction-aware good/bad valence), the */\n/* sparkline series, and the two-visit diff used by compare mode. */\n/* */\n/* Valence is the crux: \"down\" is good for weight against a loss target */\n/* but bad for haemoglobin below its reference range, so good/bad is */\n/* derived from the parameter's `betterDirection` + reference range, never */\n/* from the sign of the delta alone. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport { computeBmi as kitComputeBmi } from '../../components/bmi-calculator/bmi';\nimport type {\n AnamnesisRecord,\n MeasurementResult,\n MedicationEntry,\n NumericParameterDef,\n Visit,\n} from './anamnesis-types';\n\n/* ----------------------------- Anthropometrics -------------------------- */\n\n/** Anthropometric parameter keys map to AnthropometricSet fields; `bmi` is\n * computed. Kept as a lookup so the grid can treat anthropometrics + labs\n * uniformly. */\nexport const ANTHRO_FIELD_BY_KEY: Record<\n string,\n keyof Visit['anthropometrics']\n> = {\n weight: 'weightKg',\n height: 'heightCm',\n waist: 'waistCm',\n hips: 'hipsCm',\n arm: 'armCm',\n phaseAngle: 'phaseAngleDeg',\n};\n\n/** `Timestamp` options for the record's calendar dates (visit date, date of\n * birth, cycle start). Every one of them is a date-only ISO string, which\n * `Date` parses as UTC midnight — rendered with the viewer's zone that shows a\n * phantom time (\"13 Apr 2026, 2:00\" in CEST) and, west of UTC, the WRONG DAY.\n * Dropping the time fields and pinning the zone to UTC makes the calendar date\n * render as written, identically in every timezone (and so deterministically\n * in Chromatic). */\nexport const CALENDAR_DATE_FORMAT: Intl.DateTimeFormatOptions = {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n timeZone: 'UTC',\n};\n\n/** `Timestamp` options for a visit stamped with a clock time\n * (`YYYY-MM-DDTHH:mm`, no zone suffix). `Date` parses that form as LOCAL\n * time, so the zone is deliberately NOT pinned here: the UTC pin above would\n * move a 00:30 visit onto the previous day everywhere east of Greenwich. */\nexport const CALENDAR_DATETIME_FORMAT: Intl.DateTimeFormatOptions = {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n};\n\nconst CLOCK_TIME_RE = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}/;\nconst CALENDAR_DAY_RE = /^\\d{4}-\\d{2}-\\d{2}/;\n\n/** Whether a stored ISO string carries a clock time (`YYYY-MM-DDTHH:mm…`).\n * A visit is now an interview with a time stamp, and two interviews of one\n * module on the same day are two visits — the time is what tells them apart. */\nexport function hasClockTime(iso: string | null | undefined): boolean {\n return iso != null && CLOCK_TIME_RE.test(iso);\n}\n\n/** The `YYYY-MM-DD` prefix of a stored date, for day arithmetic that must not\n * see the time: a date-only string is returned unchanged. */\nfunction calendarDayOf(iso: string): string {\n return CALENDAR_DAY_RE.test(iso) ? iso.slice(0, 10) : iso;\n}\n\n/** The `Timestamp` options that render a stored date AS WRITTEN: the UTC pin\n * for a date-only string, local time for a datetime string. One helper, so a\n * header cannot pin a datetime to UTC and print the wrong day. */\nexport function calendarFormatFor(iso: string): Intl.DateTimeFormatOptions {\n return hasClockTime(iso) ? CALENDAR_DATETIME_FORMAT : CALENDAR_DATE_FORMAT;\n}\n\n/** BMI = kg / m². Thin `undefined`-tolerant wrapper over the kit's canonical\n * BMI maths — the anthropometric set leaves unmeasured fields `undefined`,\n * which `bmi-calculator/bmi` (a form-backed component) does not model. The\n * formula itself lives there and is not restated here. */\nexport function computeBmi(\n weightKg: number | null | undefined,\n heightCm: number | null | undefined,\n): number | null {\n return kitComputeBmi(weightKg ?? null, heightCm ?? null);\n}\n\n/** Whether a stored ISO string is a date `Date` can actually read. An archive\n * holds blanks and typos; nothing downstream may throw or print \"NaN\" on one. */\nexport function isReadableDate(iso: string | null | undefined): boolean {\n return iso != null && !Number.isNaN(new Date(iso).getTime());\n}\n\n/** Whole-years age at a reference instant, or `null` when either date is\n * unreadable OR the reference predates the birth — an unknown age is absent,\n * never `NaN` and never negative. Reference is the record's\n * own visit date (deterministic for stories / Chromatic), not the wall clock.\n * Read in UTC because both inputs are date-only strings, which `Date` parses as\n * UTC midnight: local getters return the previous day west of UTC. */\nexport function ageAt(dobIso: string, referenceIso: string): number | null {\n if (!isReadableDate(dobIso) || !isReadableDate(referenceIso)) return null;\n // Calendar days only: a reference visit stamped 00:30 local parses to the\n // previous UTC day west of Greenwich, and the UTC getters below would then\n // read a birthday as one day short.\n const dob = new Date(calendarDayOf(dobIso));\n const ref = new Date(calendarDayOf(referenceIso));\n let age = ref.getUTCFullYear() - dob.getUTCFullYear();\n const monthDiff = ref.getUTCMonth() - dob.getUTCMonth();\n if (\n monthDiff < 0 ||\n (monthDiff === 0 && ref.getUTCDate() < dob.getUTCDate())\n ) {\n age -= 1;\n }\n // A DOB typed as 2026 instead of 1926 would otherwise print \"-6 years\" on\n // three headers. A negative age is not an age.\n return age < 0 ? null : age;\n}\n\n/* ------------------------------ Storage seam ---------------------------- */\n\n/** Where a parameter's value actually lives on a `Visit`. */\nexport type ParameterStorage =\n | 'computed'\n | 'anthropometric'\n | 'dietary'\n | 'lab';\n\n/** Keys stored in `visit.dietaryIntake`. Explicit, like `ANTHRO_FIELD_BY_KEY`:\n * the kit's two shipped intake parameters have a drawer of their own, and\n * anything else a practice adds falls through to the open-ended one below. */\nexport const DIETARY_STORAGE_KEYS: ReadonlySet<string> = new Set([\n 'energy',\n 'protein',\n]);\n\n/** Resolve a parameter's STORAGE HOME. Read and write branch on this, never on\n * `def.group`: `AnthropometricSet` is a fixed shape, so a practice-added\n * anthropometric has no field of its own and must round-trip through the\n * open-ended `labs` array. Branching on `group` made it read null and store\n * nothing. `bmi` keeps its explicit guard — `def.computed` is a bare boolean\n * with no formula registry to dispatch on.\n *\n * `labs` stays the FALLBACK, so a key with no drawer of its own still stores\n * and reads back. There is no such thing as a parameter with no storage home. */\nexport function parameterStorage(def: NumericParameterDef): ParameterStorage {\n if (def.key === 'bmi') return 'computed';\n if (def.key in ANTHRO_FIELD_BY_KEY) return 'anthropometric';\n return DIETARY_STORAGE_KEYS.has(def.key) ? 'dietary' : 'lab';\n}\n\n/* ------------------------------ Parameter values ------------------------ */\n\n/** Absent, for a number read off a record. `0` is a measurement like any other,\n * so this is `== null` plus a finiteness test — never a truthiness test. A\n * stored `NaN` / `Infinity` is not a measurement and reads as absent, which is\n * what stops it reaching a delta, a range flag, a sparkline or a cell. */\nfunction readNumber(value: number | null | undefined): number | null {\n return value != null && Number.isFinite(value) ? value : null;\n}\n\n/** The raw numeric value of a parameter at a visit (BMI computed on the fly,\n * the six shipped anthropometrics read from the set, everything else looked up\n * in `labs` by key). Non-finite stored values read as absent. */\nexport function parameterValueAt(\n visit: Visit,\n def: NumericParameterDef,\n): number | null {\n switch (parameterStorage(def)) {\n case 'computed':\n return computeBmi(\n readNumber(visit.anthropometrics.weightKg),\n readNumber(visit.anthropometrics.heightCm),\n );\n case 'anthropometric':\n return readNumber(visit.anthropometrics[ANTHRO_FIELD_BY_KEY[def.key]]);\n case 'dietary': {\n const hit = visit.dietaryIntake?.find((d) => d.parameterKey === def.key);\n return hit ? readNumber(hit.value) : null;\n }\n case 'lab': {\n const hit = visit.labs.find((l) => l.parameterKey === def.key);\n return hit ? readNumber(hit.value) : null;\n }\n }\n}\n\n/** The MOST RECENT recorded value of a parameter, and the visit it was\n * recorded at — walking backwards from the newest visit to the first one that\n * measured it.\n *\n * Not the same question as `parameterValueAt(latestVisit, def)`, and the\n * difference is what a goal tile lives on: a practice that weighs the patient\n * on the 1st and sees them again on the 10th has a weight on record, and a\n * tile reading only the newest visit called it \"not yet measured\". Every\n * surface that answers \"where is this patient now\" wants this one; the grid,\n * which is per-column by construction, wants the other.\n *\n * `null` when no visit ever measured it. */\nexport function latestParameterValue(\n visits: readonly Visit[],\n def: NumericParameterDef,\n): { value: number; visit: Visit } | null {\n for (let index = visits.length - 1; index >= 0; index -= 1) {\n const visit = visits[index];\n const value = parameterValueAt(visit, def);\n if (value != null) return { value, visit };\n }\n return null;\n}\n\n/** Upsert a value into a by-key measurement list, returning a new list. */\nfunction upsertMeasurement(\n list: readonly MeasurementResult[],\n parameterKey: string,\n value: number | null,\n): MeasurementResult[] {\n return list.some((entry) => entry.parameterKey === parameterKey)\n ? list.map((entry) =>\n entry.parameterKey === parameterKey ? { ...entry, value } : entry,\n )\n : [...list, { parameterKey, value }];\n}\n\n/** Write a numeric value onto a visit at its storage home, returning a new\n * visit. Computed parameters are never written. Pure — the surfaces call it\n * through their own working-state setters. */\nexport function setNumericOnVisit(\n visit: Visit,\n def: NumericParameterDef,\n value: number | null,\n): Visit {\n const storage = parameterStorage(def);\n if (storage === 'computed' || def.computed) return visit;\n if (storage === 'anthropometric') {\n return {\n ...visit,\n anthropometrics: {\n ...visit.anthropometrics,\n [ANTHRO_FIELD_BY_KEY[def.key]]: value,\n },\n };\n }\n if (storage === 'dietary') {\n return {\n ...visit,\n dietaryIntake: upsertMeasurement(\n visit.dietaryIntake ?? [],\n def.key,\n value,\n ),\n };\n }\n return { ...visit, labs: upsertMeasurement(visit.labs, def.key, value) };\n}\n\n/* -------------------------------- Targets ------------------------------- */\n\n/** Set or clear a per-patient target, returning a new record. `null` clears\n * it. Pure — the surfaces call it through their own working-state setters,\n * exactly as they call `setNumericOnVisit`. A non-finite target is not a goal\n * and clears rather than storing \"NaN\". */\nexport function setTargetOnRecord(\n record: AnamnesisRecord,\n parameterKey: string,\n target: number | null,\n): AnamnesisRecord {\n const usable = target != null && Number.isFinite(target) ? target : null;\n if (usable == null) {\n const targets = record.targets.filter(\n (entry) => entry.parameterKey !== parameterKey,\n );\n return targets.length === record.targets.length\n ? record\n : { ...record, targets };\n }\n const exists = record.targets.some(\n (entry) => entry.parameterKey === parameterKey,\n );\n const targets = exists\n ? record.targets.map((entry) =>\n entry.parameterKey === parameterKey\n ? { ...entry, target: usable }\n : entry,\n )\n : [...record.targets, { parameterKey, target: usable }];\n return { ...record, targets };\n}\n\n/* ------------------------------ Out of range ---------------------------- */\n\nexport type RangeFlag = 'low' | 'high' | null;\n\n/** Whether a value sits outside its reference range. */\nexport function outOfRange(\n value: number | null,\n range: NumericParameterDef['referenceRange'],\n): RangeFlag {\n if (value == null || !Number.isFinite(value) || !range) return null;\n if (range.min != null && value < range.min) return 'low';\n if (range.max != null && value > range.max) return 'high';\n return null;\n}\n\n/** Signed distance from the nearest edge of the range (0 when inside). Used\n * to judge whether a `toRange` parameter moved closer to healthy. */\nfunction rangeDistance(\n value: number,\n range: NumericParameterDef['referenceRange'],\n): number {\n if (!range) return 0;\n if (range.min != null && value < range.min) return range.min - value;\n if (range.max != null && value > range.max) return value - range.max;\n return 0;\n}\n\n/* -------------------------------- Deltas -------------------------------- */\n\nexport type DeltaDirection = 'up' | 'down' | 'flat';\nexport type DeltaValence = 'good' | 'bad' | 'neutral';\n\nexport interface DeltaInfo {\n /** Signed change vs the previous visit (current − previous). */\n abs: number;\n direction: DeltaDirection;\n valence: DeltaValence;\n}\n\n/** Direction-aware good/bad. Uses the parameter's `betterDirection` and, for\n * `toRange`, the reference range — never the sign of the delta alone. */\nexport function deltaInfo(\n current: number | null,\n previous: number | null,\n def: NumericParameterDef,\n): DeltaInfo | null {\n // A change between two things that are not numbers is not a change.\n if (current == null || previous == null) return null;\n if (!Number.isFinite(current) || !Number.isFinite(previous)) return null;\n const abs = current - previous;\n const direction: DeltaDirection = abs > 0 ? 'up' : abs < 0 ? 'down' : 'flat';\n\n let valence: DeltaValence = 'neutral';\n if (abs !== 0) {\n switch (def.betterDirection) {\n case 'down':\n valence = abs < 0 ? 'good' : 'bad';\n break;\n case 'up':\n valence = abs > 0 ? 'good' : 'bad';\n break;\n case 'toRange': {\n const before = rangeDistance(previous, def.referenceRange);\n const after = rangeDistance(current, def.referenceRange);\n if (after < before) valence = 'good';\n else if (after > before) valence = 'bad';\n else valence = 'neutral';\n break;\n }\n }\n }\n return { abs, direction, valence };\n}\n\n/* --------------------------- Grid row assembly -------------------------- */\n\nexport interface ParameterCell {\n visitId: string;\n value: number | null;\n outOfRange: RangeFlag;\n /** Change vs the immediately preceding visit; null for the first column. */\n delta: DeltaInfo | null;\n}\n\nexport interface ParameterRow {\n def: NumericParameterDef;\n /** One cell per record visit, aligned to `record.visits` order. */\n cells: ParameterCell[];\n /** ONE ENTRY PER RECORD VISIT, in visit order — the sparkline series. A\n * `null` is a visit where this parameter was not measured, and it holds its\n * place: dropping it would compress a four-times-measured lab across the\n * same width as a thirteen-times-measured weight, and an event annotation\n * would then land on a different date in each row. */\n series: (number | null)[];\n /** Per-patient target for this parameter, when one is configured. */\n target: number | null;\n}\n\n/** Build the transposed grid: one row per parameter definition, one cell per\n * visit, with derived deltas / out-of-range flags / sparkline series. */\nexport function buildParameterRows(\n record: AnamnesisRecord,\n defs: NumericParameterDef[],\n): ParameterRow[] {\n const targetByKey = new Map(\n record.targets.map((t) => [t.parameterKey, t.target] as const),\n );\n return defs.map((def) => {\n const cells: ParameterCell[] = record.visits.map((visit, index) => {\n const value = parameterValueAt(visit, def);\n const previous =\n index > 0 ? parameterValueAt(record.visits[index - 1], def) : null;\n return {\n visitId: visit.id,\n value,\n outOfRange: outOfRange(value, def.referenceRange),\n delta: index > 0 ? deltaInfo(value, previous, def) : null,\n };\n });\n const series = cells.map((c) => c.value);\n return {\n def,\n cells,\n series,\n target: targetByKey.get(def.key) ?? null,\n };\n });\n}\n\n/* ------------------------------- Compare -------------------------------- */\n\nexport interface NumericChange {\n def: NumericParameterDef;\n from: number | null;\n to: number | null;\n delta: DeltaInfo | null;\n}\n\nexport interface PathologyChange {\n code: string;\n change: 'added' | 'removed';\n}\n\nexport interface MedicationChange {\n entry: MedicationEntry;\n change: 'added' | 'removed' | 'changed';\n previous?: MedicationEntry;\n}\n\nexport type TextField = 'nutritionalProposal' | 'clinicalNotes';\n\n/** The free-text fields a visit carries, in diff order. */\nexport const TEXT_FIELDS: readonly TextField[] = [\n 'nutritionalProposal',\n 'clinicalNotes',\n];\n\nexport interface TextChange {\n field: TextField;\n from?: string;\n to?: string;\n}\n\nexport interface VisitDiff {\n from: Visit;\n to: Visit;\n numeric: NumericChange[];\n pathologies: PathologyChange[];\n medications: MedicationChange[];\n texts: TextChange[];\n}\n\nfunction roundTo(value: number, precision: number): number {\n const factor = 10 ** precision;\n return Math.round(value * factor) / factor;\n}\n\n/** `roundTo` that carries absence through, so `null` stays `null`. */\nfunction round(value: number | null, precision: number): number | null {\n return value == null ? null : roundTo(value, precision);\n}\n\n/** Everything that changed between two visits — numeric parameters plus the\n * non-numeric fields (pathologies added/removed, medications added/removed/\n * changed, free-text notes edited). Only entries that actually differ are\n * returned, so compare mode can mark exactly the changed cells. */\nexport function compareVisits(\n from: Visit,\n to: Visit,\n defs: NumericParameterDef[],\n): VisitDiff {\n const numeric: NumericChange[] = [];\n for (const def of defs) {\n const precision = def.precision ?? 1;\n // Round BEFORE diffing, and diff the rounded pair. Deciding \"changed\" at\n // display precision but measuring the delta raw prints \"worsened, 0\".\n const a = round(parameterValueAt(from, def), precision);\n const b = round(parameterValueAt(to, def), precision);\n if (a !== b) {\n numeric.push({ def, from: a, to: b, delta: deltaInfo(b, a, def) });\n }\n }\n\n const pathologies: PathologyChange[] = [];\n for (const code of to.pathologyCodes) {\n if (!from.pathologyCodes.includes(code)) {\n pathologies.push({ code, change: 'added' });\n }\n }\n for (const code of from.pathologyCodes) {\n if (!to.pathologyCodes.includes(code)) {\n pathologies.push({ code, change: 'removed' });\n }\n }\n\n const medications: MedicationChange[] = [];\n const fromById = new Map(from.therapy.map((m) => [m.id, m] as const));\n const toById = new Map(to.therapy.map((m) => [m.id, m] as const));\n for (const entry of to.therapy) {\n const prev = fromById.get(entry.id);\n if (!prev) {\n medications.push({ entry, change: 'added' });\n } else if (prev.name !== entry.name || prev.dose !== entry.dose) {\n medications.push({ entry, change: 'changed', previous: prev });\n }\n }\n for (const entry of from.therapy) {\n if (!toById.has(entry.id)) {\n medications.push({ entry, change: 'removed' });\n }\n }\n\n const texts: TextChange[] = [];\n for (const field of TEXT_FIELDS) {\n const a = from[field] ?? '';\n const b = to[field] ?? '';\n if (a !== b) texts.push({ field, from: from[field], to: to[field] });\n }\n\n return { from, to, numeric, pathologies, medications, texts };\n}\n\n/* ----------------------------- Compare a span --------------------------- */\n\n/* N-WAY COMPARE — the semantics, stated once.\n *\n * A row is reported when its value is NOT CONSTANT across the compared\n * visits, and the single change it reports is the NET one: first compared\n * visit → last compared visit. Two consequences are deliberate.\n *\n * • At two visits this is exactly `compareVisits`, so the default view is\n * unchanged by the generalisation.\n * • A value that moved and came back reports a row with a net change of\n * zero. That is the honest answer to \"how far have we come\", and the\n * excursion is what the row's sparkline is there to show — the number\n * and the shape answer different halves of the question.\n *\n * Consecutive per-column deltas are NOT used: the evolution grid already\n * draws \"versus the previous visit\" in every cell, so repeating it here\n * would make compare a second grid rather than a second question.\n *\n * Visits are read in the order given, which every caller resolves in RECORD\n * order — a set of ticked visits has no order of its own, and columns that\n * disagreed with the grid above would be unreadable.\n */\n\nexport interface NumericSpanChange {\n def: NumericParameterDef;\n /** One entry per compared visit, rounded to the parameter's precision. */\n values: (number | null)[];\n /** Net change, first compared visit → last. Null when either end is absent. */\n delta: DeltaInfo | null;\n}\n\nexport interface PathologySpanChange {\n code: string;\n /** Whether the code was assigned at each compared visit. */\n present: boolean[];\n}\n\nexport interface MedicationSpanChange {\n id: string;\n /** The entry at each compared visit; `undefined` where it was not carried. */\n entries: (MedicationEntry | undefined)[];\n}\n\nexport interface TextSpanChange {\n field: TextField;\n /** The field's text at each compared visit, trimmed; '' where absent. */\n values: string[];\n}\n\nexport interface SpanDiff {\n /** The compared visits, in the order given (record order). Never below two. */\n visits: Visit[];\n numeric: NumericSpanChange[];\n pathologies: PathologySpanChange[];\n medications: MedicationSpanChange[];\n texts: TextSpanChange[];\n}\n\n/** Whether every entry equals the first — the one inclusion test every\n * category uses, so a category cannot decide \"changed\" on its own terms. */\nfunction isConstant<T>(\n values: readonly T[],\n same: (a: T, b: T) => boolean = (a, b) => a === b,\n): boolean {\n return values.every((value) => same(value, values[0]));\n}\n\nfunction sameMedication(\n a: MedicationEntry | undefined,\n b: MedicationEntry | undefined,\n): boolean {\n if (a == null || b == null) return a == null && b == null;\n return a.name === b.name && a.dose === b.dose;\n}\n\n/** Everything that is not constant across two or more visits. `null` below\n * two visits — there is no span to read, and an empty diff would claim there\n * was nothing to report. */\nexport function compareVisitSpan(\n visits: readonly Visit[],\n defs: NumericParameterDef[],\n): SpanDiff | null {\n if (visits.length < 2) return null;\n\n const numeric: NumericSpanChange[] = [];\n for (const def of defs) {\n const precision = def.precision ?? 1;\n // Round BEFORE diffing, at display precision: a sub-precision wobble is\n // not a change anybody can see, and reporting one prints a zero delta.\n const values = visits.map((visit) =>\n round(parameterValueAt(visit, def), precision),\n );\n if (isConstant(values)) continue;\n numeric.push({\n def,\n values,\n delta: deltaInfo(values[values.length - 1], values[0], def),\n });\n }\n\n const pathologies: PathologySpanChange[] = [];\n for (const code of unionInOrder(visits, (visit) => visit.pathologyCodes)) {\n const present = visits.map((visit) => visit.pathologyCodes.includes(code));\n if (isConstant(present)) continue;\n pathologies.push({ code, present });\n }\n\n const medications: MedicationSpanChange[] = [];\n for (const id of unionInOrder(visits, (visit) =>\n visit.therapy.map((entry) => entry.id),\n )) {\n const entries = visits.map((visit) =>\n visit.therapy.find((entry) => entry.id === id),\n );\n if (isConstant(entries, sameMedication)) continue;\n medications.push({ id, entries });\n }\n\n const texts: TextSpanChange[] = [];\n for (const field of TEXT_FIELDS) {\n // Trimmed before diffing: whitespace-only is not a note, so gaining or\n // losing three spaces is not an edit anyone needs to read about.\n const values = visits.map((visit) => visit[field]?.trim() ?? '');\n if (isConstant(values)) continue;\n texts.push({ field, values });\n }\n\n return { visits: [...visits], numeric, pathologies, medications, texts };\n}\n\n/** Every id seen at any compared visit, in first-seen order — so a subject\n * that only ever appears at the last visit still gets a row. */\nfunction unionInOrder(\n visits: readonly Visit[],\n read: (visit: Visit) => readonly string[],\n): string[] {\n const seen: string[] = [];\n for (const visit of visits) {\n for (const id of read(visit)) if (!seen.includes(id)) seen.push(id);\n }\n return seen;\n}\n\n/* ------------------------------- Helpers -------------------------------- */\n\n/** The newest visit — the editable one in compile mode, and the record's one\n * reference instant for anything dated against \"now\": the patient's age, the\n * header's visit date. Every surface must read it from here. Intake used to\n * date itself to `visits[0]` while compile and read-only used the last visit,\n * which printed two different ages for the same patient. */\nexport function latestVisit(record: AnamnesisRecord): Visit | undefined {\n return record.visits[record.visits.length - 1];\n}\n\n/** The one string every absent value renders as. Never a bare hyphen, never a\n * blank, never \"NaN\". */\nexport const ABSENT_VALUE = '—';\n\nconst numberFormatters = new Map<string, Intl.NumberFormat>();\n\n/** One `Intl.NumberFormat` per locale × precision. The grid formats every cell\n * of every visit on each render, and constructing a formatter is the costly\n * half of `Intl` — the format call itself is cheap. */\nfunction numberFormatter(\n locale: string | undefined,\n precision: number,\n): Intl.NumberFormat {\n const key = `${locale ?? ''}|${precision}`;\n let formatter = numberFormatters.get(key);\n if (!formatter) {\n formatter = new Intl.NumberFormat(locale, {\n minimumFractionDigits: precision,\n maximumFractionDigits: precision,\n useGrouping: false,\n });\n numberFormatters.set(key, formatter);\n }\n return formatter;\n}\n\n/** Format a numeric value to its parameter precision in the app locale (a\n * comma decimal under `it`), or an em dash when absent. `0` formats as a\n * value; a non-finite number is absent, because `Intl` would print \"NaN\" and\n * that must never reach a cell. No grouping: \"1234,5\" is a lab value, not a\n * sum of money. Callers append the unit separately. */\nexport function formatValue(\n value: number | null,\n precision = 1,\n locale?: string,\n): string {\n if (value == null || !Number.isFinite(value)) return ABSENT_VALUE;\n return numberFormatter(locale, precision).format(value);\n}\n\n/** Localised medium date (e.g. \"12 May 2025\") from an ISO date string.\n * @deprecated Pins neither timezone nor locale. Use `visitDateLabel`\n * (anamnesis-format.ts) for anything date-only; it is the reason this has no\n * callers left. */\nexport function formatDateMedium(iso: string): string {\n if (!isReadableDate(iso)) return ABSENT_VALUE;\n return new Intl.DateTimeFormat(undefined, { dateStyle: 'medium' }).format(\n new Date(iso),\n );\n}\n\n/** Localised calendar date from a date-only ISO string, pinned to UTC through\n * `CALENDAR_DATE_FORMAT`. Prefer `visitDateLabel` (anamnesis-format.ts), which\n * resolves `locale` from the surface's `t` — omitting it falls back to the\n * BROWSER locale, which disagrees with `<Timestamp>` on the same screen.\n * An unreadable date renders the em dash: `Intl` THROWS on one, which would\n * take down the whole evolution surface rather than blank one label. */\nexport function formatCalendarDate(iso: string, locale?: string): string {\n if (!isReadableDate(iso)) return ABSENT_VALUE;\n return new Intl.DateTimeFormat(locale, CALENDAR_DATE_FORMAT).format(\n new Date(iso),\n );\n}\n\n/** Localised calendar date + short time from a `YYYY-MM-DDTHH:mm` string\n * (e.g. \"25 ago 2026, 15:27\" under `it`). Parsed as LOCAL time and rendered\n * in the viewer's zone — never through the UTC pin, which is for date-only\n * strings. Same em-dash rule as `formatCalendarDate`. */\nexport function formatCalendarDateTime(iso: string, locale?: string): string {\n if (!isReadableDate(iso)) return ABSENT_VALUE;\n return new Intl.DateTimeFormat(locale, CALENDAR_DATETIME_FORMAT).format(\n new Date(iso),\n );\n}\n\n/** Signed, precision-formatted delta string (e.g. \"+2.4\", \"−1.0\"; \"+2,4\"\n * under `it`). Uses a real minus sign for the negative case. */\nexport function formatDelta(\n abs: number,\n precision = 1,\n locale?: string,\n): string {\n if (!Number.isFinite(abs)) return ABSENT_VALUE;\n const rounded = roundTo(abs, precision);\n if (rounded === 0) return '0';\n const sign = rounded > 0 ? '+' : '−';\n return `${sign}${formatValue(Math.abs(rounded), precision, locale)}`;\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — i18n-aware descriptor + answer formatting */\n/* */\n/* The one place a descriptor becomes a string a clinician reads. Deliber- */\n/* ately NOT in `anamnesis-derive.ts`, which stays pure (no i18n, no */\n/* React, no `t`). */\n/* */\n/* Label resolution rule, applied uniformly: a practice-authored `label` */\n/* wins over the i18n key derived from the descriptor's key. Practice */\n/* wording is DATA (the `PatientCustomFieldDef.label` precedent), so it is */\n/* exempt from `useTranslation` — the kit cannot translate a word it has */\n/* never seen. Where no practice label exists, the kit's own translated */\n/* string is used. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport type { TFunction } from 'i18next';\nimport { pathologyLabelKey } from './anamnesis-catalogue';\nimport {\n ABSENT_VALUE,\n ageAt,\n formatCalendarDate,\n formatCalendarDateTime,\n hasClockTime,\n latestVisit,\n} from './anamnesis-derive';\nimport type {\n AnamnesisRecord,\n IntakeAnswer,\n IntakeFieldDef,\n IntakeSectionDef,\n NumericParameterDef,\n PathologyCode,\n PatientSex,\n Visit,\n} from './anamnesis-types';\n\n/* ------------------------------ Visibility ------------------------------ */\n\n/** Only show a field when it is relevant to the patient's recorded sex.\n * Single definition — this previously existed three times (intake, compile,\n * read-only) and drifting copies are a correctness risk, not just noise. */\nexport function fieldVisible(def: IntakeFieldDef, sex: PatientSex): boolean {\n const relevance = def.relevance ?? 'any';\n return relevance === 'any' || relevance === sex;\n}\n\n/* -------------------------------- Dates --------------------------------- */\n\n/** The locale a `t` is fixed to. Both `useTranslation()` and a locale-pinned\n * `getFixedT(lng, ns)` set it, so this is the app language on every surface. */\nexport function localeOf(t: TFunction): string | undefined {\n const lng = (t as TFunction & { lng?: unknown }).lng;\n return typeof lng === 'string' ? lng : undefined;\n}\n\n/** Every stored date rendered outside a JSX `<Timestamp>`, in the app locale\n * so one visit cannot render two ways on one screen. A date-only string is\n * pinned to UTC and renders as written; a `YYYY-MM-DDTHH:mm` string is a\n * LOCAL instant and renders as date + short time — never through the UTC\n * pin, which would print the wrong day for an early-morning visit. */\nexport function visitDateLabel(iso: string, t: TFunction): string {\n const locale = localeOf(t);\n return hasClockTime(iso)\n ? formatCalendarDateTime(iso, locale)\n : formatCalendarDate(iso, locale);\n}\n\n/** A stored `YYYY-MM-DD` as a LOCAL calendar date. `new Date(iso)` would parse\n * it as UTC midnight and render the previous day west of Greenwich — the\n * off-by-one this pattern has already had to fix once. A datetime string\n * yields its calendar day: the day is what a date control edits. */\nexport function parseCalendarDate(iso: string): Date | undefined {\n const [y, m, d] = iso.slice(0, 10).split('-').map(Number);\n if (!y || !m || !d) return undefined;\n return new Date(y, m - 1, d);\n}\n\n/** The `THH:mm` tail of a datetime string, or `''` for a date-only one — so a\n * control that edits only the calendar day writes the day back without\n * discarding the time the visit was stamped with. */\nexport function clockSuffix(iso: string): string {\n return hasClockTime(iso) ? iso.slice(10, 16) : '';\n}\n\n/** A local calendar date back to `YYYY-MM-DD`. `toISOString()` would convert to\n * UTC first and can land on the wrong day; these are the local components. */\nexport function toCalendarIso(date: Date): string {\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n}\n\n/** One visit as an option label. The ordinal disambiguates two visits recorded\n * on the same calendar day, which would otherwise read identically.\n *\n * `hasNote` marks a visit whose note is only readable once that visit is a\n * column — without it the picker gives the reader no reason to pick it, and\n * the note is unreachable in practice rather than one tick away. */\nexport function visitOptionLabel(\n visit: Visit,\n index: number,\n t: TFunction,\n hasNote = false,\n): string {\n const base = t('anamnesis.compare.visitOption', {\n index: index + 1,\n visitType: t(`anamnesis.visitType.${visit.visitType}`),\n date: visitDateLabel(visit.dateIso, t),\n });\n // The source (the module the numbers came from) tells two visits minutes\n // apart from different questionnaires apart, as it does in the column.\n const label = visit.sourceLabel\n ? t('anamnesis.compare.visitOptionSource', {\n label: base,\n source: visit.sourceLabel,\n })\n : base;\n return hasNote ? t('anamnesis.window.optionHasNote', { label }) : label;\n}\n\n/* --------------------------------- Age ---------------------------------- */\n\n/** Age at an EXPLICIT reference instant. An unreadable date of birth or\n * reference date renders the em dash — the same absence marker every other\n * unknown uses, and never the \"NaN years\" the raw subtraction used to print.\n * Surfaces call `patientAgeLabel`; this stays for a caller that genuinely has\n * its own reference date. */\nexport function ageLabel(\n dateOfBirthIso: string,\n referenceIso: string,\n t: TFunction,\n): string {\n const age = ageAt(dateOfBirthIso, referenceIso);\n return age == null ? ABSENT_VALUE : t('anamnesis.header.years', { age });\n}\n\n/** The patient header's age line, on every surface. Takes the RECORD rather\n * than a date, so no call site can pick its own reference visit — picking one\n * per surface is exactly how intake and compile came to print two different\n * ages for the same patient. A record with no visit has no age to state. */\nexport function patientAgeLabel(record: AnamnesisRecord, t: TFunction): string {\n const reference = latestVisit(record);\n if (!reference) return ABSENT_VALUE;\n return ageLabel(record.patient.dateOfBirthIso, reference.dateIso, t);\n}\n\n/* -------------------------------- Labels -------------------------------- */\n\n/** A practice label only wins when it carries actual text. */\nfunction practiceLabel(label: string | undefined): string | null {\n const trimmed = label?.trim();\n return trimmed ? trimmed : null;\n}\n\n/** Numeric parameter label — practice wording, else `anamnesis.param.<key>`. */\nexport function parameterLabel(def: NumericParameterDef, t: TFunction): string {\n return (\n practiceLabel(def.label) ??\n t(`anamnesis.param.${def.key}`, { defaultValue: def.key })\n );\n}\n\n/** Parameter label with its unit appended, as the form fields render it. Unit\n * symbols (kg, mg/dL) are locale-invariant scientific notation. */\nexport function parameterLabelWithUnit(\n def: NumericParameterDef,\n t: TFunction,\n): string {\n const label = parameterLabel(def, t);\n return def.unit ? `${label} (${def.unit})` : label;\n}\n\n/** Intake field label — practice wording, else `anamnesis.field.<key>.label`. */\nexport function intakeFieldLabel(def: IntakeFieldDef, t: TFunction): string {\n return (\n practiceLabel(def.label) ??\n t(`anamnesis.field.${def.key}.label`, { defaultValue: def.key })\n );\n}\n\n/** Intake field label with its unit appended — what a `number` field renders,\n * so the reader knows whether 85 is kilograms or pounds before typing it.\n *\n * Practice units only in practice: no kit-seeded intake field carries `unit`\n * (the seeded labels spell theirs out), which is why this is a sibling helper\n * and not folded into `intakeFieldLabel` — that one also feeds the config\n * editor's rename placeholder, where a unit would end up inside the wording. */\nexport function intakeFieldLabelWithUnit(\n def: IntakeFieldDef,\n t: TFunction,\n): string {\n const label = intakeFieldLabel(def, t);\n return def.unit ? `${label} (${def.unit})` : label;\n}\n\n/** Optional help text under an intake field. Practice help text wins; the kit\n * key is optional and resolves to `undefined` when unset. */\nexport function intakeFieldHelp(\n def: IntakeFieldDef,\n t: TFunction,\n): string | undefined {\n const practice = practiceLabel(def.helpText);\n if (practice) return practice;\n const translated = t(`anamnesis.field.${def.key}.help`, { defaultValue: '' });\n return translated || undefined;\n}\n\n/** Section heading — practice wording, else `anamnesis.section.<key>`. */\nexport function sectionLabel(section: IntakeSectionDef, t: TFunction): string {\n return (\n practiceLabel(section.label) ??\n t(`anamnesis.section.${section.key}`, { defaultValue: section.key })\n );\n}\n\n/** Pathology description. The code itself is never translated; the entry may\n * be absent from the taxonomy entirely, in which case the code stands alone.\n * `pathologyLabelKey` sanitises the dot — i18next reads `.` as a separator, so\n * `E66.0` must never be concatenated into a key by hand. */\nexport function pathologyLabel(\n code: string,\n t: TFunction,\n entry?: PathologyCode,\n): string {\n return (\n practiceLabel(entry?.label) ??\n t(pathologyLabelKey(code), { defaultValue: code })\n );\n}\n\n/** `E66.0 — Obesity due to excess calories`, the form the pickers and badges\n * render. Falls back to the bare code when nothing describes it. */\nexport function pathologyCodeWithLabel(\n code: string,\n t: TFunction,\n entry?: PathologyCode,\n): string {\n const label = pathologyLabel(code, t, entry);\n return label === code ? code : `${code} — ${label}`;\n}\n\n/* ----------------------------- Answer values ---------------------------- */\n\n/** Whether an answer carries a real response. Shared by the progress meter,\n * the digest and the mandatory-answer check, so all three agree. \"Not sure\"\n * counts as UNANSWERED — provisional, pending the customer's own rule. Zero is\n * a value: every numeric branch is `!= null`, never a truthiness test. */\nexport function isIntakeAnswered(answer: IntakeAnswer | undefined): boolean {\n if (!answer) return false;\n switch (answer.kind) {\n case 'text':\n return answer.text.trim() !== '';\n case 'number':\n return answer.value != null;\n case 'yesNo':\n return answer.present !== 'unknown';\n case 'choice':\n return answer.selected != null;\n case 'multiChoice':\n return answer.selected.length > 0;\n case 'frequency':\n return answer.perWeek != null;\n case 'meal':\n return answer.description.trim() !== '';\n }\n}\n\n/** One intake answer as a read-only string. Absent values render an em dash —\n * never \"undefined\", never a bare hyphen. Zero is a value: every check here is\n * `!= null`, never a truthiness test on a number. */\nexport function formatIntakeAnswer(\n answer: IntakeAnswer,\n def: IntakeFieldDef,\n t: TFunction,\n): string {\n switch (answer.kind) {\n case 'text':\n return answer.text.trim() || '—';\n case 'number':\n // As entered, in the app locale: the field beside it renders 72,5 under\n // Italian, so the summary and the export must not say 72.5.\n return answer.value != null\n ? new Intl.NumberFormat(localeOf(t), {\n maximumFractionDigits: 10,\n useGrouping: false,\n }).format(answer.value)\n : '—';\n case 'yesNo': {\n const yn =\n answer.present === 'unknown'\n ? t('anamnesis.common.notSure')\n : t(`anamnesis.common.${answer.present}`);\n return answer.detail ? `${yn} — ${answer.detail}` : yn;\n }\n case 'choice': {\n if (!answer.selected) return '—';\n const selectedLabel = t(\n `anamnesis.field.${def.key}.option.${answer.selected}`,\n { defaultValue: answer.selected },\n );\n return answer.detail\n ? `${selectedLabel} — ${answer.detail}`\n : selectedLabel;\n }\n case 'multiChoice':\n return answer.selected.length > 0\n ? answer.selected\n .map((opt) =>\n t(`anamnesis.field.${def.key}.option.${opt}`, {\n defaultValue: opt,\n }),\n )\n .join(', ')\n : '—';\n case 'frequency': {\n const base =\n answer.perWeek != null\n ? t('anamnesis.readOnly.perWeek', { times: answer.perWeek })\n : '—';\n return answer.detail ? `${base} — ${answer.detail}` : base;\n }\n case 'meal':\n return (\n [answer.time, answer.description].filter(Boolean).join(' · ') || '—'\n );\n }\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — at-a-glance intake digest + missing-answer alert */\n/* */\n/* The clinician's read of a returned questionnaire: why the patient came, */\n/* what they already carry, what they report, what they do every day. It */\n/* REPLACES the editable answer list as the default view — the full form */\n/* stays one closed disclosure below, so no answer is rendered twice. */\n/* */\n/* The mandatory list is PROVISIONAL — the customer's real one has not */\n/* arrived. The `required` flag on the field defs is the swap point. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { RefObject } from 'react';\nimport type { TFunction } from 'i18next';\nimport { Alert, type AlertAnnounce } from '../../components/alert';\nimport { Button } from '../../components/button';\nimport { DescriptionList } from '../../components/description-list';\nimport { EmptyState } from '../../components/empty-state';\nimport {\n fieldVisible,\n formatIntakeAnswer,\n intakeFieldLabel,\n isIntakeAnswered,\n} from './anamnesis-format';\nimport type {\n IntakeAnswer,\n IntakeFieldDef,\n IntakeSectionDef,\n PatientSex,\n} from './anamnesis-types';\n\n/* ------------------------------ Vocabulary ------------------------------ */\n\n/** How one digest group is built. Phase 3 adds a group by adding an entry\n * here — the renderer switches on `kind` and never on a group id. */\nexport type DigestGroupKind = 'prose' | 'facts' | 'flags';\n\nexport type DigestGroupDef =\n | { id: string; kind: 'prose'; fieldKeys: readonly string[] }\n | { id: string; kind: 'facts'; fieldKeys: readonly string[] }\n | { id: string; kind: 'flags' };\n\n/** Reading order for a clinician with the patient in the room: why they came,\n * what they already carry, what they report, what they do every day. */\nexport const DIGEST_GROUPS: readonly DigestGroupDef[] = [\n { id: 'reason', kind: 'prose', fieldKeys: ['reasonForVisit'] },\n {\n id: 'history',\n kind: 'prose',\n fieldKeys: ['knownConditions', 'dailyMedications', 'currentSupplements'],\n },\n { id: 'flags', kind: 'flags' },\n {\n id: 'habits',\n kind: 'facts',\n fieldKeys: [\n 'coffeePerDay',\n 'coffeeSugar',\n 'waterPerDay',\n 'alcohol',\n 'fizzyDrinks',\n 'smoking',\n 'sleepQuality',\n 'bowelHabits',\n 'physicalActivity',\n ],\n },\n];\n\n/* Which questions are mandatory now lives ON the field defs\n * (`IntakeFieldDef.required`) — kit-seeded on ten questions as the\n * provisional stand-in the `.mdx` documents, and practice-configurable like\n * `enabled`/`order`. The old kit-constant set is gone: a platform host maps\n * its per-question required flags straight onto the defs. */\n\n/* -------------------------------- Model --------------------------------- */\n\n/** Reads one answer by field key. Both surfaces hold their answers in a\n * different shape (a working map vs `Sourced<IntakeAnswer>`), so the digest\n * takes a reader rather than either shape. */\nexport type AnswerReader = (key: string) => IntakeAnswer | undefined;\n\nexport interface DigestItem {\n key: string;\n label: string;\n /** Already display-ready. Absent numerics are an em dash, never \"NaN\". */\n value: string;\n}\n\nexport interface DigestGroup {\n id: string;\n kind: DigestGroupKind;\n items: DigestItem[];\n}\n\nexport interface IntakeDigest {\n /** Only groups that have something to say. */\n groups: DigestGroup[];\n answered: number;\n total: number;\n}\n\nexport interface MissingAnswer {\n key: string;\n sectionKey: string;\n label: string;\n}\n\n/* ------------------------------- Builders ------------------------------- */\n\nfunction visibleFields(\n sections: readonly IntakeSectionDef[],\n sex: PatientSex,\n): IntakeFieldDef[] {\n return sections.flatMap((section) =>\n section.fields.filter((field) => fieldVisible(field, sex)),\n );\n}\n\nfunction itemFor(\n def: IntakeFieldDef,\n read: AnswerReader,\n t: TFunction,\n): DigestItem | null {\n const answer = read(def.key);\n if (!answer || !isIntakeAnswered(answer)) return null;\n return {\n key: def.key,\n label: intakeFieldLabel(def, t),\n value: formatIntakeAnswer(answer, def, t),\n };\n}\n\n/** Everything the patient answered \"yes\" to, wherever it lives in the form —\n * derived, so a practice-added yes/no question shows up without config. */\nfunction flagItems(\n fields: readonly IntakeFieldDef[],\n read: AnswerReader,\n t: TFunction,\n): DigestItem[] {\n const out: DigestItem[] = [];\n for (const def of fields) {\n const answer = read(def.key);\n if (!answer || answer.kind !== 'yesNo' || answer.present !== 'yes')\n continue;\n out.push({\n key: def.key,\n label: intakeFieldLabel(def, t),\n value: answer.detail?.trim() || t('anamnesis.common.yes'),\n });\n }\n return out;\n}\n\n/** The whole digest. Pure apart from `t`; safe on an absent questionnaire, a\n * half-answered one, and a practice that archived half the form. */\nexport function buildIntakeDigest(\n sections: readonly IntakeSectionDef[],\n read: AnswerReader,\n sex: PatientSex,\n t: TFunction,\n): IntakeDigest {\n const fields = visibleFields(sections, sex);\n const byKey = new Map(fields.map((f) => [f.key, f] as const));\n\n const groups: DigestGroup[] = [];\n for (const group of DIGEST_GROUPS) {\n const items =\n group.kind === 'flags'\n ? flagItems(fields, read, t)\n : group.fieldKeys\n .map((key) => {\n const def = byKey.get(key);\n return def ? itemFor(def, read, t) : null;\n })\n .filter((item): item is DigestItem => item != null);\n if (items.length > 0)\n groups.push({ id: group.id, kind: group.kind, items });\n }\n\n let answered = 0;\n for (const def of fields) {\n const answer = read(def.key);\n if (answer && isIntakeAnswered(answer)) answered += 1;\n }\n\n return { groups, answered, total: fields.length };\n}\n\n/** Mandatory questions the patient has not answered, in questionnaire order.\n * \"Not sure\" counts as unanswered — provisional, and flagged in the `.mdx`. */\nexport function missingMandatoryAnswers(\n sections: readonly IntakeSectionDef[],\n read: AnswerReader,\n sex: PatientSex,\n t: TFunction,\n): MissingAnswer[] {\n const out: MissingAnswer[] = [];\n for (const section of sections) {\n for (const def of section.fields) {\n if (def.required !== true || !fieldVisible(def, sex)) continue;\n const answer = read(def.key);\n if (answer && isIntakeAnswered(answer)) continue;\n out.push({\n key: def.key,\n sectionKey: section.key,\n label: intakeFieldLabel(def, t),\n });\n }\n }\n return out;\n}\n\n/* ------------------------------- Jump seam ------------------------------ */\n\n// Every clause excludes tabindex=\"-1\": a RadioGroup's unchecked items are\n// buttons with a roving -1, so a bare `button` clause lands on the wrong one.\nconst FOCUSABLE_CONTROL =\n 'input:not([tabindex=\"-1\"]), textarea:not([tabindex=\"-1\"]), select:not([tabindex=\"-1\"]), button:not([tabindex=\"-1\"]), [tabindex]:not([tabindex=\"-1\"])';\n\n/** Moves focus to a field the caller has just revealed. Returns false when the\n * target is still not mounted, so the hook can wait one more frame. */\nfunction focusIntakeField(root: HTMLElement | null, key: string): boolean {\n const host = root?.querySelector<HTMLElement>(\n `[data-testid=\"anamnesis-field-${key}\"]`,\n );\n const control = host?.querySelector<HTMLElement>(FOCUSABLE_CONTROL);\n if (!control) return false;\n control.focus();\n return true;\n}\n\nconst MAX_JUMP_FRAMES = 4;\n\n/** Jump-to-field seam. The caller opens whatever disclosures hide the target\n * (on compile that is BOTH the section block and the answer review), then asks\n * for the jump; this waits for the reveal to mount before moving focus. */\nexport function useFieldJump(): {\n containerRef: RefObject<HTMLDivElement | null>;\n requestJump: (key: string) => void;\n} {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [pending, setPending] = useState<string | null>(null);\n\n useEffect(() => {\n if (pending == null) return;\n let frames = 0;\n let raf = 0;\n const attempt = () => {\n if (focusIntakeField(containerRef.current, pending)) {\n setPending(null);\n return;\n }\n frames += 1;\n if (frames >= MAX_JUMP_FRAMES) {\n setPending(null);\n return;\n }\n raf = window.requestAnimationFrame(attempt);\n };\n raf = window.requestAnimationFrame(attempt);\n return () => window.cancelAnimationFrame(raf);\n }, [pending]);\n\n const requestJump = useCallback((key: string) => setPending(key), []);\n\n return { containerRef, requestJump };\n}\n\n/* ------------------------- Missing-answer alert ------------------------- */\n\nexport interface AnamnesisMissingAnswersProps {\n missing: readonly MissingAnswer[];\n t: TFunction;\n /** Reveals the first missing answer and moves focus to it. */\n onJump: (missing: MissingAnswer) => void;\n /** How loudly this is announced. Pass `'off'` where the list RECOMPUTES as\n * the user types — a live region re-announces its whole content on every\n * change, so a per-keystroke summary is noise, not help. Default `'polite'`\n * suits a list fixed at mount. */\n announce?: AlertAnnounce;\n /** Label for the jump action. Override where the jump LEAVES the surface —\n * a button that changes tab has to say so before it moves focus. */\n jumpKey?: string;\n}\n\n/** Guidance, not an interruption. Tint and urgency are independent in the kit,\n * so the `info` tint here is a visual choice, separate from `announce`. */\nexport function AnamnesisMissingAnswers({\n missing,\n t,\n onJump,\n announce = 'polite',\n jumpKey = 'anamnesis.digest.missing.jump',\n}: AnamnesisMissingAnswersProps) {\n const first = missing[0];\n if (!first) return null;\n const separator = t('anamnesis.digest.missing.separator');\n const list = missing.map((m) => m.label).join(separator);\n\n return (\n <Alert\n variant=\"info\"\n announce={announce}\n data-testid=\"anamnesis-digest-missing\"\n >\n <Alert.Title as=\"p\">\n {t('anamnesis.digest.missing.title', { count: missing.length })}\n </Alert.Title>\n <Alert.Description>\n {t('anamnesis.digest.missing.list', { list })}\n </Alert.Description>\n <Alert.Action>\n <Button\n intent=\"tonal\"\n size=\"sm\"\n data-testid=\"anamnesis-digest-jump\"\n onClick={() => onJump(first)}\n >\n {t(jumpKey, { field: first.label })}\n </Button>\n </Alert.Action>\n </Alert>\n );\n}\n\n/* -------------------------------- Digest -------------------------------- */\n\nexport interface AnamnesisDigestProps {\n digest: IntakeDigest;\n t: TFunction;\n}\n\n/** Free text reads as prose; everything else as a term↔detail list. Group\n * headings are h3 — the digest always sits under the section's h2. */\nfunction DigestGroupBlock({ group, t }: { group: DigestGroup; t: TFunction }) {\n return (\n <div\n data-testid={`anamnesis-digest-group-${group.id}`}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n >\n <h3 className=\"type-title-item ds:m-0 ds:text-[color:var(--foreground)]\">\n {t(`anamnesis.digest.group.${group.id}`)}\n </h3>\n <DescriptionList\n layout={group.kind === 'prose' ? 'stacked' : 'inline'}\n labelWidth=\"fixed\"\n density=\"compact\"\n divider=\"between\"\n >\n {group.items.map((item) => (\n <DescriptionList.Row key={item.key}>\n <DescriptionList.Term>{item.label}</DescriptionList.Term>\n <DescriptionList.Detail>{item.value}</DescriptionList.Detail>\n </DescriptionList.Row>\n ))}\n </DescriptionList>\n </div>\n );\n}\n\nexport function AnamnesisDigest({ digest, t }: AnamnesisDigestProps) {\n if (digest.groups.length === 0) {\n return (\n <EmptyState\n variant=\"first-use\"\n size=\"sm\"\n title={t('anamnesis.digest.nothing.title')}\n description={t('anamnesis.digest.nothing.description')}\n />\n );\n }\n return (\n <div\n data-testid=\"anamnesis-digest-panel\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n {digest.groups.map((group) => (\n <DigestGroupBlock key={group.id} group={group} t={t} />\n ))}\n </div>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — shared visual indicators */\n/* */\n/* The vocabulary that makes \"changes are immediately visible\" work, */\n/* reused across intake, compile, the evolution grid, and read-only: */\n/* • DeltaIndicator — direction-aware arrow + signed change, coloured by */\n/* good/bad VALENCE (not the raw sign), with a redundant text/aria cue. */\n/* • OriginMarker — the \"from patient\" badge (info family) on values the */\n/* clinician has not yet confirmed. */\n/* • OutOfRangeBadge — the H/L flag for a lab outside its reference range. */\n/* • TrendSparkline — a compact inline trend for a numeric series. */\n/* */\n/* Colour never carries meaning alone (WCAG 1.4.1): deltas pair colour with */\n/* a direction glyph + signed number + an \"improved/worsened\" aria phrase; */\n/* range flags pair colour with a glyph + dot + aria; the origin marker */\n/* carries a glyph + text. */\n/* -------------------------------------------------------------------- */\n\nimport { cva } from 'class-variance-authority';\nimport type { TFunction } from 'i18next';\nimport { ArrowDown, ArrowUp, Minus, User } from 'lucide-react';\nimport { Badge } from '../../components/badge';\nimport {\n Sparkline,\n type SparklineAnnotation,\n} from '../../components/sparkline';\nimport {\n deltaInfo,\n formatDelta,\n type DeltaInfo,\n type RangeFlag,\n} from './anamnesis-derive';\nimport { localeOf, parameterLabel } from './anamnesis-format';\nimport type { NumericParameterDef } from './anamnesis-types';\n\n/* ------------------------------ DeltaIndicator -------------------------- */\n\nconst deltaVariants = cva(\n 'type-meta ds:inline-flex ds:items-center ds:gap-[var(--spacing-2xs)] ds:tabular-nums',\n {\n variants: {\n valence: {\n // Deep semantic ramp steps so the 12px delta text clears AA at small\n // sizes on both the white card surface and the warm-grey app shell.\n good: 'ds:text-[color:var(--success-foreground)]',\n bad: 'ds:text-[color:var(--error-foreground)]',\n neutral: 'ds:text-[color:var(--muted-foreground)]',\n },\n },\n defaultVariants: { valence: 'neutral' },\n },\n);\n\nexport interface DeltaIndicatorProps {\n /** The derived change vs the previous visit; `null` renders nothing (first\n * visit has no delta — never render a broken arrow). */\n delta: DeltaInfo | null;\n def: NumericParameterDef;\n t: TFunction;\n}\n\n/** Arrow + signed change vs the previous visit, coloured by whether the change\n * is an improvement for THIS parameter. */\nexport function DeltaIndicator({ delta, def, t }: DeltaIndicatorProps) {\n if (!delta) return null;\n const Icon =\n delta.direction === 'up'\n ? ArrowUp\n : delta.direction === 'down'\n ? ArrowDown\n : Minus;\n const changeText = `${formatDelta(delta.abs, def.precision ?? 1, localeOf(t))}${\n def.unit ? ` ${def.unit}` : ''\n }`;\n const valenceLabel =\n delta.valence === 'good'\n ? t('anamnesis.delta.improved')\n : delta.valence === 'bad'\n ? t('anamnesis.delta.worsened')\n : t('anamnesis.delta.unchanged');\n return (\n <span\n role=\"img\"\n className={deltaVariants({ valence: delta.valence })}\n aria-label={t('anamnesis.delta.aria', {\n valence: valenceLabel,\n change: changeText,\n })}\n >\n <Icon aria-hidden=\"true\" className=\"ds:size-4\" />\n <span aria-hidden=\"true\">{changeText}</span>\n </span>\n );\n}\n\n/* ------------------------------ OriginMarker ---------------------------- */\n\nexport interface OriginMarkerProps {\n t: TFunction;\n}\n\n/** \"From patient\" badge shown against a value the patient submitted and the\n * clinician has not yet confirmed or edited. Uses the info family (calm,\n * informational — distinct from the clinical status colours). */\nexport function OriginMarker({ t }: OriginMarkerProps) {\n return (\n <Badge variant=\"info\" size=\"sm\" leading={<User aria-hidden=\"true\" />}>\n {t('anamnesis.origin.fromPatient')}\n </Badge>\n );\n}\n\n/* ----------------------------- OutOfRangeBadge -------------------------- */\n\nexport interface OutOfRangeBadgeProps {\n flag: RangeFlag;\n t: TFunction;\n /** Icon-only chip for dense grid cells; otherwise shows a short label. */\n compact?: boolean;\n}\n\n/** H/L flag for a lab value outside its reference range. Warning tone +\n * direction glyph + colour-blind dot; the accessible name says above/below. */\nexport function OutOfRangeBadge({\n flag,\n t,\n compact = false,\n}: OutOfRangeBadgeProps) {\n if (!flag) return null;\n const label =\n flag === 'high'\n ? t('anamnesis.range.aboveRange')\n : t('anamnesis.range.belowRange');\n const Icon = flag === 'high' ? ArrowUp : ArrowDown;\n return (\n <Badge\n variant=\"warning\"\n size=\"sm\"\n withDot\n leading={<Icon aria-hidden=\"true\" />}\n aria-label={label}\n >\n {compact ? null : label}\n </Badge>\n );\n}\n\n/* ----------------------------- TrendSparkline --------------------------- */\n\nconst TREND_COLOUR: Record<'good' | 'bad' | 'neutral', string> = {\n good: 'var(--success)',\n bad: 'var(--error)',\n neutral: 'var(--muted-foreground)',\n};\n\nexport interface TrendSparklineProps {\n /** ONE ENTRY PER RECORD VISIT, in visit order. `null` is a visit where this\n * parameter was not measured, and it HOLDS its place on the x extent —\n * that is what keeps a lab drawn four times over a thirteen-visit history\n * on the same x scale as a weight drawn thirteen times, so an event\n * annotation lands on the same date in both. */\n series: (number | null)[];\n def: NumericParameterDef;\n t: TFunction;\n /** Event reference lines. The SAME array is handed to every row, so one\n * event is one vertical line down the whole grid. */\n annotations?: readonly SparklineAnnotation[];\n /** Make those lines pointer-selectable. Supplied ⇒ pressing one does what\n * pressing its chip in the bar above does. The chip bar is the keyboard\n * route and stays the only one — the lines live inside a `role=\"img\"`. */\n onSelectAnnotation?: (eventId: string) => void;\n}\n\n/** Compact inline trend across all visits, tinted by the overall valence\n * (first → last measurement) for the parameter. Reduced motion is honoured by\n * Sparkline internally. Renders nothing below two measurements (no trend to\n * draw) — the gaps do not count towards that. Always as wide as its cell:\n * the event lines are drawn over the cell, so a narrower plot would put them\n * beside the measurements they mark rather than on them. */\nexport function TrendSparkline({\n series,\n def,\n t,\n annotations,\n onSelectAnnotation,\n}: TrendSparklineProps) {\n const measured = series.filter((value): value is number => value != null);\n if (measured.length < 2) return null;\n const overall = deltaInfo(measured[measured.length - 1], measured[0], def);\n const valence = overall?.valence ?? 'neutral';\n return (\n <Sparkline\n data={series}\n variant=\"line\"\n size=\"sm\"\n /* A percentage, never the measured container width: the trend tab is\n `display:none` until it is selected, so the first measurement is 0 and\n ApexCharts would keep a chart narrower than the cell for good. */\n width=\"100%\"\n color={TREND_COLOUR[valence]}\n annotations={annotations}\n onAnnotationSelect={onSelectAnnotation}\n label={t('anamnesis.grid.trendLabel', {\n parameter: parameterLabel(def, t),\n })}\n />\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — Summary tab (the questionnaire, read-only) */\n/* */\n/* The clinician's arrival read: what the patient reported before the */\n/* visit, answered at a glance. It carries the digest built in */\n/* `anamnesis-digest.tsx` (why they came, what they carry, what they */\n/* report, what they do daily), the missing-answer alert, and the full */\n/* questionnaire one closed disclosure below — all READ-ONLY. Filling a */\n/* gap is data entry, so it happens on Compile; the alert's action crosses */\n/* to it rather than turning this panel into a form. */\n/* */\n/* `AnamnesisAnswerList` is the single read-only questionnaire renderer, */\n/* shared with the read-only care-plan surface. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport type { TFunction } from 'i18next';\nimport { ChevronDown } from 'lucide-react';\nimport { Badge } from '../../components/badge';\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '../../components/collapsible';\nimport { DescriptionList } from '../../components/description-list';\nimport {\n AnamnesisDigest,\n AnamnesisMissingAnswers,\n type IntakeDigest,\n type MissingAnswer,\n} from './anamnesis-digest';\nimport {\n fieldVisible,\n formatIntakeAnswer,\n intakeFieldLabel,\n sectionLabel,\n} from './anamnesis-format';\nimport { OriginMarker } from './anamnesis-indicators';\nimport type {\n IntakeResponse,\n IntakeSectionDef,\n PatientSex,\n} from './anamnesis-types';\n\n/** The kit's token-driven focus ring for an unstyled `CollapsibleTrigger`.\n * Without it the UA outline shows, which neither widens under\n * `.theme-accessible` nor uses `--ring`. */\nexport const TRIGGER_FOCUS_RING =\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\n/* --------------------- Read-only questionnaire list --------------------- */\n\nexport interface AnamnesisAnswerListProps {\n intake: IntakeResponse;\n /** History vocabulary, not the live one — archiving a question must never\n * erase the answer already recorded under it. */\n sections: readonly IntakeSectionDef[];\n sex: PatientSex;\n t: TFunction;\n}\n\n/** Every recorded answer as term ↔ detail, grouped by questionnaire section,\n * with the \"from patient\" marker on values the clinician has not touched.\n * Zero edit affordances — this is a read presentation, not a disabled form. */\nexport function AnamnesisAnswerList({\n intake,\n sections,\n sex,\n t,\n}: AnamnesisAnswerListProps) {\n const blocks = sections\n .map((section) => ({\n section,\n fields: section.fields\n .filter((field) => fieldVisible(field, sex))\n .filter((field) => intake.answers[field.key]),\n }))\n .filter(({ fields }) => fields.length > 0);\n\n if (blocks.length === 0) {\n return (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.summary.noAnswers')}\n </p>\n );\n }\n\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n {blocks.map(({ section, fields }) => (\n <div\n key={section.key}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <h3 className=\"type-title-item ds:m-0 ds:text-[color:var(--foreground)]\">\n {sectionLabel(section, t)}\n </h3>\n <DescriptionList layout=\"stacked\" density=\"compact\" divider=\"between\">\n {fields.map((field) => {\n const sourced = intake.answers[field.key];\n if (!sourced) return null;\n return (\n <DescriptionList.Row key={field.key}>\n <DescriptionList.Term>\n {intakeFieldLabel(field, t)}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n <span>{formatIntakeAnswer(sourced.value, field, t)}</span>\n {sourced.origin === 'patient' ? (\n <OriginMarker t={t} />\n ) : null}\n </span>\n </DescriptionList.Detail>\n </DescriptionList.Row>\n );\n })}\n </DescriptionList>\n </div>\n ))}\n </div>\n );\n}\n\n/* ------------------------------ Summary tab ----------------------------- */\n\nexport interface AnamnesisSummaryProps {\n /** Absent = no questionnaire was ever sent back. */\n intake: IntakeResponse | undefined;\n sections: readonly IntakeSectionDef[];\n sex: PatientSex;\n digest: IntakeDigest;\n missing: readonly MissingAnswer[];\n /** Hands the gap to the Compile tab, which is where answers are recorded. */\n onJump: (missing: MissingAnswer) => void;\n t: TFunction;\n}\n\n/** The Summary panel. One h2 for the tab's subject, the digest's groups as\n * h3 under it, then the full questionnaire behind its own h2 trigger — so the\n * heading order is h1 → h2 → h3 with no jump, on a panel with no inputs. */\nexport function AnamnesisSummary({\n intake,\n sections,\n sex,\n digest,\n missing,\n onJump,\n t,\n}: AnamnesisSummaryProps) {\n return (\n <section\n data-testid=\"anamnesis-summary\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n <h2 className=\"type-title-section ds:m-0 ds:text-[color:var(--foreground)]\">\n {t('anamnesis.section.patientIntake')}\n </h2>\n {intake ? (\n <>\n {/* Fixed at mount — the questionnaire has already come back — so a\n polite live region is a summary, not a per-keystroke re-read. */}\n {missing.length > 0 ? (\n <AnamnesisMissingAnswers\n missing={missing}\n t={t}\n onJump={onJump}\n jumpKey=\"anamnesis.summary.jump\"\n />\n ) : null}\n <AnamnesisDigest digest={digest} t={t} />\n <Collapsible variant=\"default\">\n <h2 className=\"type-title-section ds:m-0 ds:text-[color:var(--foreground)]\">\n <CollapsibleTrigger\n data-testid=\"anamnesis-summary-full\"\n className={\n 'type-label ds:flex ds:w-full ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)] ds:text-start' +\n TRIGGER_FOCUS_RING\n }\n >\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n {t('anamnesis.summary.fullQuestionnaire')}\n <Badge variant=\"neutral\" size=\"sm\">\n {t('anamnesis.intake.sectionProgress', {\n answered: digest.answered,\n total: digest.total,\n })}\n </Badge>\n </span>\n <ChevronDown\n aria-hidden=\"true\"\n className=\"ds:size-5 ds:shrink-0 ds:text-[color:var(--muted-foreground)] ds:transition-transform ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none ds:[[data-state=open]_&]:rotate-180\"\n />\n </CollapsibleTrigger>\n </h2>\n {/* Named after its own trigger: both derive role=\"group\", and two\n nested groups sharing a name are unnavigable. */}\n <CollapsibleContent\n aria-label={t('anamnesis.summary.fullQuestionnaire')}\n >\n <div className=\"ds:pt-[var(--spacing-md)]\">\n <AnamnesisAnswerList\n intake={intake}\n sections={sections}\n sex={sex}\n t={t}\n />\n </div>\n </CollapsibleContent>\n </Collapsible>\n </>\n ) : (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.compile.noIntake')}\n </p>\n )}\n </section>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — compile-surface density policy */\n/* */\n/* The compile tab is ten titled blocks. Opening all ten made the page a */\n/* very long scroll, most of it reference material the clinician does not */\n/* touch at a follow-up. The policy here is a DEFAULT, not a control: the */\n/* blocks a clinician fills or must recall at every visit are open on */\n/* arrival, the occasional ones are folded — and every folded block states */\n/* how much it holds AND how much of that is out of range, so folding */\n/* hides the detail and never the existence of a record or a flag. */\n/* */\n/* Pure: no i18n, no JSX, no React. The badge wording lives with the */\n/* renderer; the policy lives here so it can be read and tested on its own. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport { outOfRange } from './anamnesis-derive';\nimport type { NumericParameterDef, Visit } from './anamnesis-types';\n\n/* -------------------------------- Blocks -------------------------------- */\n\n/** Open on arrival: the blocks a clinician records at — or must recall at —\n * EVERY consultation. Visit details and anthropometrics are recorded each\n * time; an unanswered required question is this visit's to-do list; the\n * pathology list and the current therapy are the \"what does this patient carry\n * / already take\" memory aids, and proposing a supplement without seeing the\n * current medication is exactly the recall failure this surface prevents.\n * The questionnaire itself is read on the Summary tab, not here. */\nexport const EVERY_VISIT_BLOCKS = [\n 'visitMeta',\n 'intakeGaps',\n 'anthropometrics',\n 'pathologies',\n 'therapy',\n 'proposal',\n] as const;\n\n/** Folded on arrival at a FOLLOW-UP: reference or occasional. Oncological\n * history is blank for most patients; bloods are drawn a few times a year;\n * fasting cycles and the annual programme are yearly. Each keeps a fill\n * summary in its header, so folding hides the detail and never the existence\n * of a record. A first visit opens all of them — see `compileBlockDensity`. */\nexport const OCCASIONAL_BLOCKS = [\n 'oncological',\n 'labs',\n 'fmd',\n 'annual',\n] as const;\n\nexport type EveryVisitBlockId = (typeof EVERY_VISIT_BLOCKS)[number];\nexport type OccasionalBlockId = (typeof OCCASIONAL_BLOCKS)[number];\n\n/** One titled block of the compile form whose arrival state this module\n * decides. Adding an id to this union without listing it in one of the two\n * arrays above is a type error. It does NOT catch a `<Block>` rendered in the\n * JSX with no id at all — that block simply keeps the shell's own default. */\nexport type CompileBlockId = EveryVisitBlockId | OccasionalBlockId;\n\nexport interface CompileBlockDensity {\n /** Open on arrival. */\n open: boolean;\n /** How much this block already holds, for the header summary. `null` on the\n * always-open blocks, where a count beside visible content is noise. */\n fill: number | null;\n /** Of that fill, how many values sit outside their reference range. Named in\n * the header so a folded block can never hide a flagged result. */\n flagged: number;\n}\n\n/* -------------------------------- Fills --------------------------------- */\n\nfunction filledText(value: string | undefined): boolean {\n return (value ?? '').trim() !== '';\n}\n\n/** Oncological entries recorded: each answered field counts once. */\nfunction oncologicalFill(visit: Visit): number {\n const onc = visit.oncological;\n if (!onc) return 0;\n let filled = 0;\n if (filledText(onc.tumourType)) filled += 1;\n if (filledText(onc.stage)) filled += 1;\n if (onc.metastases && onc.metastases.present !== 'unknown') filled += 1;\n if (filledText(onc.treatmentStatus)) filled += 1;\n return filled;\n}\n\n/** Labs the BLOCK will actually render, not the raw `visit.labs` array: a\n * since-archived parameter, or a value round-tripped through `labs` for a\n * practice-added anthropometric, would otherwise be counted in a header whose\n * open state shows something else. `0` is a measurement; `NaN` / `Infinity`\n * are not, so this is `!= null` plus a finiteness test, never truthiness. */\nfunction labValues(\n visit: Visit,\n labDefs: readonly NumericParameterDef[],\n): { def: NumericParameterDef; value: number }[] {\n const byKey = new Map(visit.labs.map((lab) => [lab.parameterKey, lab.value]));\n const hits: { def: NumericParameterDef; value: number }[] = [];\n for (const def of labDefs) {\n const value = byKey.get(def.key);\n if (value != null && Number.isFinite(value)) hits.push({ def, value });\n }\n return hits;\n}\n\n/** The annual programme is one decision, and \"recorded\" means a decision was\n * taken — an explicit \"not proposed\" holds no proposal to read. */\nfunction annualFill(visit: Visit): number {\n const annual = visit.annualProgramme;\n if (!annual) return 0;\n return annual.proposed || annual.accepted ? 1 : 0;\n}\n\n/* --------------------------------- API ---------------------------------- */\n\n/** How each compile block opens for the visit being recorded.\n *\n * A FIRST visit opens everything: there is no history to fold away, and an\n * empty block on a first consultation means \"to be filled\", not \"nothing to\n * see\". A follow-up folds the occasional blocks behind their fill summary.\n *\n * `labDefs` is the practice's live lab vocabulary — the same list the Blood\n * tests block renders. Pass it, or the lab fill and flag counts describe a\n * different set of values from the one the opened block shows.\n *\n * Safe on a record with no visit — everything falls back to the arrival\n * default with no fill. */\nexport function compileBlockDensity(\n visit: Visit | undefined,\n labDefs: readonly NumericParameterDef[] = [],\n): Record<CompileBlockId, CompileBlockDensity> {\n const labs = visit ? labValues(visit, labDefs) : [];\n const firstVisit = visit?.visitType === 'first';\n\n const fills: Record<OccasionalBlockId, number> = {\n oncological: visit ? oncologicalFill(visit) : 0,\n labs: labs.length,\n fmd: visit ? visit.fmdCycles.length : 0,\n annual: visit ? annualFill(visit) : 0,\n };\n const flags: Record<OccasionalBlockId, number> = {\n oncological: 0,\n labs: labs.filter(({ def, value }) => outOfRange(value, def.referenceRange))\n .length,\n fmd: 0,\n annual: 0,\n };\n\n const density = {} as Record<CompileBlockId, CompileBlockDensity>;\n for (const id of EVERY_VISIT_BLOCKS)\n density[id] = { open: true, fill: null, flagged: 0 };\n for (const id of OCCASIONAL_BLOCKS)\n density[id] = { open: firstVisit, fill: fills[id], flagged: flags[id] };\n return density;\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — the merged \"first visit\" baseline */\n/* */\n/* In the platform a visit is one interview of one module, and each */\n/* module's opening interview is its own FIRST visit — minutes apart, */\n/* asking different questions. Plotted as columns, the leftmost one is */\n/* whichever module happened to open first, and every parameter the other */\n/* modules own reads \"—\" there while their own baselines sit further */\n/* right. The reader wants ONE baseline: per parameter, the value it had */\n/* at its module's first visit. */\n/* */\n/* This folds every `visitType === 'first'` visit into one synthetic */\n/* `Visit` the rest of the surface reads like any other column. It is */\n/* DERIVED here and never stored on the record; with fewer than two first */\n/* visits the input passes through untouched, so a single-module record */\n/* renders exactly as it always has. */\n/* */\n/* Pure: no i18n, no JSX, no React. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport { hasClockTime, isReadableDate } from './anamnesis-derive';\nimport type {\n AnthropometricSet,\n MeasurementResult,\n Visit,\n} from './anamnesis-types';\n\n/** Column id of the synthetic merged first visit. A record must not hold a\n * real visit with this id. */\nexport const BASELINE_VISIT_ID = 'baseline';\n\nexport interface VisitBaseline {\n /** The synthetic merged first visit; `null` when the record holds fewer\n * than two first visits. */\n baseline: Visit | null;\n /** The first visits folded into it, oldest first. Empty when `baseline`\n * is null. */\n sources: Visit[];\n /** The list every downstream read runs on: `[baseline, ...non-first visits\n * in record order]` — or the INPUT ARRAY ITSELF when nothing merged. */\n visits: Visit[];\n /** What the picker may toggle: `visits` minus the baseline (the input\n * array itself when nothing merged). */\n pickable: Visit[];\n}\n\nexport interface ResolveBaselineOptions {\n /** A visit that stays its own column even when it is a first visit —\n * compile mode's editable newest visit. Omitted = every first visit folds. */\n keepId?: string;\n}\n\n/* ------------------------------- Helpers -------------------------------- */\n\n/** One sort key for every source, on the event axis's rule: with any\n * date-only stamp among them all compare by UTC-anchored calendar DAY, else\n * by instant — so the merge order never depends on the viewer's time zone.\n * Unreadable dates sort last; `Array.sort` is stable, so ties keep record\n * order. */\nexport function visitSortKey(\n visits: readonly Visit[],\n): (iso: string) => number {\n const byDay = visits.some(\n (visit) => isReadableDate(visit.dateIso) && !hasClockTime(visit.dateIso),\n );\n return (iso) => {\n if (!isReadableDate(iso)) return Number.POSITIVE_INFINITY;\n if (!byDay) return new Date(iso).getTime();\n const [y, m, d] = iso.slice(0, 10).split('-').map(Number);\n return y && m && d ? Date.UTC(y, m - 1, d) : Number.POSITIVE_INFINITY;\n };\n}\n\nfunction finite(value: number | null | undefined): value is number {\n return value != null && Number.isFinite(value);\n}\n\nconst ANTHRO_KEYS: readonly (keyof AnthropometricSet)[] = [\n 'weightKg',\n 'heightCm',\n 'waistCm',\n 'hipsCm',\n 'armCm',\n 'phaseAngleDeg',\n];\n\n/** Per key, the value from the EARLIEST source that has a finite one; keys\n * are unioned in first-seen order, and a key nobody measured stays null. */\nfunction mergeMeasurements(\n lists: readonly (readonly MeasurementResult[])[],\n): MeasurementResult[] {\n const merged: MeasurementResult[] = [];\n const at = new Map<string, number>();\n for (const list of lists) {\n for (const entry of list) {\n const index = at.get(entry.parameterKey);\n if (index == null) {\n at.set(entry.parameterKey, merged.length);\n merged.push({\n parameterKey: entry.parameterKey,\n value: finite(entry.value) ? entry.value : null,\n });\n } else if (merged[index].value == null && finite(entry.value)) {\n merged[index] = {\n parameterKey: entry.parameterKey,\n value: entry.value,\n };\n }\n }\n }\n return merged;\n}\n\n/** Trimmed, non-empty texts oldest first: none → absent, one → that text,\n * several → joined by a blank line. The simplest union that loses nothing. */\nfunction mergeText(texts: readonly (string | undefined)[]): string | undefined {\n const kept = texts\n .map((text) => text?.trim() ?? '')\n .filter((text) => text.length > 0);\n return kept.length > 0 ? kept.join('\\n\\n') : undefined;\n}\n\nfunction firstDefined<T>(values: readonly (T | undefined)[]): T | undefined {\n return values.find((value) => value !== undefined);\n}\n\n/* --------------------------------- API ---------------------------------- */\n\nexport function isBaselineVisit(visit: Visit): boolean {\n return visit.id === BASELINE_VISIT_ID;\n}\n\n/** Resolve the effective visit list. Never mutates `visits` or any visit in\n * it; the synthetic visit is built field by field so nothing of a source's\n * identity (id, source label, practitioner) leaks into it. */\nexport function resolveBaseline(\n visits: readonly Visit[],\n { keepId }: ResolveBaselineOptions = {},\n): VisitBaseline {\n const folds = (visit: Visit) =>\n visit.visitType === 'first' && visit.id !== keepId;\n const firsts = visits.filter(folds);\n if (firsts.length < 2) {\n const same = visits as Visit[];\n return { baseline: null, sources: [], visits: same, pickable: same };\n }\n\n const key = visitSortKey(firsts);\n const sources = [...firsts].sort((a, b) => key(a.dateIso) - key(b.dateIso));\n\n const anthropometrics = {} as AnthropometricSet;\n for (const key of ANTHRO_KEYS) {\n const hit = sources.find((source) => finite(source.anthropometrics[key]));\n anthropometrics[key] = hit ? hit.anthropometrics[key] : null;\n }\n\n const intakeLists = sources\n .map((source) => source.dietaryIntake)\n .filter((list): list is MeasurementResult[] => list != null);\n\n const pathologyCodes: string[] = [];\n for (const source of sources) {\n for (const code of source.pathologyCodes) {\n if (!pathologyCodes.includes(code)) pathologyCodes.push(code);\n }\n }\n\n const therapy: Visit['therapy'] = [];\n for (const source of sources) {\n for (const entry of source.therapy) {\n if (!therapy.some((kept) => kept.id === entry.id)) therapy.push(entry);\n }\n }\n\n const baseline: Visit = {\n id: BASELINE_VISIT_ID,\n visitType: 'first',\n dateIso: sources[0].dateIso,\n practitioner: undefined,\n sourceLabel: undefined,\n anthropometrics,\n labs: mergeMeasurements(sources.map((source) => source.labs)),\n // Absent stays absent: \"not measured\" must not become \"zero\".\n dietaryIntake:\n intakeLists.length > 0 ? mergeMeasurements(intakeLists) : undefined,\n pathologyCodes,\n oncological: firstDefined(sources.map((source) => source.oncological)),\n therapy,\n fmdCycles: sources.flatMap((source) => source.fmdCycles),\n nutritionalProposal: mergeText(\n sources.map((source) => source.nutritionalProposal),\n ),\n clinicalNotes: mergeText(sources.map((source) => source.clinicalNotes)),\n annualProgramme: firstDefined(\n sources.map((source) => source.annualProgramme),\n ),\n };\n\n const rest = visits.filter((visit) => !folds(visit));\n return { baseline, sources, visits: [baseline, ...rest], pickable: rest };\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — clinical events, and where they sit on the trend */\n/* */\n/* The release-annotation pattern, applied to a care record: something */\n/* happened on a date — therapy started, a diet started, a fasting cycle */\n/* began, surgery, the gym — and the question is what the measurements did */\n/* around it. Picking an event drops one vertical line down EVERY row's */\n/* sparkline, so a variation can be read against the thing that caused it. */\n/* */\n/* TWO PROPERTIES MAKE THAT WORK, and both come from positioning by DATE */\n/* rather than by data-point index: */\n/* */\n/* 1. An event need not fall ON a visit. The oncologist starts */\n/* chemotherapy on a day the patient is not in front of this practice; */\n/* an accident happens between check-ups. Interpolating the date */\n/* between the two visits that bracket it places those at all. */\n/* */\n/* 2. Every row shares ONE x domain — the record's visit ordinals. Row k */\n/* of the grid plots one point per visit (an unmeasured visit is a */\n/* `null` that HOLDS its place, see the grid), so point i of every row */\n/* sits at i/(n-1) and a fraction derived here lands at the same x in */\n/* all of them. Deriving it per row from that row's own point count */\n/* would put the same event at a different x in a lab row than in an */\n/* anthropometric one, and the vertical read is the whole point. */\n/* */\n/* Pure: no i18n, no JSX, no React, below the label section. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport type { TFunction } from 'i18next';\nimport type { MarkerShape } from '../../components/annotation-marker';\nimport type {\n SparklineAnnotation,\n SparklineAnnotationTone,\n} from '../../components/sparkline';\nimport { hasClockTime, isReadableDate } from './anamnesis-derive';\nimport { visitDateLabel } from './anamnesis-format';\nimport type {\n ClinicalEvent,\n ClinicalEventCategory,\n Visit,\n} from './anamnesis-types';\n\n/* -------------------------------- Model --------------------------------- */\n\n/**\n * ONE shape per category, and that is the whole vocabulary — five distinct\n * glyphs, no per-category hue.\n *\n * Five saturated semantic tones (error / success / accent / warning / info)\n * used to ride these shapes. Three or four events picked at once put four\n * competing hues across a 32px-tall sparkline, nineteen rows deep, and the\n * annotations then out-shouted the trend line they exist to annotate. Shape\n * is already the accessible channel here (WCAG 1.4.1, and the kit's rule in\n * `src/components/annotation-marker/`), so the hue was reinforcement the\n * reader was paying for in noise.\n */\nexport const EVENT_SHAPE: Record<ClinicalEventCategory, MarkerShape> = {\n therapy: 'cross',\n diet: 'circle',\n fmd: 'diamond',\n surgery: 'triangle',\n lifestyle: 'square',\n};\n\n/**\n * The single restrained tone every annotation wears, chip and line alike.\n *\n * `neutral` resolves to `--muted-foreground`, the only hueless token that\n * clears WCAG 1.4.11's 3:1 for a non-text graphic in all four themes\n * (measured 6.9:1 light, 7.5:1 dark, 18.4:1 / 13.9:1 accessible, against\n * `--card`). Hueless is the point: the trend line is tinted by VALENCE —\n * green improving, red worsening — and an annotation with a hue of its own\n * competes with that read.\n */\nexport const EVENT_TONE: SparklineAnnotationTone = 'neutral';\n\n/** An event that HAS a place on the plot, with the fraction it sits at. */\nexport interface EventMark {\n event: ClinicalEvent;\n /** Fraction of the shared x domain: 0 = first visit, 1 = latest. */\n position: number;\n}\n\n/* ------------------------------ Positioning ------------------------------ */\n\n/**\n * Where an event sits on the domain every row shares, or `null` when it has\n * no place on the plot.\n *\n * `null` — rather than a clamp to 0 or 1 — for an event outside the visit\n * span: the plot covers first visit → latest, and pinning an event that\n * predates the record to the left edge would invent a correlation with a\n * measurement taken before it happened. Also `null` below two visits (no\n * extent to sit on) and on any unreadable date.\n *\n * `visits` is read in ARRAY ORDER, and chronological order is an UNCHECKED\n * precondition: an out-of-order array can bracket the event on a span that\n * runs backwards and place the marker accordingly.\n */\nexport function eventPosition(\n event: ClinicalEvent,\n visits: readonly Visit[],\n): number | null {\n const spans = visits.length - 1;\n if (spans < 1 || !isReadableDate(event.dateIso)) return null;\n\n // One axis for both stamp forms. A bare calendar date and a local\n // date-time cannot be compared as instants — `new Date` puts the first at\n // UTC midnight and the second at local time, and a same-day event then\n // falls outside the visit it belongs to anywhere off Greenwich. When either\n // side is date-only the comparison is by calendar DAY, every day anchored\n // at UTC midnight so days are uniform (local midnights are not across a\n // DST change) and an all-date-only record positions exactly as it always\n // has; only an all-datetime record positions by the clock.\n const byDay =\n !hasClockTime(event.dateIso) ||\n visits.some((visit) => !hasClockTime(visit.dateIso));\n const instant = (iso: string): number => {\n if (!byDay) return new Date(iso).getTime();\n const [y, m, d] = iso.slice(0, 10).split('-').map(Number);\n return y && m && d ? Date.UTC(y, m - 1, d) : Number.NaN;\n };\n const times = visits.map((visit) => instant(visit.dateIso));\n const at = instant(event.dateIso);\n\n for (let i = 0; i < spans; i += 1) {\n const from = times[i];\n const to = times[i + 1];\n // NaN from an unreadable visit date fails both comparisons, so a corrupt\n // visit costs that one span rather than the whole annotation.\n if (!(at >= from && at <= to)) continue;\n // Two visits recorded on the same day are one instant, not a span to\n // interpolate across — the event sits on the earlier ordinal.\n const within = to > from ? (at - from) / (to - from) : 0;\n return (i + within) / spans;\n }\n return null;\n}\n\n/** The events that can be drawn, in the order they happened. */\nexport function eventMarks(\n events: readonly ClinicalEvent[] | undefined,\n visits: readonly Visit[],\n): EventMark[] {\n return (events ?? [])\n .flatMap((event) => {\n const position = eventPosition(event, visits);\n return position == null ? [] : [{ event, position }];\n })\n .sort((a, b) => a.position - b.position);\n}\n\n/* -------------------------------- Labels -------------------------------- */\n\n/** \"Chemotherapy started · 2 Sep 2024\" — what the chip says. */\nexport function eventLabel(event: ClinicalEvent, t: TFunction): string {\n return t('anamnesis.event.chip', {\n label: t(`anamnesis.event.label.${event.labelKey}`),\n date: visitDateLabel(event.dateIso, t),\n });\n}\n\n/** Rides the chip as its accessible description: what kind of thing this was,\n * and — when it was not this practice's own decision — who recorded it. */\nexport function eventDetail(event: ClinicalEvent, t: TFunction): string {\n const category = t(`anamnesis.event.category.${event.category}`);\n if (!event.sourceKey) return category;\n return t('anamnesis.event.external', {\n category,\n source: t(`anamnesis.event.source.${event.sourceKey}`),\n });\n}\n\n/** The picked events as sparkline annotations. Every row of the grid is given\n * this SAME array, which is what pins one event to one x down the column. */\nexport function eventAnnotations(\n marks: readonly EventMark[],\n activeIds: ReadonlySet<string>,\n t: TFunction,\n): SparklineAnnotation[] {\n return marks\n .filter((mark) => activeIds.has(mark.event.id))\n .map(({ event, position }) => ({\n id: event.id,\n position,\n label: eventLabel(event, t),\n shape: EVENT_SHAPE[event.category],\n tone: EVENT_TONE,\n }));\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — the event bar above the evolution grid */\n/* */\n/* One row of toggles, one per dated thing that happened to the patient. */\n/* Picking one drops a reference line down every sparkline in the grid at */\n/* the same x, so the reader sees what the measurements did around it. */\n/* Picking none is the arrival state: the grid answers its own question */\n/* first, and the events are the second question. */\n/* */\n/* THREE CHANNELS, NEVER COLOUR ALONE: */\n/* • shape — an AnnotationMarker glyph per category, the same glyph */\n/* capping the line it draws, so chip and line pair up. */\n/* • pressed — `aria-pressed` plus the filled/outline button intent. */\n/* • text — the chip names the event and its date, and a description */\n/* beside it says what kind of thing it was and, when it was */\n/* not this practice's decision, who recorded it. */\n/* */\n/* NO TOOLTIP. The chip's whole hover popup used to be the one-word */\n/* category the marker glyph already carries — a popup that told the */\n/* reader nothing, and unreachable by touch. The same words now ride the */\n/* chip as an `aria-describedby` description, so the detail survives */\n/* without a second surface to open. */\n/* */\n/* Turning a chip ON also routes the host's side panel to that event when */\n/* the host wired one, so the reader lands on what the line means without */\n/* a second control. Turning it OFF only removes the line: navigating away */\n/* from something the reader just dismissed is not what the click meant. */\n/* The description says so when a host is wired — a control that moves the */\n/* reader's eye has to admit it, the same rule the note trigger follows. */\n/* The panel is a READING POSITION, not a mirror of the drawn set: it goes */\n/* on holding the last event asked about after that line is dismissed. */\n/* */\n/* The lines themselves are svg strokes and say nothing aloud, so the bar */\n/* also carries a polite live region naming the picked events — that is */\n/* the screen-reader equivalent of the vertical read. */\n/* -------------------------------------------------------------------- */\n\nimport { Fragment, useId } from 'react';\nimport type { TFunction } from 'i18next';\nimport { AnnotationMarker } from '../../components/annotation-marker';\nimport { Button } from '../../components/button';\nimport {\n EVENT_SHAPE,\n EVENT_TONE,\n eventDetail,\n eventLabel,\n type EventMark,\n} from './anamnesis-events';\n\n/* -------------------------------- Props --------------------------------- */\n\nexport interface AnamnesisEventBarProps {\n /** Events that HAVE a position on the plot, in the order they happened.\n * One with no place on it never reaches here — see `eventMarks`. */\n marks: readonly EventMark[];\n activeIds: ReadonlySet<string>;\n onToggle: (eventId: string) => void;\n t: TFunction;\n}\n\n/* ------------------------------- Component ------------------------------ */\n\nexport function AnamnesisEventBar({\n marks,\n activeIds,\n onToggle,\n t,\n}: AnamnesisEventBarProps) {\n const labelId = useId();\n const detailId = useId();\n // Nothing dated to draw ⇒ no bar. An empty toolbar of controls that cannot\n // do anything is chrome the clinician has to read past.\n if (marks.length === 0) return null;\n\n const active = marks.filter((mark) => activeIds.has(mark.event.id));\n\n return (\n <div\n data-testid=\"anamnesis-event-bar\"\n role=\"group\"\n aria-labelledby={labelId}\n className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\"\n >\n <span\n id={labelId}\n className=\"type-eyebrow ds:text-[color:var(--muted-foreground)]\"\n >\n {t('anamnesis.event.barLabel')}\n </span>\n {marks.map(({ event }) => {\n const pressed = activeIds.has(event.id);\n return (\n <Fragment key={event.id}>\n <Button\n size=\"sm\"\n intent={pressed ? 'primary' : 'outline'}\n aria-pressed={pressed}\n aria-describedby={`${detailId}-${event.id}`}\n data-testid={`anamnesis-event-chip-${event.id}`}\n startIcon={\n <AnnotationMarker\n shape={EVENT_SHAPE[event.category]}\n tone={EVENT_TONE}\n size=\"sm\"\n />\n }\n // A chip is a pure LINE toggle: pressing it draws or removes\n // the event's reference line and nothing else. OPENING the\n // event's note is the line's own pointer band (and the host's\n // notes-view entry point for keyboard readers) — a toggle that\n // also opened a modal covered the very grid it had just\n // annotated.\n onClick={() => onToggle(event.id)}\n >\n {eventLabel(event, t)}\n </Button>\n {/* The category (and the outside source, where there is one) in\n words. The chip only toggles the line, so the description\n never claims a navigation it no longer performs. */}\n <span id={`${detailId}-${event.id}`} className=\"ds:sr-only\">\n {eventDetail(event, t)}\n </span>\n </Fragment>\n );\n })}\n {/* The vertical read, in words. Polite so it follows the click rather\n than interrupting it. */}\n <p className=\"ds:sr-only\" aria-live=\"polite\">\n {active.length === 0\n ? t('anamnesis.event.noneShown')\n : t('anamnesis.event.shown', {\n list: active\n .map(({ event }) => eventLabel(event, t))\n .join(t('anamnesis.event.separator')),\n })}\n </p>\n </div>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — the notes bound to one visit */\n/* */\n/* What happened at THIS check-up, read where the check-up is: a note */\n/* affordance in the evolution grid's visit-column header. The trigger */\n/* exists only when the visit actually carries a note, so a column with */\n/* nothing to say shows no dead button. Both free-text fields the visit */\n/* already holds are read together — the clinical note (what was observed) */\n/* first, the nutritional proposal (what was decided) second. */\n/* */\n/* A note recorded at a visit the reader has not picked in the visit */\n/* multi-select is reached by picking that visit — the selection is explicit, */\n/* so nothing is hidden behind a column that is not there. */\n/* */\n/* WHERE THE NOTE OPENS depends on whether the host has a side panel: */\n/* • host wired (`onOpenNote`) — the trigger hands the visit id OUT and */\n/* the host's panel navigates to it. One place notes live, so the grid */\n/* does not carry a second copy of the reading surface. */\n/* • no host — the trigger opens the note in place. This is the only way */\n/* a standalone anamnesis can read a past visit's note at all, and only */\n/* ONE of the two branches ever renders, so nothing is duplicated. */\n/* */\n/* Clinician-only: the `visit.note` row in anamnesis-disclosure.ts. */\n/* -------------------------------------------------------------------- */\n\nimport type { TFunction } from 'i18next';\nimport { NotebookPen } from 'lucide-react';\nimport { DescriptionList } from '../../components/description-list';\nimport { IconButton } from '../../components/icon-button';\nimport { Popover } from '../../components/popover';\nimport { Timestamp } from '../../components/timestamp';\nimport { calendarFormatFor, type TextField } from './anamnesis-derive';\nimport { visitDateLabel } from './anamnesis-format';\nimport type { OpenAnamnesisNote, Visit } from './anamnesis-types';\n\n/* -------------------------------- Model --------------------------------- */\n\n/** One free-text note recorded at a visit. */\nexport interface VisitNote {\n field: TextField;\n text: string;\n}\n\n/** Reading order: what was observed, then what was proposed. */\nconst NOTE_FIELDS: readonly TextField[] = [\n 'clinicalNotes',\n 'nutritionalProposal',\n];\n\n/** The visit's notes, blank ones dropped. Whitespace-only text is not a note —\n * an empty string would otherwise open a popover onto nothing. */\nexport function visitNotes(visit: Visit): VisitNote[] {\n return NOTE_FIELDS.flatMap((field) => {\n const text = visit[field]?.trim();\n return text ? [{ field, text }] : [];\n });\n}\n\n/** Whether this visit has anything to read. Drives the trigger's existence. */\nexport function hasVisitNotes(visit: Visit): boolean {\n return visitNotes(visit).length > 0;\n}\n\n/* ----------------------------- Shared body ------------------------------ */\n\n/** One visit's notes as a term↔detail list, under the same labels the compile\n * form uses. Exported so a HOST side panel renders the note the same way the\n * in-place fallback does — one definition of what a note looks like. */\nexport function AnamnesisVisitNoteList({\n visit,\n t,\n}: {\n visit: Visit;\n t: TFunction;\n}) {\n return (\n <DescriptionList layout=\"stacked\" divider=\"between\">\n {visitNotes(visit).map((note) => (\n <DescriptionList.Row key={note.field}>\n <DescriptionList.Term>\n {t(`anamnesis.field.${note.field}.label`)}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n <span className=\"ds:block ds:break-words ds:whitespace-pre-line\">\n {note.text}\n </span>\n </DescriptionList.Detail>\n </DescriptionList.Row>\n ))}\n </DescriptionList>\n );\n}\n\n/** The scroll region every note panel puts its body in. A long note scrolls\n * inside the popover rather than growing past the viewport, and the region\n * takes a tab stop so a keyboard user can reach the scrollbar. */\nconst NOTE_SCROLL_CLASS =\n 'ds:mt-[var(--spacing-md)] ds:max-h-[min(20rem,var(--radix-popover-content-available-height))] ds:overflow-y-auto ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]';\n\n/* -------------------------------- Props --------------------------------- */\n\nexport interface AnamnesisVisitNoteProps {\n visit: Visit;\n t: TFunction;\n /** Render already open. Chromatic never runs play functions, so the story\n * that snapshots the note has to mount it open. Ignored when `onOpenNote`\n * is wired — the host owns the panel and its open state. */\n defaultOpen?: boolean;\n /** The host's side panel. Supplied ⇒ the trigger routes there instead of\n * opening a popover; omitted ⇒ it opens the note in place. Wiring it obliges\n * the host to render a panel AND to move focus to or announce the addressed\n * note — see `OpenAnamnesisNote`. */\n onOpenNote?: OpenAnamnesisNote;\n}\n\n/* ------------------------------- Component ------------------------------ */\n\nexport function AnamnesisVisitNote({\n visit,\n t,\n defaultOpen = false,\n onOpenNote,\n}: AnamnesisVisitNoteProps) {\n const notes = visitNotes(visit);\n if (notes.length === 0) return null;\n\n const visitTypeLabel = t(`anamnesis.visitType.${visit.visitType}`);\n const dateLabel = visitDateLabel(visit.dateIso, t);\n // Names the visit, not just \"Notes\": in a grid of columns the reader has to\n // know which check-up the note belongs to before opening it. The routed name\n // also says WHERE it opens, because the answer arrives off to the side.\n const triggerLabel = t(\n onOpenNote\n ? 'anamnesis.visitNote.openInPanel'\n : 'anamnesis.visitNote.trigger',\n { visitType: visitTypeLabel, date: dateLabel },\n );\n\n if (onOpenNote) {\n return (\n <IconButton\n icon={<NotebookPen aria-hidden=\"true\" />}\n intent=\"ghost\"\n size=\"sm\"\n aria-label={triggerLabel}\n data-testid={`anamnesis-visit-note-trigger-${visit.id}`}\n onClick={() => onOpenNote({ kind: 'visit', visitId: visit.id })}\n />\n );\n }\n\n return (\n <Popover defaultOpen={defaultOpen}>\n <Popover.Trigger asChild>\n <IconButton\n icon={<NotebookPen aria-hidden=\"true\" />}\n intent=\"ghost\"\n size=\"sm\"\n aria-label={triggerLabel}\n data-testid={`anamnesis-visit-note-trigger-${visit.id}`}\n />\n </Popover.Trigger>\n <Popover.Content\n size=\"lg\"\n align=\"start\"\n data-testid={`anamnesis-visit-note-panel-${visit.id}`}\n // Mounted-open is a demo state, not a user action: stealing focus there\n // would scroll the docs page to the canvas on load.\n onOpenAutoFocus={\n defaultOpen ? (event) => event.preventDefault() : undefined\n }\n >\n <Popover.Close />\n <Popover.Heading>{t('anamnesis.visitNote.title')}</Popover.Heading>\n <Popover.Description>\n {visitTypeLabel}\n {' · '}\n <Timestamp\n value={visit.dateIso}\n format=\"absolute\"\n shape=\"bare\"\n absoluteFormat={calendarFormatFor(visit.dateIso)}\n />\n {visit.practitioner ? (\n <>\n {' · '}\n <span className=\"ds:break-words\">{visit.practitioner}</span>\n </>\n ) : null}\n </Popover.Description>\n <div\n /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- a long note scrolls inside the popover; axe scrollable-region-focusable needs the tab stop */\n tabIndex={0}\n role=\"group\"\n aria-label={t('anamnesis.visitNote.title')}\n className={NOTE_SCROLL_CLASS}\n >\n <AnamnesisVisitNoteList visit={visit} t={t} />\n </div>\n </Popover.Content>\n </Popover>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — the across-visits matrix shell */\n/* */\n/* ONE definition of the shape both across-visits reads wear: the */\n/* evolution grid and the compare panel below it. COLUMN ORDER LIVES HERE */\n/* AND NOWHERE ELSE — */\n/* identity → the first compared visit → the trend sparkline → */\n/* every remaining visit → an optional trailing column. */\n/* Two surfaces re-deriving that order is exactly how they drift apart, */\n/* and the customer reads them one under the other. */\n/* */\n/* The shell owns the scroll region and its tab stop, the sticky edges, */\n/* the caption and the group banners. Each surface supplies its own */\n/* <th>/<td> ELEMENTS, because what a cell holds differs (an editable */\n/* input here, a diff value there) while where it sits must not. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport type { ReactNode } from 'react';\nimport type { TFunction } from 'i18next';\nimport { Badge } from '../../components/badge';\nimport { Timestamp } from '../../components/timestamp';\nimport { calendarFormatFor } from './anamnesis-derive';\nimport type { OpenAnamnesisNote, Visit } from './anamnesis-types';\nimport { AnamnesisVisitNote } from './anamnesis-visit-note';\nimport type { VisitColumn } from './anamnesis-window';\n\n/* -------------------------------- Sizing -------------------------------- */\n\n/** Static class literals — Tailwind has to see every arbitrary value at build\n * time, and a class built by interpolation emits no CSS at all. */\n/** Floored at the longest parameter label + its unit and reference range on\n * ONE line — measured across en / ar / ja under `.theme-accessible`, whose\n * larger type is the widest case (ja \"HDLコレステロール\", 147px + 16px of cell\n * padding). Below that the label wraps and the cell goes to three lines. */\nexport const MATRIX_IDENTITY_CLASS = 'ds:min-w-[11rem]';\n/** Floored by the editable cell, not by the number it shows: `NumberInput`\n * spends 56px on its two spinners and 16px on input padding before a digit is\n * drawn, so 128px of column is 40px of readable value. It cannot go lower. */\nexport const MATRIX_VISIT_COLUMN_CLASS = 'ds:min-w-[8rem]';\n/**\n * A PERCENTAGE, not a rem cap — that is what redirects the spare pixels.\n *\n * Under `table-layout: auto` the spare width of a table narrower than its\n * container goes to whichever columns declare no width, and `max-width` on a\n * table cell is only honoured while some other column is left to absorb. The\n * old `w-[9rem] max-w-[10rem]` therefore pinned the trend at 160px and handed\n * everything else to the identity and value columns — 325px and 443px of\n * mostly whitespace at 1440px wide. Claiming a share instead inverts that.\n * When the table DOES overflow, the percentage stops applying and the\n * min-width is what the trend gets.\n */\nexport const MATRIX_TREND_COLUMN_CLASS = 'ds:w-[40%] ds:min-w-[14rem]';\n\nconst IDENTITY_HEADER_CLASS =\n 'type-label ds:sticky ds:start-0 ds:top-0 ds:z-[3] ds:bg-[color:var(--card)] ds:px-[var(--spacing-sm)] ds:py-[var(--spacing-sm)] ds:text-start ds:shadow-[var(--shadow-chrome-end)]';\nconst COLUMN_HEADER_CLASS =\n 'ds:sticky ds:top-0 ds:z-[2] ds:px-[var(--spacing-sm)] ds:py-[var(--spacing-sm)] ds:text-start ds:shadow-[var(--shadow-chrome-down)]';\n/** The trailing column mirrors the identity column on the opposite edge: it\n * carries the answer, and horizontal scroll must not be what takes it away. */\nconst TRAILING_HEADER_CLASS =\n 'type-label ds:sticky ds:end-0 ds:top-0 ds:z-[3] ds:bg-[color:var(--card)] ds:px-[var(--spacing-sm)] ds:py-[var(--spacing-sm)] ds:text-start ds:shadow-[var(--shadow-chrome-start)]';\n\n/** Apply to every `<td>` a surface hands to `trailing`, so the column sticks\n * as one piece rather than only in its header. */\nexport const MATRIX_TRAILING_CELL_CLASS =\n 'ds:sticky ds:end-0 ds:z-[1] ds:bg-[color:var(--card)] ds:shadow-[var(--shadow-chrome-start)]';\n\n/** Every body cell in a value column. Exported so both surfaces open from the\n * same padding / alignment rather than each picking its own. */\nexport const MATRIX_CELL_CLASS =\n 'ds:px-[var(--spacing-sm)] ds:py-[var(--spacing-xs)] ds:align-top';\n\n/* ----------------------------- Visit header ----------------------------- */\n\nexport interface MatrixVisitHeaderProps {\n column: VisitColumn;\n t: TFunction;\n /** Muted fill — the column is one of the compared pair/set. */\n emphasised?: boolean;\n /** Adds the \"Editable\" chip; compile mode's newest column only. */\n editable?: boolean;\n /** Render this visit's note popover already open (demo hook). */\n defaultOpenNoteVisitId?: string;\n /** Offer the note affordance. The compare panel sets this `false`: its\n * columns repeat the grid's, and two note triggers with the same accessible\n * name on one screen is a control the reader has to disambiguate. */\n withNote?: boolean;\n /** Route the note to the host's side panel instead of opening it in place. */\n onOpenNote?: OpenAnamnesisNote;\n /** The first visits this column merges, oldest first. Set only on the\n * synthetic baseline column: the header then lists them instead of one\n * date, and offers no note trigger (there is no single visit to open). */\n mergedFrom?: readonly Visit[];\n}\n\n/** One visit's `<th scope=\"col\">`, identical wherever the visit is a column. */\nexport function MatrixVisitHeader({\n column,\n t,\n emphasised = false,\n editable = false,\n defaultOpenNoteVisitId,\n withNote = true,\n onOpenNote,\n mergedFrom,\n}: MatrixVisitHeaderProps) {\n const { visit } = column;\n const headerClass = [\n MATRIX_VISIT_COLUMN_CLASS,\n COLUMN_HEADER_CLASS,\n emphasised ? 'ds:bg-[color:var(--muted)]' : 'ds:bg-[color:var(--card)]',\n ].join(' ');\n\n if (mergedFrom) {\n return (\n <th\n scope=\"col\"\n data-testid=\"anamnesis-baseline-header\"\n className={headerClass}\n >\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-2xs)]\">\n <Badge variant=\"brand\" size=\"sm\">\n {t('anamnesis.visitType.first')}\n </Badge>\n {editable ? (\n <Badge variant=\"accentSoft\" size=\"sm\">\n {t('anamnesis.grid.editable')}\n </Badge>\n ) : null}\n </span>\n <span className=\"type-meta ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.grid.baselineMerged', { total: mergedFrom.length })}\n </span>\n {/* One line per merged module, oldest first — the same Timestamp\n the real columns use, so dates format identically across. */}\n {mergedFrom.map((source) => (\n <span\n key={source.id}\n data-testid={`anamnesis-baseline-source-${source.id}`}\n className=\"type-meta ds:text-[color:var(--muted-foreground)]\"\n >\n {source.sourceLabel ? (\n <>\n {source.sourceLabel}\n {' · '}\n </>\n ) : null}\n <Timestamp\n value={source.dateIso}\n format=\"absolute\"\n shape=\"bare\"\n absoluteFormat={calendarFormatFor(source.dateIso)}\n />\n </span>\n ))}\n </div>\n </th>\n );\n }\n\n return (\n <th scope=\"col\" className={headerClass}>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n {/* The note sits at the column's top-end corner in every column that\n has one, so it scans across at one glance. It renders nothing\n when the visit carries no note. */}\n <span className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-2xs)]\">\n <span className=\"type-label ds:text-[color:var(--foreground)]\">\n {/* A visit stamped with a time shows it: two interviews of one\n module on the same day are two columns, told apart here. */}\n <Timestamp\n value={visit.dateIso}\n format=\"absolute\"\n shape=\"bare\"\n absoluteFormat={calendarFormatFor(visit.dateIso)}\n />\n </span>\n {withNote ? (\n <AnamnesisVisitNote\n visit={visit}\n t={t}\n defaultOpen={visit.id === defaultOpenNoteVisitId}\n onOpenNote={onOpenNote}\n />\n ) : null}\n </span>\n {visit.sourceLabel ? (\n <span\n data-testid={`anamnesis-visit-source-${visit.id}`}\n className=\"type-meta ds:text-[color:var(--muted-foreground)]\"\n >\n {visit.sourceLabel}\n </span>\n ) : null}\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-2xs)]\">\n <Badge\n variant={visit.visitType === 'first' ? 'brand' : 'neutral'}\n size=\"sm\"\n >\n {t(`anamnesis.visitType.${visit.visitType}`)}\n </Badge>\n {editable ? (\n <Badge variant=\"accentSoft\" size=\"sm\">\n {t('anamnesis.grid.editable')}\n </Badge>\n ) : null}\n </span>\n </div>\n </th>\n );\n}\n\n/* --------------------------------- Rows --------------------------------- */\n\nexport interface MatrixRowSpec {\n key: string;\n /** Full-width group banner. When set, every other field is ignored. */\n banner?: string;\n /** The row's `<th scope=\"row\">` element. */\n header?: ReactNode;\n /** One `<td>` per visit column, in column order. */\n cells?: readonly ReactNode[];\n /** The `<td>` under the trend column. */\n trend?: ReactNode;\n /** The `<td>` under the trailing column, where the table declares one. */\n trailing?: ReactNode;\n}\n\n/* -------------------------------- Props --------------------------------- */\n\nexport interface AnamnesisMatrixProps {\n captionId: string;\n /** Screen-reader caption naming what the table holds. */\n caption: string;\n /** Header of the sticky identity column. */\n identityLabel: string;\n /** Header of the trend column. */\n trendLabel: string;\n /** Test hook on the trend header. Only one matrix on screen may claim it,\n * so the grid takes it and the compare panel below goes without. */\n trendTestId?: string;\n /** One `<th scope=\"col\">` per visit column — build them with\n * `MatrixVisitHeader` so the two surfaces cannot disagree. */\n visitHeaders: readonly ReactNode[];\n /** Header of a column rendered after every visit. Omitted = no such column. */\n trailingLabel?: string;\n /** Test hook on the trailing header — the surface names it, not the shell. */\n trailingTestId?: string;\n rows: readonly MatrixRowSpec[];\n /** Draw the outer border + surface. `false` inside a card, to avoid a\n * box-in-a-box. */\n framed?: boolean;\n testId?: string;\n}\n\n/* ------------------------------- Component ------------------------------ */\n\nexport function AnamnesisMatrix({\n captionId,\n caption,\n identityLabel,\n trendLabel,\n trendTestId,\n visitHeaders,\n trailingLabel,\n trailingTestId,\n rows,\n framed = true,\n testId,\n}: AnamnesisMatrixProps) {\n // Identity + trend + every visit + the optional trailing column. The group\n // banner spans all of them, so it must be counted here rather than guessed.\n const columnCount = visitHeaders.length + 2 + (trailingLabel ? 1 : 0);\n\n return (\n <div\n /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- horizontal-scroll comparison grid needs a keyboard tab stop (axe scrollable-region-focusable); the semantic table is the accessible source of truth */\n tabIndex={0}\n role=\"group\"\n aria-labelledby={captionId}\n data-testid={testId}\n className={[\n 'ds:w-full ds:overflow-x-auto ds:outline-none ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n framed\n ? 'ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--border)] ds:bg-[color:var(--card)]'\n : '',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n <table className=\"ds:w-full ds:border-collapse\">\n <caption id={captionId} className=\"ds:sr-only\">\n {caption}\n </caption>\n <thead>\n <tr>\n {/* Top-start corner — sticky on both axes, highest layer */}\n <th\n scope=\"col\"\n className={`${MATRIX_IDENTITY_CLASS} ${IDENTITY_HEADER_CLASS}`}\n >\n {identityLabel}\n </th>\n {visitHeaders[0]}\n <th\n scope=\"col\"\n data-testid={trendTestId}\n className={[\n MATRIX_TREND_COLUMN_CLASS,\n 'type-label ds:bg-[color:var(--card)]',\n COLUMN_HEADER_CLASS,\n ].join(' ')}\n >\n {trendLabel}\n </th>\n {visitHeaders.slice(1)}\n {trailingLabel ? (\n <th\n scope=\"col\"\n data-testid={trailingTestId}\n className={`${MATRIX_VISIT_COLUMN_CLASS} ${TRAILING_HEADER_CLASS}`}\n >\n {trailingLabel}\n </th>\n ) : null}\n </tr>\n </thead>\n <tbody>\n {rows.map((row) =>\n row.banner != null ? (\n <tr key={row.key} className=\"ds:bg-[color:var(--muted)]\">\n {/* Full-width section banner heading the rows below it;\n `scope` is intentionally omitted (it heads rows, not a\n column). */}\n {/* No sticky: the cell already spans the whole table, so\n pinning it moves nothing and only risks a see-through\n layer over scrolled content. */}\n <th\n colSpan={columnCount}\n className=\"type-eyebrow ds:px-[var(--spacing-sm)] ds:py-[var(--spacing-2xs)] ds:text-start ds:text-[color:var(--muted-foreground)]\"\n >\n {row.banner}\n </th>\n </tr>\n ) : (\n <tr key={row.key}>\n {row.header}\n {row.cells?.[0]}\n {row.trend}\n {row.cells?.slice(1)}\n {row.trailing}\n </tr>\n ),\n )}\n </tbody>\n </table>\n </div>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — visit window (which visit columns are rendered) */\n/* */\n/* The comparison IS the grid: the picker lists every visit and opens with */\n/* ALL of them ticked, so every column and every adjacent delta is on */\n/* screen on arrival. Un-ticking a visit removes its column — the reader */\n/* narrows the history, never widens it. */\n/* */\n/* Nothing stands in for an un-ticked visit: the omission is the reader's */\n/* own choice, so a column naming it would be noise. */\n/* */\n/* Pure: no i18n, no JSX, no React. It filters RENDERED COLUMNS only, */\n/* never the maths. `buildParameterRows` always runs over the full */\n/* `record.visits`, so a cell's delta never depends on the selection. */\n/* Visits are read in ARRAY ORDER and never re-sorted, for the same */\n/* reason. */\n/* */\n/* The merged first-visit baseline is pinned through `alwaysShowIds`: it */\n/* renders in every window and is never counted as shown or hidden. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport type { Visit } from './anamnesis-types';\n\n/* -------------------------------- Columns ------------------------------- */\n\n/** One rendered column. `index` is the position in the FULL visit array, so\n * the grid still reads the cell whose delta was computed there. */\nexport interface VisitColumn {\n key: string;\n visit: Visit;\n index: number;\n}\n\nexport interface VisitWindow {\n columns: VisitColumn[];\n shownCount: number;\n totalCount: number;\n hiddenCount: number;\n /** First / last date among the SHOWN columns, in record order (never\n * re-sorted). Null when nothing is shown. */\n firstIso: string | null;\n lastIso: string | null;\n}\n\nexport interface VisitWindowOptions {\n /** Ids rendered in every window and EXCLUDED from the counts — the merged\n * baseline. \"Showing N of M\" counts only what the picker can toggle. */\n alwaysShowIds?: Iterable<string>;\n}\n\n/* --------------------------------- API ---------------------------------- */\n\n/** The selection the picker opens on: every visit, in record order. Empty\n * on an empty record. Also the export's fallback when a host passed no\n * selection, so a file with no mirrored picker matches the on-screen default. */\nexport function defaultSelectedVisitIds(visits: readonly Visit[]): string[] {\n return visits.map((v) => v.id);\n}\n\n/** Resolve which visit columns render, in RECORD order — never in the order\n * the reader happened to tick them. Safe on an empty record, a single-visit\n * record, same-date visits and out-of-order visits. */\nexport function windowVisits(\n visits: readonly Visit[],\n selectedIds: Iterable<string>,\n options: VisitWindowOptions = {},\n): VisitWindow {\n const pinned = new Set<string>(options.alwaysShowIds ?? []);\n const shown = new Set<string>(selectedIds);\n for (const id of pinned) shown.add(id);\n\n const columns: VisitColumn[] = [];\n visits.forEach((visit, index) => {\n if (shown.has(visit.id)) columns.push({ key: visit.id, visit, index });\n });\n\n // A pinned column is neither shown-by-choice nor hidden, so it drops out of\n // every count and the readout says only what the reader can change.\n const pinnedShown = columns.filter((c) => pinned.has(c.visit.id)).length;\n const pinnedTotal = visits.filter((v) => pinned.has(v.id)).length;\n const shownCount = columns.length - pinnedShown;\n const totalCount = visits.length - pinnedTotal;\n\n return {\n columns,\n shownCount,\n totalCount,\n hiddenCount: totalCount - shownCount,\n firstIso: columns[0]?.visit.dateIso ?? null,\n lastIso: columns[columns.length - 1]?.visit.dateIso ?? null,\n };\n}\n\n/** Every visit as its own column — the unwindowed default. */\nexport function allVisitColumns(visits: readonly Visit[]): VisitColumn[] {\n return windowVisits(visits, defaultSelectedVisitIds(visits)).columns;\n}\n\n/** Whether the picker has more than one visit to offer. With one visit it is\n * chrome the clinician has to read and cannot use, so the toolbar leaves it\n * out entirely. */\nexport function visitPickerIsUseful(visits: readonly Visit[]): boolean {\n return visits.length >= 2;\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — evolution grid (the Excel replacement) */\n/* */\n/* The parameters-as-rows, visits-as-columns matrix, modernised. A real */\n/* semantic <table> inside a keyboard-focusable horizontal-scroll region */\n/* (axe scrollable-region-focusable). The parameter column is sticky on the */\n/* INLINE-START edge (flips correctly under RTL — logical, not \"left\"), the */\n/* visit-header row is sticky on the block-start edge; both use opaque */\n/* surface tokens + the chrome-divider shadows so scrolled cells are */\n/* occluded. Each cell shows the value, an out-of-range flag, and the */\n/* direction-aware delta vs the previous visit. The newest visit column is */\n/* editable; older columns are read-only. */\n/* */\n/* COLUMN ORDER, and nothing may be inserted into it: */\n/* parameter identity → the first picked visit → the trend sparkline → */\n/* every remaining picked visit. */\n/* The baseline value sits beside the parameter it belongs to, and the */\n/* sparkline reads as the bridge from it to the columns that follow. */\n/* */\n/* A visit-column header carries the note affordance for that visit, when — */\n/* and only when — that visit has a note to read. A note recorded at a visit */\n/* the reader has not picked is reached by picking that visit. */\n/* */\n/* Columns are supplied by the visit window, which by default renders every */\n/* visit. A delta is drawn only where the column before it on screen IS the */\n/* visit it was measured against — un-ticking a visit hides the chip after it. */\n/* -------------------------------------------------------------------- */\n\nimport { useId } from 'react';\nimport type { TFunction } from 'i18next';\nimport { NumberInput } from '../../components/number-input';\nimport { isBaselineVisit } from './anamnesis-baseline';\nimport { EmptyState } from '../../components/empty-state';\nimport type { SparklineAnnotation } from '../../components/sparkline';\nimport {\n buildParameterRows,\n formatValue,\n type ParameterCell,\n type ParameterRow,\n} from './anamnesis-derive';\nimport { localeOf, parameterLabel } from './anamnesis-format';\nimport {\n DeltaIndicator,\n OutOfRangeBadge,\n TrendSparkline,\n} from './anamnesis-indicators';\nimport {\n AnamnesisMatrix,\n MATRIX_CELL_CLASS,\n MATRIX_IDENTITY_CLASS,\n MATRIX_TREND_COLUMN_CLASS,\n MATRIX_VISIT_COLUMN_CLASS,\n MatrixVisitHeader,\n type MatrixRowSpec,\n} from './anamnesis-matrix';\nimport { allVisitColumns, type VisitColumn } from './anamnesis-window';\nimport type {\n AnamnesisRecord,\n NumericParameterDef,\n OpenAnamnesisNote,\n Visit,\n} from './anamnesis-types';\n\n/* -------------------------------- Sizing -------------------------------- */\n\n/** Stand-in for a column whose cell was never computed — a caller can pass\n * columns resolved against a different record. Reads as \"not measured\" rather\n * than throwing on `undefined.value`. */\nconst UNMEASURED_CELL: ParameterCell = {\n visitId: '',\n value: null,\n outOfRange: null,\n delta: null,\n};\n\n/* ------------------------------- Helpers -------------------------------- */\n\n/** A delta was measured against the immediately preceding visit in the record.\n * It may only be drawn where that visit is the column before it on screen —\n * otherwise the chip reads as the change across everything left out. */\nfunction deltaIsLegible(columns: readonly VisitColumn[], at: number): boolean {\n const column = columns[at];\n const previous = columns[at - 1];\n if (!previous) return column.index === 0;\n return previous.index === column.index - 1;\n}\n\n/** A reference bound at its own precision — \"18.5\", never \"18.50\" or \"19\" —\n * in the app locale, like every figure in the cells beside it. */\nfunction formatBound(bound: number, locale: string | undefined): string {\n const decimals = (String(bound).split('.')[1] ?? '').length;\n return formatValue(bound, Math.min(decimals, 3), locale);\n}\n\nfunction formatRange(\n range: NumericParameterDef['referenceRange'],\n t: TFunction,\n locale: string | undefined,\n): string | null {\n if (!range) return null;\n if (range.min != null && range.max != null)\n return `${formatBound(range.min, locale)}–${formatBound(range.max, locale)}`;\n if (range.max != null)\n return t('anamnesis.range.atMost', {\n value: formatBound(range.max, locale),\n });\n if (range.min != null)\n return t('anamnesis.range.atLeast', {\n value: formatBound(range.min, locale),\n });\n return null;\n}\n\n/* -------------------------------- Props --------------------------------- */\n\nexport interface AnamnesisEvolutionGridProps {\n record: AnamnesisRecord;\n defs: NumericParameterDef[];\n t: TFunction;\n /** Make the newest visit column editable (compile mode). */\n editable?: boolean;\n /** The visit whose column takes the inputs, by id. Omitted = the record's\n * last visit. The evolution section sets it from the REAL record: on the\n * merged view the last position need not be the visit being compiled. */\n editableVisitId?: string;\n onCellChange?: (\n visit: Visit,\n def: NumericParameterDef,\n value: number | null,\n ) => void;\n /** Draw the outer border + surface (standalone use). Set `false` when the\n * grid already sits inside a card, to avoid a box-in-a-box. */\n framed?: boolean;\n /** Mount this visit's note popover already open. Demo/story hook only —\n * Chromatic skips play functions, so a click-opened popover is never\n * snapshotted. Ignored once `onOpenNote` is wired. */\n defaultOpenNoteVisitId?: string;\n /** Route a visit's note to the host's side panel instead of opening it in\n * place. Omitted = read in place, which is all a standalone grid can do. */\n onOpenNote?: OpenAnamnesisNote;\n /** Which columns render, from the visit window. Omitted = every visit.\n * Column order and `index` always follow `record.visits`; the window\n * changes what is SHOWN, never what was computed. */\n visitColumns?: readonly VisitColumn[];\n /** Keys the practice still captures. A key outside this set renders its\n * history read-only: archiving stops capture, it never erases the record.\n * Omitted = every def is capturable. */\n capturableKeys?: ReadonlySet<string>;\n /** Event reference lines, positioned as a fraction of the record's visit\n * span. Every row gets this SAME array, which is what makes one event one\n * vertical line down the whole grid rather than one line per row. */\n annotations?: readonly SparklineAnnotation[];\n /** Make those lines pointer-selectable — pressing one is pressing the\n * event's chip in the bar above. Omitted = the lines stay decorative, which\n * is all a grid with no event bar above it can honestly offer. */\n onSelectAnnotation?: (eventId: string) => void;\n /** The first visits the leftmost column merges, oldest first; the header\n * lists them. Omitted = no column is synthetic. */\n baselineSources?: readonly Visit[];\n /** Insert the parameter-group banner rows. `false` when the caller has\n * already headed the table — a per-source block names its module above\n * it, and \"Blood tests\" over a questionnaire's water question misleads. */\n groupBanners?: boolean;\n /** The table's caption. A per-source block names its module here so N\n * tables on one page do not share one accessible name. */\n caption?: string;\n}\n\n/* ------------------------------- Component ------------------------------ */\n\nexport function AnamnesisEvolutionGrid({\n record,\n defs,\n t,\n editable = false,\n editableVisitId,\n onCellChange,\n framed = true,\n defaultOpenNoteVisitId,\n onOpenNote,\n visitColumns,\n capturableKeys,\n annotations,\n onSelectAnnotation,\n baselineSources,\n groupBanners = true,\n caption,\n}: AnamnesisEvolutionGridProps) {\n const captionId = useId();\n const locale = localeOf(t);\n const rows = buildParameterRows(record, defs);\n const visits = record.visits;\n const editableId = editableVisitId ?? visits[visits.length - 1]?.id;\n const columns = visitColumns ?? allVisitColumns(visits);\n\n // Insert a group-heading row whenever the parameter group changes.\n const renderedRows: MatrixRowSpec[] = [];\n let lastGroup: string | null = null;\n\n rows.forEach((row: ParameterRow) => {\n if (groupBanners && row.def.group !== lastGroup) {\n lastGroup = row.def.group;\n renderedRows.push({\n key: `group-${row.def.group}`,\n banner: t(`anamnesis.group.${row.def.group}`),\n });\n }\n\n const rangeText = formatRange(row.def.referenceRange, t, locale);\n\n // One <td> per rendered column, built in column order; the trend cell is\n // spliced in after the first of them below.\n const valueCells = columns.map((column, columnIndex) => {\n const { visit, index } = column;\n const cell = row.cells[index] ?? UNMEASURED_CELL;\n // Identity, not position: the merged view folds first visits away, so\n // the last column can be an older visit than the one being compiled.\n // The synthetic baseline is nobody's visit and never takes an input.\n const isEditableVisit =\n visit.id === editableId && !isBaselineVisit(visit);\n const capturable =\n capturableKeys == null || capturableKeys.has(row.def.key);\n const editableCell =\n editable && isEditableVisit && capturable && !row.def.computed;\n const deltaHidden = !deltaIsLegible(columns, columnIndex);\n return (\n <td\n key={column.key}\n className={[\n MATRIX_VISIT_COLUMN_CLASS,\n MATRIX_CELL_CLASS,\n 'ds:tabular-nums',\n ].join(' ')}\n >\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n {editableCell ? (\n <NumberInput\n size=\"sm\"\n value={cell.value}\n mode={(row.def.precision ?? 0) > 0 ? 'decimal' : 'integer'}\n aria-label={t('anamnesis.grid.editCell', {\n parameter: parameterLabel(row.def, t),\n })}\n onChange={(next) => onCellChange?.(visit, row.def, next)}\n />\n ) : (\n <span className=\"type-body-sm ds:font-[var(--font-weight-medium)] ds:text-[color:var(--foreground)]\">\n {formatValue(cell.value, row.def.precision, locale)}\n </span>\n )}\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-2xs)]\">\n {cell.outOfRange ? (\n <OutOfRangeBadge flag={cell.outOfRange} t={t} compact />\n ) : null}\n {deltaHidden ? null : (\n <DeltaIndicator delta={cell.delta} def={row.def} t={t} />\n )}\n </div>\n </div>\n </td>\n );\n });\n\n renderedRows.push({\n key: row.def.key,\n // Sticky parameter column (inline-start). The shell splices the trend\n // in after the first value cell — the order is not decided here.\n header: (\n <th\n scope=\"row\"\n className={`${MATRIX_IDENTITY_CLASS} ds:sticky ds:start-0 ds:z-[1] ds:bg-[color:var(--card)] ds:text-start ds:shadow-[var(--shadow-chrome-end)] ${MATRIX_CELL_CLASS}`}\n >\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <span className=\"type-label ds:text-[color:var(--foreground)]\">\n {parameterLabel(row.def, t)}\n </span>\n <span className=\"type-meta ds:text-[color:var(--muted-foreground)]\">\n {row.def.unit}\n {rangeText ? (\n <>\n {' · '}\n {rangeText}\n </>\n ) : null}\n </span>\n {row.target != null ? (\n <span className=\"type-meta ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.grid.target', {\n value: formatValue(row.target, row.def.precision, locale),\n unit: row.def.unit ?? '',\n })}\n </span>\n ) : null}\n </div>\n </th>\n ),\n cells: valueCells,\n trend: (\n <td className={`${MATRIX_TREND_COLUMN_CLASS} ${MATRIX_CELL_CLASS}`}>\n <TrendSparkline\n series={row.series}\n def={row.def}\n t={t}\n annotations={annotations}\n onSelectAnnotation={onSelectAnnotation}\n />\n </td>\n ),\n });\n });\n\n // A practice can configure its parameter list down to nothing. A table of\n // headers with no rows is a blank box, not a grid — say what is missing.\n if (rows.length === 0) {\n return (\n <div\n className=\"ds:w-full\"\n data-testid=\"anamnesis-evolution-no-parameters\"\n >\n <EmptyState\n variant=\"first-use\"\n size=\"sm\"\n title={t('anamnesis.empty.noParameters.title')}\n description={t('anamnesis.empty.noParameters.description')}\n />\n </div>\n );\n }\n\n const visitHeaders = columns.map((column) => (\n <MatrixVisitHeader\n key={column.key}\n column={column}\n t={t}\n editable={\n editable &&\n column.visit.id === editableId &&\n !isBaselineVisit(column.visit)\n }\n defaultOpenNoteVisitId={defaultOpenNoteVisitId}\n onOpenNote={onOpenNote}\n mergedFrom={isBaselineVisit(column.visit) ? baselineSources : undefined}\n />\n ));\n\n return (\n <AnamnesisMatrix\n captionId={captionId}\n caption={caption ?? t('anamnesis.grid.caption')}\n identityLabel={t('anamnesis.grid.parameter')}\n trendLabel={t('anamnesis.grid.trend')}\n trendTestId=\"anamnesis-grid-trend\"\n visitHeaders={visitHeaders}\n rows={renderedRows}\n framed={framed}\n />\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — visits grouped by source (one table per module) */\n/* */\n/* In the platform a visit is one interview of one anamnesis MODULE, and */\n/* modules ask different questions: a pre-visit questionnaire asks how */\n/* much water the patient drinks, a blood-test module asks for glucose. */\n/* Values from different modules cannot share a column set — one grid */\n/* over every visit shows dashes wherever a module never asked, and */\n/* compares numbers that were never meant to sit side by side. */\n/* */\n/* This groups a record's visits by `sourceLabel` so the trend can draw */\n/* one table per module, each holding only that module's visits and only */\n/* the parameters that module ever measured. */\n/* */\n/* Pure: no i18n, no JSX, no React. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport { visitSortKey } from './anamnesis-baseline';\nimport { parameterValueAt } from './anamnesis-derive';\nimport type { NumericParameterDef, Visit } from './anamnesis-types';\n\n/** Key of the block holding visits with no `sourceLabel`. */\nexport const UNLABELLED_BLOCK_KEY = 'unlabelled';\n\n/** Key of the single block the un-partitioned surface renders. */\nexport const WHOLE_RECORD_BLOCK_KEY = 'record';\n\nexport interface SourceBlock {\n /** Stable key for React and for the selection union: `source:<label>`,\n * `unlabelled`, or `record` for the whole-record block. */\n key: string;\n /** The heading the block wears — a module name, or the unlabelled\n * fallback. Empty for the whole-record block. */\n label: string;\n /** This block's visits, in RECORD order (never re-sorted). */\n visits: Visit[];\n}\n\n/* --------------------------------- API ---------------------------------- */\n\n/** The single block the un-partitioned surface renders: every visit, no\n * label. Returns the INPUT ARRAY ITSELF so the caller can hand the original\n * record through untouched. */\nexport function wholeRecordBlock(visits: readonly Visit[]): SourceBlock {\n return { key: WHOLE_RECORD_BLOCK_KEY, label: '', visits: visits as Visit[] };\n}\n\n/** Group visits by `sourceLabel`, blocks ordered by their OLDEST visit.\n * `unlabelledLabel` is already translated by the caller — this module stays\n * i18n-free. Visits inside a block keep record order. */\nexport function partitionVisitsBySource(\n visits: readonly Visit[],\n unlabelledLabel: string,\n): SourceBlock[] {\n const blocks = new Map<string, SourceBlock>();\n for (const visit of visits) {\n const label = visit.sourceLabel?.trim() ?? '';\n const key = label === '' ? UNLABELLED_BLOCK_KEY : `source:${label}`;\n const block = blocks.get(key);\n if (block) {\n block.visits.push(visit);\n } else {\n blocks.set(key, {\n key,\n label: label === '' ? unlabelledLabel : label,\n visits: [visit],\n });\n }\n }\n // One key rule for the whole record, so the by-day / by-instant choice is\n // made once and block order never depends on the viewer's time zone.\n const sortKey = visitSortKey(visits);\n const oldest = (block: SourceBlock) =>\n Math.min(...block.visits.map((visit) => sortKey(visit.dateIso)));\n return [...blocks.values()].sort((a, b) => oldest(a) - oldest(b));\n}\n\n/** Parameters worth a row in a block: measured at least once in its visits,\n * or force-kept by the caller. Order follows `defs`. */\nexport function measuredParameters(\n visits: readonly Visit[],\n defs: readonly NumericParameterDef[],\n keep?: (def: NumericParameterDef) => boolean,\n): NumericParameterDef[] {\n return defs.filter(\n (def) =>\n keep?.(def) === true ||\n visits.some((visit) => parameterValueAt(visit, def) != null),\n );\n}\n\n/** Concatenate per-block reports in block order; first occurrence wins. */\nexport function unionShownVisitIds(\n reports: readonly (readonly string[])[],\n): string[] {\n const seen = new Set<string>();\n const union: string[] = [];\n for (const report of reports) {\n for (const id of report) {\n if (seen.has(id)) continue;\n seen.add(id);\n union.push(id);\n }\n }\n return union;\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — evolution section (the across-visits grid) */\n/* */\n/* The across-visits view, shared by compile mode (editable newest column) */\n/* and read-only mode (no edit affordances). */\n/* */\n/* The comparison IS the grid: every visit is a column on arrival, */\n/* un-ticking a visit in the picker removes its column, and the delta */\n/* between two adjacent shown columns is always drawn. There is no */\n/* separate compare mode. */\n/* */\n/* The section renders ONE OR MORE BLOCKS. By default there is exactly one */\n/* block holding every visit. With `partitionBySource` the record's visits */\n/* are grouped by module (`sourceLabel`) and each module gets its own */\n/* block — its own picker, baseline and event marks — so values two */\n/* modules never asked for in the same interview are not laid out as if */\n/* they had been. The empty state (no visit at all) belongs to the */\n/* section, not to a block: a block always holds at least one visit. */\n/* */\n/* FIXED VERTICAL ORDER inside a block — four slots, nothing else inserted: */\n/* 0. Block heading — only when partitioned by source; names the */\n/* module the table below belongs to */\n/* 1. Toolbar — one wrapping row: the visit menu (one button */\n/* opening checkbox items) and its readout, then */\n/* the host's export control at the inline end */\n/* (`exportSlot`) */\n/* 2. Event bar — one toggle per dated event; picking one drops a */\n/* reference line down every sparkline below it. */\n/* Directly above the grid because that is what it */\n/* annotates; nothing picked on arrival */\n/* 3. Grid — the primary read; never moves, never collapses. */\n/* Its leftmost column may be the MERGED first */\n/* visit (anamnesis-baseline.ts), derived here and */\n/* never stored on the record */\n/* */\n/* Under `partitionBySource` the export control sits ONCE above the blocks */\n/* rather than inside any of them: a file of the whole trend must not be */\n/* owned by one module's region. A host that mounts the trend on a bare */\n/* surface asks for `cardBlocks`, and each block then wears its OWN */\n/* elevated card — stacked loose in one surface the modules ran together */\n/* and the reader lost which table belonged to which — with the card gap */\n/* dividing them, so no rule is drawn between blocks. A host that has */\n/* already carded the trend leaves the flag off rather than nesting cards. */\n/* -------------------------------------------------------------------- */\n\nimport {\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport type { TFunction } from 'i18next';\nimport { ChevronDown } from 'lucide-react';\nimport { Button } from '../../components/button';\nimport { Card } from '../../components/card';\nimport { DropdownMenu } from '../../components/dropdown-menu';\nimport { EmptyState } from '../../components/empty-state';\nimport { BASELINE_VISIT_ID, resolveBaseline } from './anamnesis-baseline';\nimport {\n allParametersIncludingArchived,\n configuredParameters,\n type PracticeAnamnesisConfig,\n} from './anamnesis-config';\nimport { AnamnesisEventBar } from './anamnesis-event-bar';\nimport { eventAnnotations, eventMarks } from './anamnesis-events';\nimport { visitDateLabel, visitOptionLabel } from './anamnesis-format';\nimport { hasVisitNotes } from './anamnesis-visit-note';\nimport { AnamnesisEvolutionGrid } from './anamnesis-evolution-grid';\nimport {\n measuredParameters,\n partitionVisitsBySource,\n unionShownVisitIds,\n wholeRecordBlock,\n} from './anamnesis-source-blocks';\nimport { visitPickerIsUseful, windowVisits } from './anamnesis-window';\nimport type {\n AnamnesisRecord,\n NumericParameterDef,\n OpenAnamnesisNote,\n Visit,\n} from './anamnesis-types';\n\n/* -------------------------------- Props --------------------------------- */\n\nexport interface AnamnesisEvolutionProps {\n record: AnamnesisRecord;\n t: TFunction;\n editable?: boolean;\n onCellChange?: (\n visit: Visit,\n def: NumericParameterDef,\n value: number | null,\n ) => void;\n /** Draw the grid's own border/surface. `false` when this sits inside a card. */\n framed?: boolean;\n /** The practice's configured vocabulary. Omitted = the kit-seeded default. */\n config?: PracticeAnamnesisConfig;\n /** One table per anamnesis type: visits grouped by `sourceLabel`, each\n * group with its own header, picker and matrix. Default false — every\n * visit in one grid, as before. */\n partitionBySource?: boolean;\n /** Give each per-module block its own elevated card. The HOST decides,\n * because only the host knows what surface the trend sits on: a surface\n * that already cards the trend would otherwise nest a card in a card.\n * Only read under `partitionBySource` — the single whole-record block is\n * never carded here. */\n cardBlocks?: boolean;\n /** Mount with this visit selection instead of every visit. Demo/story hook\n * only — Chromatic skips play functions, so a click-narrowed grid is never\n * snapshotted. Under `partitionBySource` each block keeps the ids it holds\n * and ignores the rest. */\n defaultVisitIds?: readonly string[];\n /** Mount with these events already drawn. Demo/story hook only — the\n * arrival state picks none, and Chromatic skips play functions. */\n defaultEventIds?: readonly string[];\n /** The picker's live selection, whenever it changes (and once on mount).\n * A host's export control needs to know which visit columns are on screen\n * — the file must be the view that was asked for. Under\n * `partitionBySource` it is the union of every block's columns. */\n onVisitSelectionChange?: (visitIds: readonly string[]) => void;\n /** The host's side panel. Wired ⇒ a visit's note trigger routes there\n * instead of opening a popover, and turning an event chip on navigates the\n * panel to that event. Omitted ⇒ the note opens in place and the chip only\n * draws its line, which is all a standalone surface can do. */\n onOpenNote?: OpenAnamnesisNote;\n /** Rendered at the inline end of the trend's toolbar row — the host's\n * export control. Under `partitionBySource` it sits above the blocks, once,\n * for the whole trend. */\n exportSlot?: ReactNode;\n}\n\n/* ------------------------------- Section -------------------------------- */\n\nexport function AnamnesisEvolution({\n record,\n t,\n editable = false,\n config,\n partitionBySource = false,\n cardBlocks = false,\n onVisitSelectionChange,\n exportSlot,\n ...blockProps\n}: AnamnesisEvolutionProps) {\n // Compile mode writes to the record's newest visit — decided on the REAL\n // record and kept out of the merge: a new module's first interview is the\n // newest visit, and folding it would hand the inputs to an older one.\n const editableVisitId = editable\n ? record.visits[record.visits.length - 1]?.id\n : undefined;\n // History surface: archived parameters stay, so a value recorded under a\n // since-archived parameter still renders.\n const allDefs = useMemo(\n () => allParametersIncludingArchived(config),\n [config],\n );\n // ...but capture follows the LIVE list: an archived parameter keeps its\n // history and loses its input.\n const capturableKeys = useMemo(\n () => new Set(configuredParameters(config).map((d) => d.key)),\n [config],\n );\n\n const unlabelled = t('anamnesis.grid.unlabelledSource');\n const blocks = useMemo(\n () =>\n partitionBySource\n ? partitionVisitsBySource(record.visits, unlabelled)\n : [wholeRecordBlock(record.visits)],\n [partitionBySource, record.visits, unlabelled],\n );\n const views = useMemo(\n () =>\n blocks.map((block) => {\n // A module never asked for a parameter nobody measured in it, so the\n // row would be dashes only. The block being compiled keeps every\n // capturable input regardless: an empty row is where the value goes.\n const compiling =\n editableVisitId != null &&\n block.visits.some((visit) => visit.id === editableVisitId);\n return {\n block,\n // Same reference when nothing was partitioned, so downstream memos\n // keep their identity.\n record:\n block.visits === record.visits\n ? record\n : { ...record, visits: block.visits },\n defs: partitionBySource\n ? measuredParameters(\n block.visits,\n allDefs,\n compiling\n ? (def) => capturableKeys.has(def.key) && !def.computed\n : undefined,\n )\n : allDefs,\n };\n }),\n [\n blocks,\n record,\n partitionBySource,\n allDefs,\n editableVisitId,\n capturableKeys,\n ],\n );\n\n // A ref, not state: each block's effect re-fires when its callback changes\n // identity, so a setState here would re-render, mint new closures and loop.\n // Only live blocks count — a swapped record leaves stale keys behind.\n const shownByBlock = useRef(new Map<string, readonly string[]>());\n const reportBlock = useCallback(\n (key: string, ids: readonly string[]) => {\n shownByBlock.current.set(key, ids);\n onVisitSelectionChange?.(\n unionShownVisitIds(\n blocks.map((block) => shownByBlock.current.get(block.key) ?? []),\n ),\n );\n },\n [blocks, onVisitSelectionChange],\n );\n const reporters = useMemo(\n () =>\n new Map(\n blocks.map((block) => [\n block.key,\n (ids: readonly string[]) => reportBlock(block.key, ids),\n ]),\n ),\n [blocks, reportBlock],\n );\n\n /* ---- SLOT 0 — no visits: nothing to plot, nothing to compare ---- */\n if (record.visits.length === 0) {\n return (\n <div className=\"ds:w-full\" data-testid=\"anamnesis-evolution-empty\">\n <EmptyState\n variant=\"first-use\"\n size=\"sm\"\n title={t('anamnesis.empty.noVisits.title')}\n description={t('anamnesis.empty.noVisits.description')}\n />\n </div>\n );\n }\n\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]\">\n {/* One export control for the whole trend. Partitioned blocks are\n module regions, and a file of everything must not sit inside one. */}\n {partitionBySource && exportSlot ? (\n <div\n data-testid=\"anamnesis-evolution-actions\"\n className=\"ds:flex ds:justify-end\"\n >\n {exportSlot}\n </div>\n ) : null}\n {views.map(({ block, record: blockRecord, defs }) => (\n <EvolutionBlock\n key={block.key}\n {...blockProps}\n record={blockRecord}\n defs={defs}\n t={t}\n editable={editable}\n editableVisitId={editableVisitId}\n capturableKeys={capturableKeys}\n heading={\n partitionBySource\n ? { label: block.label, count: block.visits.length }\n : undefined\n }\n groupBanners={!partitionBySource}\n carded={partitionBySource && cardBlocks}\n onVisitSelectionChange={reporters.get(block.key)}\n toolbarEnd={partitionBySource ? undefined : exportSlot}\n />\n ))}\n </div>\n );\n}\n\n/* ------------------------------- Host hook ------------------------------ */\n\n/** Mirror of the trend's shown columns for a host's export control. Bails\n * on an identical set: the child reports on every mount, and a fresh array\n * each time would re-render the host. */\nexport function useShownVisitIds(): [\n readonly string[],\n (ids: readonly string[]) => void,\n] {\n const [ids, setIds] = useState<readonly string[]>([]);\n const track = useCallback((next: readonly string[]) => {\n setIds((prev) =>\n prev.length === next.length && prev.every((id, i) => id === next[i])\n ? prev\n : [...next],\n );\n }, []);\n return [ids, track];\n}\n\n/* -------------------------------- Block --------------------------------- */\n\ninterface EvolutionBlockProps extends Omit<\n AnamnesisEvolutionProps,\n 'partitionBySource' | 'cardBlocks' | 'config' | 'exportSlot'\n> {\n /** The rows this block draws — already narrowed by the section. */\n defs: NumericParameterDef[];\n capturableKeys: ReadonlySet<string>;\n /** Decided by the section on the REAL record, never on a block's slice. */\n editableVisitId?: string;\n /** The module this block belongs to. Omitted = the block is the record. */\n heading?: { label: string; count: number };\n /** Parameter-group banner rows inside the grid. Off when the heading\n * already names the module the table belongs to. */\n groupBanners: boolean;\n /** Give the block its own elevated card. On per module when the host asked\n * for it; off for the single whole-record block, which is already whatever\n * surface the host put it on. */\n carded: boolean;\n /** The section's export control, when this block's toolbar is to hold it. */\n toolbarEnd?: ReactNode;\n}\n\nfunction EvolutionBlock({\n record,\n t,\n defs,\n capturableKeys,\n editable = false,\n editableVisitId,\n onCellChange,\n framed = true,\n heading,\n groupBanners,\n carded,\n defaultVisitIds,\n defaultEventIds,\n onVisitSelectionChange,\n onOpenNote,\n toolbarEnd,\n}: EvolutionBlockProps) {\n // Several modules each open with their own first interview; the reader\n // wants ONE baseline column, so those first visits fold into a synthetic one.\n const merge = useMemo(\n () => resolveBaseline(record.visits, { keepId: editableVisitId }),\n [record.visits, editableVisitId],\n );\n const { visits, pickable, baseline } = merge;\n // The record every derivation reads. Same reference when nothing merged.\n const view = useMemo<AnamnesisRecord>(\n () => (baseline ? { ...record, visits } : record),\n [record, baseline, visits],\n );\n const pinnedIds = useMemo(\n () => (baseline ? [BASELINE_VISIT_ID] : []),\n [baseline],\n );\n const headingId = useId();\n const readoutId = useId();\n const [refusalNote, setRefusalNote] = useState('');\n\n /* ---- Visit picker: which columns render (never which maths run) ---- */\n // Every visit on arrival — the grid is the comparison. The baseline is\n // pinned, never picked, so it is not part of the selection.\n const [pickedVisitIds, setPickedVisitIds] = useState<string[]>(() =>\n (defaultVisitIds ? [...defaultVisitIds] : pickable.map((v) => v.id)).filter(\n (id) => id !== BASELINE_VISIT_ID,\n ),\n );\n const pickerUseful = visitPickerIsUseful(pickable);\n // A host that swaps the record leaves the state holding ids this one does\n // not have. Dropping them can empty the selection, which would render a grid\n // with no visit column at all — fall back to every visit rather than to\n // nothing. Same floor the picker enforces on deselection. A baseline-only\n // record has nothing to pick, and stays empty rather than looping back.\n const selectedVisitIds = useMemo(() => {\n const live = pickedVisitIds.filter((id) =>\n pickable.some((v) => v.id === id),\n );\n if (live.length > 0 || pickable.length === 0) return live;\n return pickable.map((v) => v.id);\n }, [pickedVisitIds, pickable]);\n\n const visitWindow = useMemo(\n () => windowVisits(visits, selectedVisitIds, { alwaysShowIds: pinnedIds }),\n [visits, selectedVisitIds, pinnedIds],\n );\n\n // Reported, never owned: the host only mirrors what the grid draws. The\n // synthetic column expands to the real visits it merges: the host and the\n // export only know ids that exist on the record.\n const shownVisitIds = useMemo(\n () =>\n visitWindow.columns.flatMap((column) =>\n column.visit.id === BASELINE_VISIT_ID\n ? merge.sources.map((source) => source.id)\n : [column.visit.id],\n ),\n [visitWindow, merge],\n );\n useEffect(() => {\n onVisitSelectionChange?.(shownVisitIds);\n }, [shownVisitIds, onVisitSelectionChange]);\n\n // Ordinals count from the baseline's \"1.\".\n const visitItems = useMemo(() => {\n const offset = baseline ? 1 : 0;\n return pickable.map((visit, index) => ({\n id: visit.id,\n label: visitOptionLabel(visit, index + offset, t, hasVisitNotes(visit)),\n }));\n }, [pickable, baseline, t]);\n const allShown = selectedVisitIds.length === pickable.length;\n const triggerText = t('anamnesis.window.pickerTrigger', {\n shown: visitWindow.shownCount,\n total: visitWindow.totalCount,\n });\n\n // The floor is a REFUSAL, not a disabled row: the last shown visit stays\n // tickable so the reader hears why nothing changed.\n const refuseFloor = () => setRefusalNote(t('anamnesis.window.minimum'));\n // Built on the live set, not the raw state, so a stale id from a swapped\n // record cannot resurrect.\n const setVisitShown = (visitId: string, shown: boolean) => {\n if (!shown && selectedVisitIds.length === 1) return refuseFloor();\n setRefusalNote('');\n setPickedVisitIds(\n shown\n ? [...selectedVisitIds, visitId]\n : selectedVisitIds.filter((id) => id !== visitId),\n );\n };\n // An action, not a toggle: a checkbox row that can never be un-ticked\n // exposes a state nobody can set (WCAG 4.1.2).\n const selectAllVisits = () => {\n setRefusalNote('');\n setPickedVisitIds(pickable.map((visit) => visit.id));\n };\n\n const windowReadout = useMemo(() => {\n const from = visitWindow.firstIso\n ? visitDateLabel(visitWindow.firstIso, t)\n : '';\n const to = visitWindow.lastIso\n ? visitDateLabel(visitWindow.lastIso, t)\n : '';\n const shown =\n visitWindow.hiddenCount > 0\n ? t('anamnesis.window.showing', {\n shown: visitWindow.shownCount,\n total: visitWindow.totalCount,\n from,\n to,\n })\n : t('anamnesis.window.showingAll', {\n total: visitWindow.totalCount,\n from,\n to,\n });\n // Under a per-module block the readout names the module, so N pickers\n // do not share one description.\n const parts = heading ? [heading.label, shown] : [shown];\n // Said only where it applies: at one visit the next removal is the one the\n // picker refuses, and silence there reads as a broken control.\n if (selectedVisitIds.length === 1)\n parts.push(t('anamnesis.window.minimum'));\n return parts.join(' · ');\n }, [visitWindow, selectedVisitIds, t, heading]);\n\n /* ---- Events: one shared x domain, one line per picked event ---- */\n // Positions come from the block's visit span, NOT from any row's point\n // count and NOT from the visit selection — the sparklines plot the whole\n // block, so windowing columns must not move a marker.\n const marks = useMemo(\n () => eventMarks(record.events, visits),\n [record.events, visits],\n );\n const [pickedEventIds, setPickedEventIds] = useState<string[]>(() =>\n defaultEventIds ? [...defaultEventIds] : [],\n );\n // A host that swaps the record leaves ids this one cannot draw. Nothing\n // falls back here: an unpicked event is the arrival state, so dropping a\n // dead id lands on a state the reader already understands.\n const activeEventIds = useMemo(() => {\n const drawable = new Set(marks.map((mark) => mark.event.id));\n return new Set(pickedEventIds.filter((id) => drawable.has(id)));\n }, [pickedEventIds, marks]);\n\n const annotations = useMemo(\n () => eventAnnotations(marks, activeEventIds, t),\n [marks, activeEventIds, t],\n );\n\n const toggleEvent = (eventId: string) =>\n setPickedEventIds((current) =>\n current.includes(eventId)\n ? current.filter((id) => id !== eventId)\n : [...current, eventId],\n );\n\n // Pressing a drawn line is the SECOND half of pressing its chip, never the\n // first: the line only exists because the chip is already on, so the press\n // means \"what was this?\", not \"toggle it\". It therefore only routes the\n // panel — and only where a host wired one, which is also the only case where\n // it becomes pressable at all. No host panel, no pointer affordance: an\n // interactive-looking line that does nothing is worse than a drawn one.\n const selectAnnotation = useMemo(\n () =>\n onOpenNote\n ? (eventId: string) => onOpenNote({ kind: 'event', eventId })\n : undefined,\n [onOpenNote],\n );\n\n const block = (\n <div\n data-testid=\"anamnesis-evolution-block\"\n role={heading ? 'region' : undefined}\n aria-labelledby={heading ? headingId : undefined}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n {/* SLOT 0 — block heading. The module is the grouping, which is why the\n grid below draws no parameter-group banners of its own. */}\n {heading ? (\n <div\n data-testid=\"anamnesis-evolution-block-header\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\"\n >\n <h3\n id={headingId}\n className=\"type-title-item ds:m-0 ds:text-[color:var(--foreground)]\"\n >\n {heading.label}\n </h3>\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.grid.blockVisits', { count: heading.count })}\n </p>\n </div>\n ) : null}\n\n {/* SLOT 1 — toolbar. One wrapping row; rendered only when it has a\n control to hold, so a single-visit record shows no empty bar. */}\n {pickerUseful || toolbarEnd != null ? (\n <div\n data-testid=\"anamnesis-evolution-toolbar\"\n className=\"ds:flex ds:flex-wrap ds:items-start ds:gap-[var(--spacing-md)]\"\n >\n {pickerUseful ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n {/* Non-modal: the host page runs its own pointer/focus\n handling, as its other kit menus do. */}\n <DropdownMenu.Root modal={false}>\n <DropdownMenu.Trigger asChild>\n <Button\n type=\"button\"\n intent=\"outline\"\n size=\"sm\"\n /* The column stretches its children, so without this the\n trigger grew to the readout's width — 549px of button\n for a five-word label. The readout stays stretched. */\n className=\"ds:w-fit\"\n endIcon={<ChevronDown aria-hidden=\"true\" />}\n /* WCAG 2.5.3: the name OPENS with the visible text, then\n says what the control is. */\n aria-label={`${triggerText} · ${t('anamnesis.window.label')}`}\n /* The readout already opens with the module name per\n block, so the heading is not read twice. */\n aria-describedby={readoutId}\n data-testid=\"anamnesis-window-picker\"\n >\n {triggerText}\n </Button>\n </DropdownMenu.Trigger>\n {/* No clear-all: the grid needs at least one visit column, so\n an affordance that empties the selection would be a control\n whose effect is refused. Ticking keeps the menu open. */}\n <DropdownMenu.Content align=\"start\">\n <DropdownMenu.Label>\n {t('anamnesis.window.label')}\n </DropdownMenu.Label>\n <DropdownMenu.Item\n disabled={allShown}\n onSelect={(event) => {\n event.preventDefault();\n selectAllVisits();\n }}\n >\n {t('anamnesis.window.selectAll')}\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n {visitItems.map((item) => (\n <DropdownMenu.CheckboxItem\n key={item.id}\n checked={selectedVisitIds.includes(item.id)}\n onCheckedChange={(checked) =>\n setVisitShown(item.id, checked)\n }\n onSelect={(event) => event.preventDefault()}\n >\n {item.label}\n </DropdownMenu.CheckboxItem>\n ))}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n <p\n id={readoutId}\n data-testid=\"anamnesis-window-readout\"\n className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\"\n >\n {windowReadout}\n </p>\n {/* The floor is enforced by REFUSING the change, and a\n description never re-read explains nothing to a reader who\n cannot see it. */}\n <span\n role=\"status\"\n data-testid=\"anamnesis-window-floor\"\n className=\"ds:sr-only\"\n >\n {refusalNote}\n </span>\n </div>\n ) : null}\n\n {toolbarEnd ? <div className=\"ds:ms-auto\">{toolbarEnd}</div> : null}\n </div>\n ) : null}\n\n {/* SLOT 2 — events. Renders nothing when the record has none that fall\n inside the plotted span. */}\n <AnamnesisEventBar\n marks={marks}\n activeIds={activeEventIds}\n onToggle={toggleEvent}\n t={t}\n />\n\n {/* SLOT 3 — the primary read. */}\n <AnamnesisEvolutionGrid\n record={view}\n defs={defs}\n t={t}\n editable={editable}\n editableVisitId={editableVisitId}\n onCellChange={onCellChange}\n /* The card is the frame — a bordered table inside it is a box in a box. */\n framed={carded ? false : framed}\n visitColumns={visitWindow.columns}\n capturableKeys={capturableKeys}\n annotations={annotations}\n onSelectAnnotation={selectAnnotation}\n onOpenNote={onOpenNote}\n baselineSources={baseline ? merge.sources : undefined}\n groupBanners={groupBanners}\n caption={\n heading\n ? t('anamnesis.grid.captionInModule', { module: heading.label })\n : undefined\n }\n />\n </div>\n );\n\n return carded ? (\n <Card variant=\"elevated\">\n <Card.Body>{block}</Card.Body>\n </Card>\n ) : (\n block\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — patient-copy boundary */\n/* */\n/* ONE table answering one question: which audience may see a concept. */\n/* Reason codes, the export audience matrix, the read-only render and the */\n/* AI framing all resolve here — there is no second mechanism, no */\n/* `canPatientSee` boolean and no `audience` field on a domain type. */\n/* */\n/* THIS IS DOCUMENTATION PLUS A RESOLVER. It enforces NOTHING at runtime */\n/* and is NOT a security boundary — the real guarantee is a server-side */\n/* check on the document-generation and portal paths. Later stages ADD */\n/* ROWS; they never edit an existing row and never change the shape. */\n/* */\n/* Every row is provisional: our judgement, not the customer's. None of it */\n/* has been signed off. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\n/** Who a concept may be disclosed to. `clinician` is implicit on every row. */\nexport type DisclosureAudience = 'clinician' | 'patient' | 'external';\n\nexport interface DisclosureRule {\n /** Stable concept id — never a UI label, never a data-model field path. */\n id: string;\n /** Where the concept is captured or rendered. */\n surface: 'intake' | 'compile' | 'evolution' | 'readOnly' | 'export';\n /** Audiences allowed to see it. Always includes 'clinician'. */\n audiences: readonly DisclosureAudience[];\n /** One English sentence, for the customer sign-off walkthrough. */\n rationale: string;\n /** 'provisional' = our judgement, not the customer's. */\n status: 'provisional' | 'signedOff';\n}\n\nconst CLINICIAN_ONLY: readonly DisclosureAudience[] = ['clinician'];\nconst CLINICIAN_AND_PATIENT: readonly DisclosureAudience[] = [\n 'clinician',\n 'patient',\n];\n\nexport const DISCLOSURE_RULES: readonly DisclosureRule[] = [\n {\n id: 'patient.identity',\n surface: 'intake',\n audiences: CLINICIAN_AND_PATIENT,\n rationale: 'The patient supplied their own identifying details.',\n status: 'provisional',\n },\n {\n id: 'visit.date',\n surface: 'evolution',\n audiences: CLINICIAN_AND_PATIENT,\n rationale: 'The patient attended the visit and knows when it happened.',\n status: 'provisional',\n },\n {\n id: 'visit.type',\n surface: 'evolution',\n audiences: CLINICIAN_AND_PATIENT,\n rationale: 'First visit versus follow-up carries no clinical judgement.',\n status: 'provisional',\n },\n {\n id: 'visit.practitioner',\n surface: 'compile',\n audiences: CLINICIAN_AND_PATIENT,\n rationale: 'The patient met the practitioner.',\n status: 'provisional',\n },\n {\n id: 'visit.reason',\n surface: 'compile',\n audiences: CLINICIAN_AND_PATIENT,\n rationale:\n 'The human-readable reason for the visit is what the patient came for. Renders nothing today.',\n status: 'provisional',\n },\n {\n id: 'visit.reasonCode',\n surface: 'compile',\n audiences: CLINICIAN_ONLY,\n rationale:\n 'The coded reason is internal: the patient-facing artefact must be code-free. Separate row from visit.reason on purpose.',\n status: 'provisional',\n },\n {\n id: 'intake.answers',\n surface: 'intake',\n audiences: CLINICIAN_AND_PATIENT,\n rationale: 'The patient authored them.',\n status: 'provisional',\n },\n {\n id: 'anthropometrics.values',\n surface: 'compile',\n audiences: CLINICIAN_AND_PATIENT,\n rationale: 'Measured with the patient present, and motivating to track.',\n status: 'provisional',\n },\n {\n id: 'dietary.intake',\n surface: 'compile',\n audiences: CLINICIAN_AND_PATIENT,\n rationale:\n 'Estimated daily energy and protein describe what the patient eats — their own behaviour, and the thing the plan asks them to change.',\n status: 'provisional',\n },\n {\n id: 'derived.bmi',\n surface: 'compile',\n audiences: CLINICIAN_AND_PATIENT,\n rationale: 'Derived from weight and height, both already disclosed.',\n status: 'provisional',\n },\n {\n id: 'lab.values',\n surface: 'compile',\n audiences: CLINICIAN_ONLY,\n rationale:\n 'Our guess: raw lab values without interpretation can alarm. Needs customer sign-off.',\n status: 'provisional',\n },\n {\n id: 'pathology.codes',\n surface: 'compile',\n audiences: CLINICIAN_ONLY,\n rationale: 'Diagnostic codes are internal coding, not patient copy.',\n status: 'provisional',\n },\n {\n id: 'oncological.history',\n surface: 'compile',\n audiences: CLINICIAN_ONLY,\n rationale: 'Staging and treatment status need a clinician to deliver them.',\n status: 'provisional',\n },\n {\n id: 'therapy.entries',\n surface: 'compile',\n audiences: CLINICIAN_AND_PATIENT,\n rationale: 'The patient takes them and needs the list.',\n status: 'provisional',\n },\n {\n id: 'fmd.cycles',\n surface: 'compile',\n audiences: CLINICIAN_AND_PATIENT,\n rationale: 'The patient follows the programme.',\n status: 'provisional',\n },\n {\n id: 'notes.clinicalNotes',\n surface: 'compile',\n audiences: CLINICIAN_ONLY,\n rationale: \"The clinician's own working notes, not a patient letter.\",\n status: 'provisional',\n },\n {\n id: 'notes.nutritionalProposal',\n surface: 'compile',\n audiences: CLINICIAN_AND_PATIENT,\n rationale: 'This is the plan the patient is asked to follow.',\n status: 'provisional',\n },\n {\n id: 'annual.programme',\n surface: 'compile',\n audiences: CLINICIAN_AND_PATIENT,\n rationale: 'The patient accepts or declines it.',\n status: 'provisional',\n },\n {\n id: 'compare.diff',\n surface: 'evolution',\n audiences: CLINICIAN_ONLY,\n rationale:\n 'The diff spans lab values and codes; the strictest member governs the whole surface.',\n status: 'provisional',\n },\n {\n id: 'visit.note',\n surface: 'evolution',\n audiences: CLINICIAN_ONLY,\n rationale:\n 'Renders clinical notes and the nutritional proposal together; the strictest member governs.',\n status: 'provisional',\n },\n {\n id: 'intake.digest',\n surface: 'compile',\n audiences: CLINICIAN_AND_PATIENT,\n rationale: 'A summary of answers the patient wrote themselves.',\n status: 'provisional',\n },\n {\n id: 'symptom.observations',\n surface: 'compile',\n audiences: CLINICIAN_ONLY,\n rationale:\n 'Clinician-recorded observations, not patient self-report. Renders nothing today.',\n status: 'provisional',\n },\n {\n id: 'event.timeline',\n surface: 'evolution',\n audiences: CLINICIAN_ONLY,\n rationale:\n 'Clinical events carry third-party attribution — an event started by an outside professional names that professional.',\n status: 'provisional',\n },\n {\n id: 'export.workbook',\n surface: 'export',\n audiences: CLINICIAN_ONLY,\n rationale:\n 'Nothing in this track exports; the row reserves the boundary before anything does.',\n status: 'provisional',\n },\n {\n id: 'export.tabDocument',\n surface: 'export',\n audiences: CLINICIAN_AND_PATIENT,\n rationale:\n 'The per-tab export ENVELOPE — a title, a meta block and a list of tables. It carries no clinical content of its own: every table inside is gated on the concept it renders, so this row decides only whether a file may be produced at all. The whole-record workbook stays reserved by export.workbook.',\n status: 'provisional',\n },\n];\n\nconst RULE_BY_ID: ReadonlyMap<string, DisclosureRule> = new Map(\n DISCLOSURE_RULES.map((rule) => [rule.id, rule] as const),\n);\n\n/** The one resolver. Never inline this logic. An unknown id is NOT disclosed —\n * a concept with no row is a concept nobody has thought about yet. */\nexport function disclosedTo(id: string, audience: DisclosureAudience): boolean {\n const rule = RULE_BY_ID.get(id);\n if (!rule) return false;\n return rule.audiences.includes(audience);\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — export serialisation */\n/* */\n/* Three tabs, ONE tabular shape. Summary, Compile and Evolution each */\n/* serialise to an `ExportDocument` — a title, a meta block and a list of */\n/* `ExportTable`s — and every writer (CSV here, Excel here, PDF later) */\n/* consumes that one shape. Without it, three writers become three */\n/* different readings of the same screen. */\n/* */\n/* AUDIENCE IS A PARAMETER, NOT AN AFTERTHOUGHT. Every table and every */\n/* parameter row resolves through `disclosedTo()` in */\n/* `anamnesis-disclosure.ts`. A concept with no rule is NOT disclosed, so */\n/* a table nobody has classified stays out of a patient copy by default. */\n/* This module is not a security boundary — the real guarantee is a */\n/* server-side check on the document-generation path. */\n/* */\n/* PURE: no React, no DOM, no `document`. The writers return Blobs; the */\n/* download trigger lives in `anamnesis-export-download.ts`. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport type { TFunction } from 'i18next';\nimport {\n allParametersIncludingArchived,\n allSectionsIncludingArchived,\n configuredParameters,\n type PracticeAnamnesisConfig,\n pathologyLookup,\n} from './anamnesis-config';\nimport {\n buildParameterRows,\n isReadableDate,\n latestVisit,\n outOfRange,\n parameterValueAt,\n type ParameterRow,\n type RangeFlag,\n} from './anamnesis-derive';\nimport { type DisclosureAudience, disclosedTo } from './anamnesis-disclosure';\nimport {\n fieldVisible,\n formatIntakeAnswer,\n intakeFieldLabel,\n localeOf,\n parameterLabel,\n pathologyLabel,\n patientAgeLabel,\n sectionLabel,\n visitDateLabel,\n} from './anamnesis-format';\nimport {\n allVisitColumns,\n defaultSelectedVisitIds,\n type VisitColumn,\n windowVisits,\n} from './anamnesis-window';\nimport type {\n AnamnesisRecord,\n NumericParameterDef,\n Visit,\n} from './anamnesis-types';\n\n/* ------------------------- The one tabular shape ------------------------ */\n\n/** A cell. `null` is ABSENT and every writer renders it as an empty cell —\n * never the em dash the screen uses, which a spreadsheet cannot compute on. */\nexport type ExportValue = string | number | null;\n\nexport interface ExportColumn {\n /** Stable key — the Excel column key, never rendered. */\n key: string;\n /** Translated header text. */\n header: string;\n /** Numbers land in this column: right-aligned and number-formatted. */\n numeric?: boolean;\n /** Decimal places for numeric cells, when the whole column shares one. */\n precision?: number;\n}\n\nexport interface ExportRow {\n /** `section` is a group banner: cell 0 carries the label, the rest is blank. */\n kind?: 'data' | 'section';\n /** Aligned to `columns` by index; short rows are padded by the writer. */\n cells: ExportValue[];\n /** Decimal places for THIS row's numeric cells — a parameter row carries its\n * own precision, and the column cannot know it. Wins over the column. */\n precision?: number;\n}\n\nexport interface ExportTable {\n /** Stable id — the worksheet key and the PDF anchor. */\n id: string;\n title: string;\n columns: ExportColumn[];\n rows: ExportRow[];\n /** Rendered in place of the rows when there are none. */\n emptyText?: string;\n}\n\nexport interface ExportMetaEntry {\n label: string;\n value: string;\n}\n\n/** Which tab was exported. */\nexport type AnamnesisExportTab = 'summary' | 'compile' | 'evolution';\n\nexport interface ExportDocument {\n tab: AnamnesisExportTab;\n audience: DisclosureAudience;\n /** Filename without an extension — see `exportFileName`. */\n fileStem: string;\n title: string;\n /** Who the copy names, or `null` when identity is not disclosed to this\n * audience. Lifted out of `meta` so a writer can stamp every page with it. */\n patientName: string | null;\n /** The audience, translated — the \"Copy for\" value, in one place. */\n audienceLabel: string;\n meta: ExportMetaEntry[];\n tables: ExportTable[];\n /** Translated notes rendered under the tables. */\n footnotes: string[];\n /** Disclosure concept IDS held back from this document. Metadata for the UI\n * and the tests — writers never print it, because an id is not a value. */\n withheld: string[];\n /** App locale, resolved from `t`. Drives the CSV dialect. */\n locale?: string;\n}\n\n/* ------------------------------- Options -------------------------------- */\n\nexport interface AnamnesisExportOptions {\n record: AnamnesisRecord;\n /** Who the file is for. Filters every table through `disclosedTo`. */\n audience: DisclosureAudience;\n t: TFunction;\n config?: PracticeAnamnesisConfig;\n /** Generation instant. Defaults to now — pass one to keep a test stable. */\n generatedAtIso?: string;\n}\n\n/** `selected` exports the columns the picker is showing; `all` exports every\n * visit. Defaults to `selected`: exporting thirteen visits from a screen\n * showing three is a different document from the one that was asked for. */\nexport type EvolutionExportScope = 'selected' | 'all';\n\nexport interface EvolutionExportOptions extends AnamnesisExportOptions {\n /** The picker's current selection. Omitted = the picker's own default\n * (first visit + latest), never \"everything\". */\n selectedVisitIds?: Iterable<string>;\n scope?: EvolutionExportScope;\n}\n\n/* ---------------------------- Disclosure gate --------------------------- */\n\n/** The envelope's own rule. Denied ⇒ no file at all, and the reason is named. */\nconst DOCUMENT_CONCEPT = 'export.tabDocument';\n\n/** Collects what a build withheld, so the document can say so without naming\n * a single value. Local to one build call — nothing observable escapes. */\ninterface Gate {\n audience: DisclosureAudience;\n withheld: Set<string>;\n}\n\nfunction allow(gate: Gate, conceptId: string): boolean {\n if (disclosedTo(conceptId, gate.audience)) return true;\n gate.withheld.add(conceptId);\n return false;\n}\n\n/** A parameter's disclosure concept, from its DISPLAY group — not from\n * `parameterStorage`, which routes a practice-added anthropometric through the\n * `labs` array and would classify it as a lab value. */\nexport function parameterConcept(def: NumericParameterDef): string {\n if (def.key === 'bmi') return 'derived.bmi';\n switch (def.group) {\n case 'anthropometric':\n return 'anthropometrics.values';\n case 'dietary':\n return 'dietary.intake';\n case 'lab':\n return 'lab.values';\n }\n}\n\n/* ------------------------------- Helpers -------------------------------- */\n\nfunction sectionRow(label: string): ExportRow {\n return { kind: 'section', cells: [label] };\n}\n\nfunction textCell(value: string | undefined | null): ExportValue {\n const trimmed = value?.trim();\n return trimmed ? trimmed : null;\n}\n\nfunction referenceRangeText(\n def: NumericParameterDef,\n t: TFunction,\n): ExportValue {\n const range = def.referenceRange;\n if (!range) return null;\n if (range.min != null && range.max != null)\n return `${range.min}–${range.max}`;\n if (range.max != null)\n return t('anamnesis.range.atMost', { value: range.max });\n if (range.min != null)\n return t('anamnesis.range.atLeast', { value: range.min });\n return null;\n}\n\nfunction flagText(flag: RangeFlag, t: TFunction): ExportValue {\n if (flag === 'high') return t('anamnesis.range.aboveRange');\n if (flag === 'low') return t('anamnesis.range.belowRange');\n return null;\n}\n\n/** ASCII slug for a filename. A name with no Latin letters (Arabic, Japanese)\n * collapses to nothing, so the caller falls back to a neutral stem. */\nfunction slugify(value: string): string {\n return value\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nfunction calendarPart(iso: string | undefined): string | null {\n if (!iso) return null;\n const day = iso.slice(0, 10);\n return isReadableDate(day) ? day : null;\n}\n\n/** The audience rides in the STEM, not just in the document. Outside the app —\n * in a Downloads folder, on a USB stick, attached to an email — the filename is\n * the only thing left that says which of the two copies this is; without it the\n * second one is silently `… (1).pdf`. */\nfunction buildFileStem(\n tab: AnamnesisExportTab,\n record: AnamnesisRecord,\n referenceIso: string | null,\n namesDisclosed: boolean,\n audience: DisclosureAudience,\n): string {\n const name = namesDisclosed\n ? slugify(`${record.patient.lastName} ${record.patient.firstName}`)\n : '';\n const parts = [\n 'anamnesis',\n tab,\n audience,\n name || 'patient',\n referenceIso ?? '',\n ];\n return parts.filter(Boolean).join('-');\n}\n\nfunction audienceLabel(audience: DisclosureAudience, t: TFunction): string {\n return t(`anamnesis.export.audience.${audience}`);\n}\n\nfunction tabLabel(tab: AnamnesisExportTab, t: TFunction): string {\n return t(`anamnesis.export.tab.${tab}`);\n}\n\n/** The tab's name AS A DOCUMENT. \"Compile\" is a fine label on a tab strip and a\n * poor title for a clinical record — worse in Italian, where \"Compila\" reads as\n * an instruction to whoever is holding the sheet. Falls back to the control's\n * own tab name for a locale that carries only the evolution slice. */\nfunction docTabLabel(tab: AnamnesisExportTab, t: TFunction): string {\n return t(`anamnesis.export.docTab.${tab}`, {\n defaultValue: tabLabel(tab, t),\n });\n}\n\n/** The patient / generation meta every document carries. Identity is gated:\n * a copy that may not name the patient names nobody. */\nfunction baseMeta(\n record: AnamnesisRecord,\n gate: Gate,\n t: TFunction,\n generatedAtIso: string,\n): { meta: ExportMetaEntry[]; patientName: string | null } {\n const meta: ExportMetaEntry[] = [];\n const identity = allow(gate, 'patient.identity');\n const patientName = identity\n ? `${record.patient.firstName} ${record.patient.lastName}`.trim()\n : null;\n\n if (patientName) {\n meta.push({ label: t('anamnesis.header.name'), value: patientName });\n meta.push({\n label: t('anamnesis.header.dob'),\n value: visitDateLabel(record.patient.dateOfBirthIso, t),\n });\n meta.push({\n label: t('anamnesis.header.age'),\n value: patientAgeLabel(record, t),\n });\n }\n meta.push({\n label: t('anamnesis.export.generated'),\n value: visitDateLabel(generatedAtIso.slice(0, 10), t),\n });\n meta.push({\n label: t('anamnesis.export.audienceLabel'),\n value: audienceLabel(gate.audience, t),\n });\n return { meta, patientName };\n}\n\nfunction documentTitle(\n tab: AnamnesisExportTab,\n patientName: string | null,\n t: TFunction,\n): string {\n const tabText = docTabLabel(tab, t);\n return patientName\n ? t('anamnesis.export.docTitle', { tab: tabText, patient: patientName })\n : tabText;\n}\n\n/** The document produced when the envelope itself is not disclosed. Empty on\n * purpose: no tables, no meta, and the reason named in `withheld`. */\nfunction refusedDocument(\n tab: AnamnesisExportTab,\n audience: DisclosureAudience,\n t: TFunction,\n): ExportDocument {\n return {\n tab,\n audience,\n fileStem: `anamnesis-${tab}-${audience}`,\n title: docTabLabel(tab, t),\n patientName: null,\n audienceLabel: audienceLabel(audience, t),\n meta: [],\n tables: [],\n footnotes: [t('anamnesis.export.withheld')],\n withheld: [DOCUMENT_CONCEPT],\n locale: localeOf(t),\n };\n}\n\nfunction finish(\n document: Omit<\n ExportDocument,\n 'withheld' | 'footnotes' | 'locale' | 'audienceLabel'\n >,\n gate: Gate,\n t: TFunction,\n extraFootnotes: string[] = [],\n): ExportDocument {\n const withheld = [...gate.withheld].sort();\n const footnotes = [...extraFootnotes];\n if (withheld.length > 0) footnotes.push(t('anamnesis.export.withheld'));\n return {\n ...document,\n audienceLabel: audienceLabel(gate.audience, t),\n footnotes,\n withheld,\n locale: localeOf(t),\n };\n}\n\n/* ------------------------------- Summary -------------------------------- */\n\n/** The Summary tab: the patient's own questionnaire, one row per answered\n * question, grouped by section, with who authored each answer. */\nexport function buildSummaryExport(\n options: AnamnesisExportOptions,\n): ExportDocument {\n const { record, audience, t, config } = options;\n const generatedAtIso = options.generatedAtIso ?? new Date().toISOString();\n const gate: Gate = { audience, withheld: new Set() };\n\n if (!allow(gate, DOCUMENT_CONCEPT))\n return refusedDocument('summary', audience, t);\n\n const { meta, patientName } = baseMeta(record, gate, t, generatedAtIso);\n const tables: ExportTable[] = [];\n const footnotes: string[] = [];\n\n const intake = record.intake;\n if (allow(gate, 'intake.answers') && intake) {\n const rows: ExportRow[] = [];\n for (const section of allSectionsIncludingArchived(config)) {\n const answered = section.fields\n .filter((field) => fieldVisible(field, record.patient.sex))\n .filter((field) => intake.answers[field.key]);\n if (answered.length === 0) continue;\n rows.push(sectionRow(sectionLabel(section, t)));\n for (const field of answered) {\n const sourced = intake.answers[field.key];\n if (!sourced) continue;\n rows.push({\n cells: [\n intakeFieldLabel(field, t),\n textCell(formatIntakeAnswer(sourced.value, field, t)),\n t(`anamnesis.export.source.${sourced.origin}`),\n ],\n });\n }\n }\n tables.push({\n id: 'questionnaire',\n title: t('anamnesis.section.patientIntake'),\n columns: [\n { key: 'question', header: t('anamnesis.export.column.question') },\n { key: 'answer', header: t('anamnesis.export.column.answer') },\n { key: 'source', header: t('anamnesis.export.column.source') },\n ],\n rows,\n emptyText: t('anamnesis.summary.noAnswers'),\n });\n } else if (!intake) {\n footnotes.push(t('anamnesis.compile.noIntake'));\n }\n\n const referenceIso =\n calendarPart(intake?.submittedAtIso) ??\n calendarPart(latestVisit(record)?.dateIso) ??\n calendarPart(generatedAtIso);\n\n return finish(\n {\n tab: 'summary',\n audience,\n fileStem: buildFileStem(\n 'summary',\n record,\n referenceIso,\n !!patientName,\n audience,\n ),\n title: documentTitle('summary', patientName, t),\n patientName,\n meta,\n tables,\n },\n gate,\n t,\n footnotes,\n );\n}\n\n/* ------------------------------- Compile -------------------------------- */\n\nfunction measurementTable(\n id: string,\n title: string,\n defs: NumericParameterDef[],\n visit: Visit,\n gate: Gate,\n t: TFunction,\n withRange: boolean,\n): ExportTable | null {\n const rows: ExportRow[] = [];\n let anyAllowed = false;\n for (const def of defs) {\n if (!allow(gate, parameterConcept(def))) continue;\n anyAllowed = true;\n const value = parameterValueAt(visit, def);\n const cells: ExportValue[] = [\n parameterLabel(def, t),\n value,\n def.unit ?? null,\n ];\n if (withRange) {\n cells.push(referenceRangeText(def, t));\n cells.push(flagText(outOfRange(value, def.referenceRange), t));\n }\n rows.push({ cells, precision: def.precision });\n }\n if (!anyAllowed) return null;\n\n const columns: ExportColumn[] = [\n { key: 'parameter', header: t('anamnesis.grid.parameter') },\n { key: 'value', header: t('anamnesis.export.column.value'), numeric: true },\n { key: 'unit', header: t('anamnesis.export.column.unit') },\n ];\n if (withRange) {\n columns.push({\n key: 'referenceRange',\n header: t('anamnesis.export.column.referenceRange'),\n });\n columns.push({ key: 'flag', header: t('anamnesis.export.column.flag') });\n }\n return { id, title, columns, rows, emptyText: t('anamnesis.export.none') };\n}\n\nfunction fieldValueTable(\n id: string,\n title: string,\n rows: ExportRow[],\n t: TFunction,\n): ExportTable {\n return {\n id,\n title,\n columns: [\n { key: 'field', header: t('anamnesis.export.column.field') },\n { key: 'value', header: t('anamnesis.export.column.value') },\n ],\n rows,\n emptyText: t('anamnesis.export.none'),\n };\n}\n\n/** The Compile tab: the visit being recorded, block by block, in the order the\n * form presents them. Each block is gated on its own disclosure concept. */\nexport function buildCompileExport(\n options: AnamnesisExportOptions,\n): ExportDocument {\n const { record, audience, t, config } = options;\n const generatedAtIso = options.generatedAtIso ?? new Date().toISOString();\n const gate: Gate = { audience, withheld: new Set() };\n\n if (!allow(gate, DOCUMENT_CONCEPT))\n return refusedDocument('compile', audience, t);\n\n const { meta, patientName } = baseMeta(record, gate, t, generatedAtIso);\n const visit = latestVisit(record);\n const tables: ExportTable[] = [];\n const footnotes: string[] = [];\n\n if (!visit) {\n footnotes.push(t('anamnesis.export.none'));\n return finish(\n {\n tab: 'compile',\n audience,\n fileStem: buildFileStem(\n 'compile',\n record,\n calendarPart(generatedAtIso),\n !!patientName,\n audience,\n ),\n title: documentTitle('compile', patientName, t),\n patientName,\n meta,\n tables,\n },\n gate,\n t,\n footnotes,\n );\n }\n\n if (allow(gate, 'visit.date')) {\n meta.push({\n label: t('anamnesis.header.visitDate'),\n value: visitDateLabel(visit.dateIso, t),\n });\n }\n\n /* Visit details — each line its own concept, so a patient copy can carry the\n date and the practitioner without carrying anything else. */\n const visitRows: ExportRow[] = [];\n if (allow(gate, 'visit.type')) {\n visitRows.push({\n cells: [\n t('anamnesis.field.visitType.label'),\n t(`anamnesis.visitType.${visit.visitType}`),\n ],\n });\n }\n if (allow(gate, 'visit.date')) {\n visitRows.push({\n cells: [\n t('anamnesis.header.visitDate'),\n visitDateLabel(visit.dateIso, t),\n ],\n });\n }\n if (allow(gate, 'visit.practitioner') && visit.practitioner) {\n visitRows.push({\n cells: [\n t('anamnesis.field.practitioner.label'),\n textCell(visit.practitioner),\n ],\n });\n }\n if (visitRows.length > 0) {\n tables.push(\n fieldValueTable('visit', t('anamnesis.section.visitMeta'), visitRows, t),\n );\n }\n\n const anthro = measurementTable(\n 'anthropometrics',\n t('anamnesis.section.anthropometrics'),\n configuredParameters(config, 'anthropometric'),\n visit,\n gate,\n t,\n false,\n );\n if (anthro) tables.push(anthro);\n\n const dietary = measurementTable(\n 'dietary',\n t('anamnesis.section.dietary'),\n configuredParameters(config, 'dietary'),\n visit,\n gate,\n t,\n false,\n );\n if (dietary) tables.push(dietary);\n\n if (allow(gate, 'pathology.codes')) {\n const lookup = pathologyLookup(config);\n tables.push({\n id: 'pathologies',\n title: t('anamnesis.section.pathologies'),\n columns: [\n { key: 'code', header: t('anamnesis.export.column.code') },\n {\n key: 'description',\n header: t('anamnesis.export.column.description'),\n },\n ],\n rows: visit.pathologyCodes.map((code) => ({\n cells: [code, pathologyLabel(code, t, lookup[code])],\n })),\n emptyText: t('anamnesis.export.none'),\n });\n }\n\n if (allow(gate, 'oncological.history')) {\n const onc = visit.oncological;\n const rows: ExportRow[] = [];\n if (onc) {\n if (textCell(onc.tumourType))\n rows.push({\n cells: [\n t('anamnesis.field.tumourType.label'),\n textCell(onc.tumourType),\n ],\n });\n if (textCell(onc.stage))\n rows.push({\n cells: [t('anamnesis.field.stage.label'), textCell(onc.stage)],\n });\n if (onc.metastases) {\n const present = t(`anamnesis.common.${onc.metastases.present}`);\n const site = textCell(onc.metastases.site);\n rows.push({\n cells: [\n t('anamnesis.field.metastases.label'),\n site ? `${present} — ${site}` : present,\n ],\n });\n }\n if (textCell(onc.treatmentStatus))\n rows.push({\n cells: [\n t('anamnesis.field.treatmentStatus.label'),\n textCell(onc.treatmentStatus),\n ],\n });\n }\n tables.push(\n fieldValueTable(\n 'oncological',\n t('anamnesis.section.oncological'),\n rows,\n t,\n ),\n );\n }\n\n if (allow(gate, 'therapy.entries')) {\n tables.push({\n id: 'therapy',\n title: t('anamnesis.section.therapy'),\n columns: [\n { key: 'name', header: t('anamnesis.export.column.name') },\n { key: 'dose', header: t('anamnesis.export.column.dose') },\n { key: 'kind', header: t('anamnesis.export.column.kind') },\n ],\n rows: visit.therapy.map((entry) => ({\n cells: [\n textCell(entry.name),\n textCell(entry.dose),\n t(`anamnesis.medKind.${entry.kind}`),\n ],\n })),\n emptyText: t('anamnesis.compile.noTherapy'),\n });\n }\n\n const labs = measurementTable(\n 'labs',\n t('anamnesis.section.labs'),\n configuredParameters(config, 'lab'),\n visit,\n gate,\n t,\n true,\n );\n if (labs) tables.push(labs);\n\n if (allow(gate, 'fmd.cycles')) {\n tables.push({\n id: 'fmd',\n title: t('anamnesis.section.fmd'),\n columns: [\n { key: 'cycle', header: t('anamnesis.export.column.cycle') },\n { key: 'startDate', header: t('anamnesis.export.column.startDate') },\n { key: 'status', header: t('anamnesis.export.column.status') },\n { key: 'notes', header: t('anamnesis.export.column.notes') },\n ],\n rows: visit.fmdCycles.map((cycle) => ({\n cells: [\n t('anamnesis.compile.cycleNumber', { number: cycle.cycleNumber }),\n visitDateLabel(cycle.startDateIso, t),\n cycle.completed\n ? t('anamnesis.compile.cycleCompleted')\n : t('anamnesis.compile.cycleInProgress'),\n textCell(cycle.notes),\n ],\n })),\n emptyText: t('anamnesis.compile.noFmd'),\n });\n }\n\n if (allow(gate, 'annual.programme')) {\n const annual = visit.annualProgramme;\n const rows: ExportRow[] = [];\n if (annual) {\n const yesNo = (value: boolean) =>\n value ? t('anamnesis.common.yes') : t('anamnesis.common.no');\n rows.push({\n cells: [\n t('anamnesis.field.annualProposed.label'),\n yesNo(annual.proposed),\n ],\n });\n rows.push({\n cells: [\n t('anamnesis.field.annualAccepted.label'),\n yesNo(annual.accepted),\n ],\n });\n if (textCell(annual.declineReason))\n rows.push({\n cells: [\n t('anamnesis.field.annualDeclineReason.label'),\n textCell(annual.declineReason),\n ],\n });\n }\n tables.push(\n fieldValueTable('annual', t('anamnesis.section.annual'), rows, t),\n );\n }\n\n const noteRows: ExportRow[] = [];\n if (\n allow(gate, 'notes.nutritionalProposal') &&\n textCell(visit.nutritionalProposal)\n ) {\n noteRows.push({\n cells: [\n t('anamnesis.field.nutritionalProposal.label'),\n textCell(visit.nutritionalProposal),\n ],\n });\n }\n if (allow(gate, 'notes.clinicalNotes') && textCell(visit.clinicalNotes)) {\n noteRows.push({\n cells: [\n t('anamnesis.field.clinicalNotes.label'),\n textCell(visit.clinicalNotes),\n ],\n });\n }\n if (noteRows.length > 0) {\n tables.push({\n id: 'notes',\n title: t('anamnesis.section.proposal'),\n columns: [\n { key: 'note', header: t('anamnesis.export.column.note') },\n { key: 'text', header: t('anamnesis.export.column.text') },\n ],\n rows: noteRows,\n emptyText: t('anamnesis.export.none'),\n });\n }\n\n return finish(\n {\n tab: 'compile',\n audience,\n fileStem: buildFileStem(\n 'compile',\n record,\n calendarPart(visit.dateIso) ?? calendarPart(generatedAtIso),\n !!patientName,\n audience,\n ),\n title: documentTitle('compile', patientName, t),\n patientName,\n meta,\n tables,\n },\n gate,\n t,\n footnotes,\n );\n}\n\n/* ------------------------------ Evolution ------------------------------- */\n\nfunction outOfRangeText(\n row: ParameterRow,\n columns: readonly VisitColumn[],\n t: TFunction,\n): ExportValue {\n const flagged = columns\n .map((column) => {\n const flag = row.cells[column.index]?.outOfRange ?? null;\n if (!flag) return null;\n return t('anamnesis.export.flagged', {\n date: visitDateLabel(column.visit.dateIso, t),\n flag: flagText(flag, t),\n });\n })\n .filter((entry): entry is string => entry != null);\n if (flagged.length === 0) return null;\n return flagged.join(t('anamnesis.export.listSeparator'));\n}\n\n/** Change ACROSS THE SHOWN WINDOW — last shown value minus first shown value.\n * The grid draws a per-cell delta against the previous visit; a single column\n * in a file has to say which two figures it compares, so the header names the\n * two dates. On the default two-column selection the two readings coincide. */\nfunction windowChange(\n row: ParameterRow,\n columns: readonly VisitColumn[],\n): number | null {\n if (columns.length < 2) return null;\n const first = row.cells[columns[0].index]?.value ?? null;\n const last = row.cells[columns[columns.length - 1].index]?.value ?? null;\n if (first == null || last == null) return null;\n return last - first;\n}\n\n/** The Evolution tab: parameters as rows, the SHOWN visits as columns, plus\n * target, window change and which visits fell out of range. */\nexport function buildEvolutionExport(\n options: EvolutionExportOptions,\n): ExportDocument {\n const { record, audience, t, config } = options;\n const generatedAtIso = options.generatedAtIso ?? new Date().toISOString();\n const scope: EvolutionExportScope = options.scope ?? 'selected';\n const gate: Gate = { audience, withheld: new Set() };\n\n if (!allow(gate, DOCUMENT_CONCEPT))\n return refusedDocument('evolution', audience, t);\n\n const { meta, patientName } = baseMeta(record, gate, t, generatedAtIso);\n const tables: ExportTable[] = [];\n const footnotes: string[] = [];\n\n /* An EMPTY selection is not a selection. `?? default` alone lets a `[]` from\n a host that has not yet mirrored the picker through, and that yields a\n document with no matrix, no withheld concepts, and a menu line reading \"a\n patient copy leaves nothing out\" over a copy that dropped every lab. */\n const passed = options.selectedVisitIds\n ? [...options.selectedVisitIds]\n : null;\n const selectedIds =\n passed && passed.length > 0\n ? passed\n : defaultSelectedVisitIds(record.visits);\n const columns =\n scope === 'all'\n ? allVisitColumns(record.visits)\n : windowVisits(record.visits, selectedIds).columns;\n\n meta.push({\n label: t('anamnesis.export.visitsLabel'),\n value:\n scope === 'all'\n ? t('anamnesis.export.visitsAll', { total: record.visits.length })\n : t('anamnesis.export.visitsSelected', {\n shown: columns.length,\n total: record.visits.length,\n }),\n });\n\n /* The matrix is unreadable without dated columns, so the whole table hangs\n off `visit.date` rather than emitting columns nobody may name. */\n if (allow(gate, 'visit.date') && columns.length > 0) {\n const defs = allParametersIncludingArchived(config);\n const parameterRows = buildParameterRows(record, defs);\n const fromDate = visitDateLabel(columns[0].visit.dateIso, t);\n const toDate = visitDateLabel(columns[columns.length - 1].visit.dateIso, t);\n\n const tableColumns: ExportColumn[] = [\n { key: 'parameter', header: t('anamnesis.grid.parameter') },\n { key: 'unit', header: t('anamnesis.export.column.unit') },\n {\n key: 'referenceRange',\n header: t('anamnesis.export.column.referenceRange'),\n },\n ...columns.map((column) => ({\n key: `visit-${column.visit.id}`,\n header: visitDateLabel(column.visit.dateIso, t),\n numeric: true,\n })),\n {\n key: 'target',\n header: t('anamnesis.export.column.target'),\n numeric: true,\n },\n {\n key: 'change',\n header: t('anamnesis.export.column.change', {\n from: fromDate,\n to: toDate,\n }),\n numeric: true,\n },\n { key: 'outOfRange', header: t('anamnesis.export.column.outOfRange') },\n ];\n\n const rows: ExportRow[] = [];\n let lastGroup: string | null = null;\n for (const row of parameterRows) {\n if (!allow(gate, parameterConcept(row.def))) continue;\n if (row.def.group !== lastGroup) {\n lastGroup = row.def.group;\n rows.push(sectionRow(t(`anamnesis.group.${row.def.group}`)));\n }\n rows.push({\n precision: row.def.precision,\n cells: [\n parameterLabel(row.def, t),\n row.def.unit ?? null,\n referenceRangeText(row.def, t),\n ...columns.map((column) => row.cells[column.index]?.value ?? null),\n row.target,\n windowChange(row, columns),\n outOfRangeText(row, columns, t),\n ],\n });\n }\n\n tables.push({\n id: 'matrix',\n title: t('anamnesis.section.evolution'),\n columns: tableColumns,\n rows,\n emptyText: t('anamnesis.export.none'),\n });\n } else if (columns.length === 0) {\n footnotes.push(t('anamnesis.export.none'));\n }\n\n const referenceIso =\n calendarPart(columns[columns.length - 1]?.visit.dateIso) ??\n calendarPart(generatedAtIso);\n\n return finish(\n {\n tab: 'evolution',\n audience,\n fileStem: buildFileStem(\n 'evolution',\n record,\n referenceIso,\n !!patientName,\n audience,\n ),\n title: documentTitle('evolution', patientName, t),\n patientName,\n meta,\n tables,\n },\n gate,\n t,\n footnotes,\n );\n}\n\n/** One entry point for a tab id — the UI stage switches on the active tab. */\nexport function buildAnamnesisExport(\n tab: AnamnesisExportTab,\n options: EvolutionExportOptions,\n): ExportDocument {\n switch (tab) {\n case 'summary':\n return buildSummaryExport(options);\n case 'compile':\n return buildCompileExport(options);\n case 'evolution':\n return buildEvolutionExport(options);\n }\n}\n\n/* -------------------- What a copy holds and holds back ------------------- */\n\n/** A withheld concept's translated name. The id carries dots and i18next reads\n * a dot as a level, so the key flattens them — `lab.values` reads\n * `anamnesis.export.concept.lab_values`. An id with no key falls back to the\n * id rather than to a blank, so a rule nobody has named still shows up. */\nexport function conceptLabel(conceptId: string, t: TFunction): string {\n return t(`anamnesis.export.concept.${conceptId.replace(/\\./g, '_')}`, {\n defaultValue: conceptId,\n });\n}\n\nexport interface DocumentDisclosure {\n /** Table titles the document actually carries, in document order. */\n included: string[];\n /** Translated names of the concepts held back, alphabetical. */\n excluded: string[];\n}\n\n/** What this document gives the audience and what it holds back — the share\n * dialog's whole content, and the menu's exclusion line. Reads the built\n * document rather than re-deriving the rules, so the preview cannot disagree\n * with the file. */\nexport function documentDisclosure(\n document: ExportDocument,\n t: TFunction,\n): DocumentDisclosure {\n return {\n included: document.tables.map((table) => table.title),\n excluded: document.withheld\n .map((id) => conceptLabel(id, t))\n .sort((a, b) => a.localeCompare(b, document.locale)),\n };\n}\n\n/* --------------------------------- CSV ---------------------------------- */\n\nexport const CSV_MIME = 'text/csv;charset=utf-8';\nexport const XLSX_MIME =\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';\n\nexport interface CsvDialect {\n /** Field separator. `;` wherever the decimal mark is a comma. */\n delimiter: ',' | ';';\n decimal: '.' | ',';\n eol: string;\n /** Emit a UTF-8 BOM so Excel detects the encoding instead of guessing. */\n bom: boolean;\n}\n\n/** RFC 4180, and the line ending Excel expects on every platform. */\nconst CSV_EOL = '\\r\\n';\n\n/** A leading `=` `+` `-` `@` (or tab / CR) turns a text cell into a formula in\n * Excel and Sheets. Guarded on TEXT cells only — a numeric cell goes down the\n * number path, so `-12.5` is never mangled into `'-12.5`. */\nconst CSV_INJECTION = /^[=+\\-@\\t\\r]/;\n\nfunction decimalSeparatorFor(locale: string | undefined): '.' | ',' {\n if (!locale) return '.';\n try {\n const parts = new Intl.NumberFormat(locale, {\n useGrouping: false,\n }).formatToParts(1.5);\n return parts.find((part) => part.type === 'decimal')?.value === ','\n ? ','\n : '.';\n } catch {\n return '.';\n }\n}\n\n/** The CSV convention Excel expects for a locale. Italian (and every other\n * decimal-comma locale) gets `;` + `,`; English gets `,` + `.`. A locale whose\n * decimal mark is neither — Arabic's `٫` — takes the point convention, because\n * the numbers written here are Latin digits either way. */\nexport function csvDialectFor(locale?: string): CsvDialect {\n return decimalSeparatorFor(locale) === ','\n ? { delimiter: ';', decimal: ',', eol: CSV_EOL, bom: true }\n : { delimiter: ',', decimal: '.', eol: CSV_EOL, bom: true };\n}\n\nfunction formatCsvNumber(\n value: number,\n precision: number | undefined,\n dialect: CsvDialect,\n): string {\n if (!Number.isFinite(value)) return '';\n const text = precision == null ? String(value) : value.toFixed(precision);\n return dialect.decimal === ',' ? text.replace('.', ',') : text;\n}\n\nfunction escapeCsvText(raw: string, dialect: CsvDialect): string {\n const guarded = CSV_INJECTION.test(raw) ? `'${raw}` : raw;\n const mustQuote =\n guarded.includes(dialect.delimiter) ||\n guarded.includes('\"') ||\n guarded.includes('\\n') ||\n guarded.includes('\\r') ||\n guarded !== guarded.trim();\n return mustQuote ? `\"${guarded.replace(/\"/g, '\"\"')}\"` : guarded;\n}\n\n/** One cell, escaped. Exported for the tests that pin the escaping rules. */\nexport function csvCell(\n value: ExportValue,\n dialect: CsvDialect,\n precision?: number,\n): string {\n if (value == null) return '';\n if (typeof value === 'number')\n return formatCsvNumber(value, precision, dialect);\n return escapeCsvText(value, dialect);\n}\n\nfunction cellPrecision(\n row: ExportRow,\n column: ExportColumn | undefined,\n): number | undefined {\n return row.precision ?? column?.precision;\n}\n\n/** The document as one CSV. Tables run in order, each behind its own title\n * row and separated by a blank line — the report shape every spreadsheet\n * reader already understands. */\nexport function toCsv(\n document: ExportDocument,\n dialect: CsvDialect = csvDialectFor(document.locale),\n): string {\n const lines: string[] = [];\n const push = (fields: readonly string[]) =>\n lines.push(fields.join(dialect.delimiter));\n\n push([escapeCsvText(document.title, dialect)]);\n for (const entry of document.meta) {\n push([\n escapeCsvText(entry.label, dialect),\n escapeCsvText(entry.value, dialect),\n ]);\n }\n\n for (const table of document.tables) {\n lines.push('');\n push([escapeCsvText(table.title, dialect)]);\n push(table.columns.map((column) => escapeCsvText(column.header, dialect)));\n if (table.rows.length === 0 && table.emptyText) {\n push([escapeCsvText(table.emptyText, dialect)]);\n continue;\n }\n for (const row of table.rows) {\n if (row.kind === 'section') {\n push([csvCell(row.cells[0] ?? null, dialect)]);\n continue;\n }\n push(\n table.columns.map((column, index) =>\n csvCell(\n row.cells[index] ?? null,\n dialect,\n cellPrecision(row, column),\n ),\n ),\n );\n }\n }\n\n if (document.footnotes.length > 0) {\n lines.push('');\n for (const note of document.footnotes) push([escapeCsvText(note, dialect)]);\n }\n\n return lines.join(dialect.eol) + dialect.eol;\n}\n\nexport function toCsvBlob(\n document: ExportDocument,\n dialect: CsvDialect = csvDialectFor(document.locale),\n): Blob {\n const body = toCsv(document, dialect);\n return new Blob([dialect.bom ? `\\uFEFF${body}` : body], { type: CSV_MIME });\n}\n\n/* -------------------------------- Excel --------------------------------- */\n\ntype ExcelJsModule = typeof import('exceljs');\n\n/** Dynamic-imported so exceljs stays out of the bundle of a consumer who never\n * exports. Handles both the namespace and the CJS-interop default. */\nasync function loadExcelJs(): Promise<ExcelJsModule> {\n const module = await import('exceljs');\n const interop = module as ExcelJsModule & { default?: ExcelJsModule };\n return typeof interop.Workbook === 'function'\n ? module\n : (interop.default ?? module);\n}\n\n/** Excel forbids `\\ / ? * [ ] :` in a sheet name and caps it at 31 chars. */\nfunction sheetName(raw: string, used: Set<string>): string {\n const cleaned = raw\n .replace(/[\\\\/?*[\\]:]/g, ' ')\n .trim()\n .slice(0, 31);\n let name = cleaned || 'Sheet';\n let index = 2;\n while (used.has(name.toLowerCase())) {\n const suffix = ` (${index})`;\n name = `${cleaned.slice(0, 31 - suffix.length)}${suffix}`;\n index += 1;\n }\n used.add(name.toLowerCase());\n return name;\n}\n\nfunction numberFormatFor(precision: number | undefined): string | undefined {\n if (precision == null) return undefined;\n return precision > 0 ? `0.${'0'.repeat(precision)}` : '0';\n}\n\nconst MIN_COLUMN_WIDTH = 12;\nconst MAX_COLUMN_WIDTH = 60;\n\nfunction columnWidth(header: string, cells: readonly ExportValue[]): number {\n const longest = cells.reduce<number>(\n (max, cell) => Math.max(max, cell == null ? 0 : String(cell).length),\n header.length,\n );\n return Math.min(MAX_COLUMN_WIDTH, Math.max(MIN_COLUMN_WIDTH, longest + 2));\n}\n\n/** The document as an `.xlsx` — the info block on its own sheet, then one\n * sheet per table. No colour: the kit's tokens are CSS custom properties that\n * only resolve against a live DOM, and this module has none. Weight and\n * freeze-panes carry the hierarchy instead. */\nexport async function toXlsxBlob(document: ExportDocument): Promise<Blob> {\n const ExcelJS = await loadExcelJs();\n const workbook = new ExcelJS.Workbook();\n workbook.created = new Date();\n const used = new Set<string>();\n\n const info = workbook.addWorksheet(sheetName(document.title, used));\n const titleRow = info.addRow([document.title]);\n titleRow.font = { bold: true };\n for (const entry of document.meta) info.addRow([entry.label, entry.value]);\n if (document.footnotes.length > 0) {\n info.addRow([]);\n for (const note of document.footnotes) info.addRow([note]);\n }\n info.getColumn(1).width = 28;\n info.getColumn(2).width = 48;\n\n for (const table of document.tables) {\n const sheet = workbook.addWorksheet(sheetName(table.title, used));\n const headerRow = sheet.addRow(\n table.columns.map((column) => column.header),\n );\n headerRow.font = { bold: true };\n sheet.views = [{ state: 'frozen', ySplit: 1 }];\n\n if (table.rows.length === 0 && table.emptyText) {\n sheet.addRow([table.emptyText]);\n }\n for (const row of table.rows) {\n if (row.kind === 'section') {\n const banner = sheet.addRow([row.cells[0] ?? null]);\n banner.font = { bold: true };\n continue;\n }\n const values = table.columns.map((_, index) => row.cells[index] ?? null);\n const added = sheet.addRow(values);\n table.columns.forEach((column, index) => {\n const cell = added.getCell(index + 1);\n if (typeof values[index] !== 'number') return;\n const format = numberFormatFor(cellPrecision(row, column));\n if (format) cell.numFmt = format;\n cell.alignment = { horizontal: 'right' };\n });\n }\n\n table.columns.forEach((column, index) => {\n sheet.getColumn(index + 1).width = columnWidth(\n column.header,\n table.rows.map((row) => row.cells[index] ?? null),\n );\n });\n }\n\n const buffer = await workbook.xlsx.writeBuffer();\n return new Blob([buffer], { type: XLSX_MIME });\n}\n\n/* ------------------------------ Filenames ------------------------------- */\n\nexport type ExportFormat = 'csv' | 'xlsx' | 'pdf';\n\n/** Deterministic, meaningful, and free of anything a filesystem rejects. */\nexport function exportFileName(\n document: ExportDocument,\n format: ExportFormat,\n): string {\n return `${document.fileStem}.${format}`;\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — the download trigger */\n/* */\n/* The ONLY part of the export path that touches the DOM. Kept out of */\n/* `anamnesis-export.ts` so the serialisers and the writers stay pure and */\n/* unit-testable without a browser. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport {\n type CsvDialect,\n csvDialectFor,\n type ExportDocument,\n exportFileName,\n toCsvBlob,\n toXlsxBlob,\n} from './anamnesis-export';\n\n/** Hand a Blob to the browser as a download. Returns `false` where there is no\n * DOM to hand it to (SSR, a node test), so callers can fall back rather than\n * throw. */\nexport function downloadBlob(blob: Blob, filename: string): boolean {\n if (\n typeof window === 'undefined' ||\n typeof document === 'undefined' ||\n typeof URL === 'undefined' ||\n typeof URL.createObjectURL !== 'function'\n ) {\n return false;\n }\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = filename;\n document.body.appendChild(anchor);\n anchor.click();\n anchor.remove();\n // NOT in this tick. Chrome starts the fetch inside the click dispatch, but\n // Safari and older Firefox revoke first and the download silently aborts —\n // no file, no error to catch, and the caller still says \"ready\".\n window.setTimeout(() => URL.revokeObjectURL(url), 0);\n return true;\n}\n\n/** Download the document as a `.csv` in the dialect its locale calls for. */\nexport function downloadCsv(\n doc: ExportDocument,\n dialect: CsvDialect = csvDialectFor(doc.locale),\n): boolean {\n return downloadBlob(toCsvBlob(doc, dialect), exportFileName(doc, 'csv'));\n}\n\n/** Download the document as an `.xlsx`. Async: exceljs is dynamic-imported. */\nexport async function downloadXlsx(doc: ExportDocument): Promise<boolean> {\n return downloadBlob(await toXlsxBlob(doc), exportFileName(doc, 'xlsx'));\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — the PDF writer, and the print path */\n/* */\n/* The fourth writer over the ONE `ExportDocument` shape from */\n/* `anamnesis-export.ts`. CSV and Excel are for a spreadsheet; this is the */\n/* human-readable copy — and it is also what PRINTS. */\n/* */\n/* WHY PRINT ROUTES THROUGH HERE. There is no `@media print` anywhere in */\n/* the kit, so `window.print()` prints the app shell — sidebar, header, */\n/* rail — around the record. A pattern-scoped print stylesheet would not */\n/* fix it either: Radix Tabs unmounts the inactive panels, so the only */\n/* thing on the page to print is the ACTIVE tab's live DOM — a form of */\n/* inputs on Compile, a sticky horizontally-scrolled matrix on Evolution. */\n/* Printing the DOCUMENT instead means print and PDF are the same bytes, */\n/* and print honours the disclosure gate for free. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport type { Table as AutoTable, UserOptions } from 'jspdf-autotable';\nimport {\n type ExportDocument,\n type ExportRow,\n type ExportTable,\n type ExportValue,\n exportFileName,\n} from './anamnesis-export';\nimport { downloadBlob } from './anamnesis-export-download';\n\nexport const PDF_MIME = 'application/pdf';\n\n/* ------------------------------- Palette -------------------------------- */\n\nexport type PdfRgb = [number, number, number];\n\nexport interface PdfPalette {\n headerFill: PdfRgb;\n headerText: PdfRgb;\n bodyText: PdfRgb;\n mutedText: PdfRgb;\n zebraFill: PdfRgb;\n sectionFill: PdfRgb;\n}\n\n/** Legible without a DOM to read tokens from — a light fill and a dark text\n * everywhere, never white-on-white. Only ever a fallback. */\nconst PDF_FALLBACK: PdfPalette = {\n headerFill: [237, 237, 240],\n headerText: [24, 24, 27],\n bodyText: [24, 24, 27],\n mutedText: [96, 96, 106],\n zebraFill: [249, 249, 250],\n sectionFill: [232, 232, 236],\n};\n\n/** Resolve a DS colour token to `[r, g, b]` by letting the browser do it.\n *\n * READ THE TOKEN, THEN RESOLVE IT — two steps, not one. The kit's colour\n * tokens hold finished colour VALUES (`--muted: var(--color-blue-50)` →\n * `#eaeaee`), not the raw `H S% L%` triplets shadcn ships, so wrapping them in\n * `hsl()` produces an invalid declaration; `color` is inherited, so an invalid\n * one silently resolves to the parent's text colour and every role comes back\n * the same. Assigning the raw value instead makes a bad token detectable: the\n * CSSOM rejects it at parse time and `.style.color` stays empty, which is the\n * one honest signal to take the fallback.\n *\n * The token is read from INSIDE the pattern (not `<body>`), or the theme class\n * on the kit's wrapper would not apply. Mutating `.style` on a throwaway probe\n * that never enters JSX is the same escape hatch the DataTable's PDF path\n * takes (src/docs/23-constraints.mdx). */\nfunction resolveTokenRgb(\n varName: string,\n fallback: PdfRgb,\n scope: Element | null | undefined,\n): PdfRgb {\n if (typeof document === 'undefined' || typeof getComputedStyle !== 'function')\n return fallback;\n const host = scope ?? document.body;\n if (!host) return fallback;\n const value = getComputedStyle(host).getPropertyValue(varName).trim();\n if (!value) return fallback;\n const probe = document.createElement('span');\n probe.style.color = value;\n // Rejected at parse time ⇒ not a colour this browser understands.\n if (!probe.style.color) return fallback;\n probe.style.position = 'absolute';\n probe.style.visibility = 'hidden';\n host.appendChild(probe);\n const computed = getComputedStyle(probe).color;\n probe.remove();\n const match = computed.match(/rgba?\\(\\s*(\\d+)[,\\s]+(\\d+)[,\\s]+(\\d+)/i);\n if (!match) return fallback;\n return [Number(match[1]), Number(match[2]), Number(match[3])];\n}\n\n/** The document palette for the theme `scope` is rendered in. Pass the pattern\n * root; omit it and the fallback greys are used. */\nexport function pdfPalette(scope?: Element | null): PdfPalette {\n return {\n headerFill: resolveTokenRgb('--muted', PDF_FALLBACK.headerFill, scope),\n headerText: resolveTokenRgb('--foreground', PDF_FALLBACK.headerText, scope),\n bodyText: resolveTokenRgb(\n '--card-foreground',\n PDF_FALLBACK.bodyText,\n scope,\n ),\n mutedText: resolveTokenRgb(\n '--muted-foreground',\n PDF_FALLBACK.mutedText,\n scope,\n ),\n zebraFill: resolveTokenRgb('--card', PDF_FALLBACK.zebraFill, scope),\n sectionFill: resolveTokenRgb('--muted', PDF_FALLBACK.sectionFill, scope),\n };\n}\n\n/* --------------------------- Character coverage -------------------------- */\n\n/* jsPDF's built-in faces are the standard-14, and those are WinAnsi (cp1252).\n * ONE character outside it flips the WHOLE string to UTF-16, which a\n * standard-14 font cannot draw — so a single `→` in a column header does not\n * lose the arrow, it loses the header. The symbols below are the ones the kit's\n * own strings reach for; they are respelled rather than dropped so the meaning\n * survives. Characters from another script are left alone: there is nothing to\n * respell them as, and a font subset is the only real fix (FOLLOW-UPS.md). */\nconst WINANSI_SUBSTITUTIONS: ReadonlyArray<readonly [string, string]> = [\n ['→', '->'], // → the Evolution change header\n ['←', '<-'],\n ['↔', '<->'],\n ['⇒', '=>'],\n ['↑', '^'],\n ['↓', 'v'],\n ['≥', '>='], // ≥ reference range, at least\n ['≤', '<='], // ≤ reference range, at most\n ['≈', '~'],\n ['≠', '!='],\n ['−', '-'], // minus sign\n ['‐', '-'], // hyphen\n ['‑', '-'], // non-breaking hyphen\n ['‒', '-'], // figure dash\n ['Δ', 'D'], // Δ\n ['∞', 'inf'],\n ['⁄', '/'],\n // Spaces `Intl.NumberFormat` groups with in several locales.\n ['\\u202f', ' '], // narrow no-break space\n ['\\u2009', ' '], // thin space\n ['\\u2007', ' '], // figure space\n ['\\u2060', ''], // word joiner\n];\n\n/** The cp1252 0x80–0x9f block, which Latin-1 does not cover: the curly\n * quotes, the dashes, the bullet, the ellipsis, the per-mille. */\nconst WINANSI_SPECIALS = new Set(\n [\n 0x20ac, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x02c6, 0x2030,\n 0x0160, 0x2039, 0x0152, 0x017d, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022,\n 0x2013, 0x2014, 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x017e, 0x0178,\n ].map((code) => String.fromCodePoint(code)),\n);\n\n/** True when jsPDF can draw `text` with a built-in face — i.e. it will not be\n * silently re-encoded as UTF-16. */\nexport function isWinAnsiSafe(text: string): boolean {\n for (const character of text) {\n const code = character.codePointAt(0) ?? 0;\n if (code === 0x0a || code === 0x0d || code === 0x09) continue;\n if (code >= 0x20 && code <= 0x7e) continue;\n if (code >= 0xa0 && code <= 0xff) continue;\n if (WINANSI_SPECIALS.has(character)) continue;\n return false;\n }\n return true;\n}\n\n/** Respell the symbols a standard-14 face cannot draw. Applied at the writer\n * boundary, so the arrow survives on screen and in the spreadsheet. */\nexport function pdfSafeText(text: string): string {\n let out = text;\n for (const [from, to] of WINANSI_SUBSTITUTIONS) {\n if (out.includes(from)) out = out.split(from).join(to);\n }\n return out;\n}\n\n/* ------------------------------ Page layout ----------------------------- */\n\n/* Millimetres. A4 portrait is 210 wide; a matrix of visit columns needs more\n * than that, so the orientation follows the widest table. */\nconst MARGIN = 14;\nconst WIDE_TABLE_COLUMNS = 6;\nconst TITLE_SIZE = 15;\nconst META_SIZE = 9;\nconst TABLE_TITLE_SIZE = 11;\nconst BODY_SIZE = 8.5;\nconst FOOTNOTE_SIZE = 8;\nconst LINE = 5;\n\nfunction isWide(document: ExportDocument): boolean {\n return document.tables.some(\n (table) => table.columns.length > WIDE_TABLE_COLUMNS,\n );\n}\n\n/** Latin digits with the reader's decimal mark — this is a document a person\n * reads, not a cell a spreadsheet computes on, so it follows the locale\n * rather than the CSV dialect. */\nfunction formatNumber(\n value: number,\n precision: number | undefined,\n locale: string | undefined,\n): string {\n if (!Number.isFinite(value)) return '';\n try {\n return new Intl.NumberFormat(locale, {\n minimumFractionDigits: precision ?? 0,\n maximumFractionDigits: precision ?? 3,\n }).format(value);\n } catch {\n return precision == null ? String(value) : value.toFixed(precision);\n }\n}\n\nfunction cellText(\n value: ExportValue,\n precision: number | undefined,\n locale: string | undefined,\n): string {\n if (value == null) return '';\n return pdfSafeText(\n typeof value === 'number' ? formatNumber(value, precision, locale) : value,\n );\n}\n\nfunction rowText(\n row: ExportRow,\n table: ExportTable,\n locale: string | undefined,\n): string[] {\n return table.columns.map((column, index) =>\n cellText(\n row.cells[index] ?? null,\n row.precision ?? column.precision,\n locale,\n ),\n );\n}\n\n/* --------------------------------- Writer ------------------------------- */\n\nexport interface PdfOptions {\n palette?: PdfPalette;\n /** Set the PDF's own open action so the viewer raises the print dialog.\n * This is what the Print item uses; a downloaded PDF leaves it off. */\n autoPrint?: boolean;\n}\n\n/** The document as a paged PDF. jspdf + jspdf-autotable are dynamic-imported,\n * so neither ships to a consumer who never exports. */\nexport async function toPdfBlob(\n document: ExportDocument,\n options: PdfOptions = {},\n): Promise<Blob> {\n const [{ jsPDF }, { default: autoTable }] = await Promise.all([\n import('jspdf'),\n import('jspdf-autotable'),\n ]);\n\n const palette = options.palette ?? PDF_FALLBACK;\n const locale = document.locale;\n const doc = new jsPDF({\n orientation: isWide(document) ? 'landscape' : 'portrait',\n unit: 'mm',\n format: 'a4',\n });\n const pageWidth = doc.internal.pageSize.getWidth();\n const pageHeight = doc.internal.pageSize.getHeight();\n const contentWidth = pageWidth - MARGIN * 2;\n\n // jsPDF's built-in faces are the only ones in the file without embedding a\n // subset; `helvetica` is the same one the DataTable's PDF path uses. The\n // kit's own faces are CSS tokens and cannot be handed to jsPDF.\n const setFace = (weight: 'normal' | 'bold', size: number, colour: PdfRgb) => {\n doc.setFont('helvetica', weight);\n doc.setFontSize(size);\n doc.setTextColor(colour[0], colour[1], colour[2]);\n };\n\n let cursorY = MARGIN;\n\n setFace('bold', TITLE_SIZE, palette.headerText);\n for (const line of doc.splitTextToSize(\n pdfSafeText(document.title),\n contentWidth,\n )) {\n doc.text(line, MARGIN, cursorY);\n cursorY += LINE + 1;\n }\n cursorY += 1;\n\n setFace('normal', META_SIZE, palette.mutedText);\n for (const entry of document.meta) {\n doc.text(pdfSafeText(`${entry.label}: ${entry.value}`), MARGIN, cursorY);\n cursorY += LINE - 0.6;\n }\n\n for (const table of document.tables) {\n cursorY += LINE;\n if (cursorY > pageHeight - MARGIN * 2) {\n doc.addPage();\n cursorY = MARGIN;\n }\n setFace('bold', TABLE_TITLE_SIZE, palette.headerText);\n doc.text(pdfSafeText(table.title), MARGIN, cursorY);\n cursorY += 2;\n\n if (table.rows.length === 0 && table.emptyText) {\n cursorY += LINE;\n setFace('normal', BODY_SIZE, palette.mutedText);\n doc.text(pdfSafeText(table.emptyText), MARGIN, cursorY);\n cursorY += 1;\n continue;\n }\n\n // A section row banners its group: the label sits in the first cell and\n // spans the table, which is why it is styled rather than laid out.\n const sectionRows = new Set<number>();\n const body = table.rows.map((row, index) => {\n if (row.kind === 'section') {\n sectionRows.add(index);\n return [\n cellText(row.cells[0] ?? null, undefined, locale),\n ...table.columns.slice(1).map(() => ''),\n ];\n }\n return rowText(row, table, locale);\n });\n\n const capture: { table?: AutoTable } = {};\n const settings: UserOptions = {\n head: [table.columns.map((column) => pdfSafeText(column.header))],\n body,\n startY: cursorY + 2,\n margin: { left: MARGIN, right: MARGIN, bottom: MARGIN + LINE },\n theme: 'grid',\n styles: {\n font: 'helvetica',\n fontSize: BODY_SIZE,\n cellPadding: 1.6,\n textColor: palette.bodyText,\n lineColor: palette.headerFill,\n lineWidth: 0.1,\n overflow: 'linebreak',\n },\n headStyles: {\n fillColor: palette.headerFill,\n textColor: palette.headerText,\n fontStyle: 'bold',\n },\n alternateRowStyles: { fillColor: palette.zebraFill },\n columnStyles: Object.fromEntries(\n table.columns.map((column, index) => [\n index,\n column.numeric ? { halign: 'right' as const } : {},\n ]),\n ),\n didParseCell: (data) => {\n if (data.section !== 'body') return;\n if (!sectionRows.has(data.row.index)) return;\n data.cell.styles.fillColor = palette.sectionFill;\n data.cell.styles.textColor = palette.headerText;\n data.cell.styles.fontStyle = 'bold';\n },\n didDrawPage: (data) => {\n capture.table = data.table;\n },\n };\n autoTable(doc, settings);\n cursorY = capture.table?.finalY ?? cursorY + LINE;\n }\n\n if (document.footnotes.length > 0) {\n cursorY += LINE + 1;\n if (cursorY > pageHeight - MARGIN * 2) {\n doc.addPage();\n cursorY = MARGIN;\n }\n setFace('normal', FOOTNOTE_SIZE, palette.mutedText);\n for (const note of document.footnotes) {\n for (const line of doc.splitTextToSize(pdfSafeText(note), contentWidth)) {\n doc.text(line, MARGIN, cursorY);\n cursorY += LINE - 1;\n }\n }\n }\n\n // Page 2 of a loose clinical record identifies nobody, and a practice copy\n // and a patient copy are otherwise the same object on a desk. Both ride\n // every page.\n const stamp = pdfSafeText(\n [document.patientName, document.audienceLabel].filter(Boolean).join(' · '),\n );\n const pages = doc.getNumberOfPages();\n for (let page = 1; page <= pages; page += 1) {\n doc.setPage(page);\n setFace('normal', FOOTNOTE_SIZE, palette.mutedText);\n if (stamp) doc.text(stamp, MARGIN, pageHeight - MARGIN + 4);\n doc.text(\n `${page} / ${pages}`,\n pageWidth - MARGIN,\n pageHeight - MARGIN + 4,\n { align: 'right' },\n );\n }\n\n if (options.autoPrint) doc.autoPrint();\n return doc.output('blob');\n}\n\n/* ----------------------------- Download / print -------------------------- */\n\n/** Download the document as a `.pdf`. */\nexport async function downloadPdf(\n document: ExportDocument,\n options: PdfOptions = {},\n): Promise<boolean> {\n return downloadBlob(\n await toPdfBlob(document, options),\n exportFileName(document, 'pdf'),\n );\n}\n\n/** Point an off-screen frame at the document with the print action armed, and\n * hand the object URL back so the caller can revoke it. `null` means there was\n * no frame or no `URL.createObjectURL` to build one with. */\nexport async function printPdf(\n document: ExportDocument,\n frame: HTMLIFrameElement | null,\n options: PdfOptions = {},\n): Promise<string | null> {\n if (!frame) return null;\n if (typeof URL === 'undefined' || typeof URL.createObjectURL !== 'function')\n return null;\n const blob = await toPdfBlob(document, { ...options, autoPrint: true });\n const url = URL.createObjectURL(blob);\n frame.setAttribute('src', url);\n return url;\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — the one export / share control */\n/* */\n/* ONE affordance for the whole Diagnosis surface, not one per table. It */\n/* acts on the tab that is currently selected and says so, in the trigger's */\n/* accessible name and again in the menu's own header. */\n/* */\n/* ORDER CARRIES A MESSAGE. Share → PDF → Print → Excel → CSV: the routes */\n/* that keep the record in the practice come first, the spreadsheet last. */\n/* Excel is not hidden — a clinician who wants it is one item away — but a */\n/* menu that leads with it teaches \"take the data out and work elsewhere\". */\n/* */\n/* AUDIENCE IS THE SAFETY FEATURE. One radio governs all five routes, and */\n/* whenever the patient copy is chosen the menu names, on screen, what that */\n/* copy leaves out. Nothing here is a security boundary — the real */\n/* guarantee is a server-side check on the document-generation path. */\n/* */\n/* SHARE IS A MOCK. The dialog shows the SHAPE of a share and says so. It */\n/* transmits nothing, and no string in it claims otherwise. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport type { TFunction } from 'i18next';\nimport {\n ChevronDown,\n Download,\n FileSpreadsheet,\n FileText,\n Printer,\n Share2,\n} from 'lucide-react';\nimport {\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { Alert } from '../../components/alert';\nimport { Badge } from '../../components/badge';\nimport { Button } from '../../components/button';\nimport { Dialog } from '../../components/dialog';\nimport { DropdownMenu } from '../../components/dropdown-menu';\nimport { Radio, RadioGroup } from '../../components/radio-group';\nimport type { PracticeAnamnesisConfig } from './anamnesis-config';\nimport type { DisclosureAudience } from './anamnesis-disclosure';\nimport {\n type AnamnesisExportTab,\n type ExportDocument,\n buildAnamnesisExport,\n documentDisclosure,\n} from './anamnesis-export';\nimport { downloadCsv, downloadXlsx } from './anamnesis-export-download';\nimport { downloadPdf, pdfPalette, printPdf } from './anamnesis-export-pdf';\nimport type { AnamnesisRecord } from './anamnesis-types';\n\n/** The audiences this control offers. `external` is deliberately absent: no\n * disclosure rule discloses anything to it today, so choosing it could only\n * ever produce an empty file. */\ntype OfferedAudience = 'clinician' | 'patient';\n\nconst OFFERED_AUDIENCES: readonly OfferedAudience[] = ['clinician', 'patient'];\n\nexport interface AnamnesisExportMenuProps {\n /** The tab the surface is showing. The control acts on THIS view. */\n tab: AnamnesisExportTab;\n record: AnamnesisRecord;\n t: TFunction;\n config?: PracticeAnamnesisConfig;\n /** Evolution only: the visit columns the grid is currently showing. */\n shownVisitIds?: readonly string[];\n /** Mount with the menu open. Demo/story hook only — Chromatic skips play\n * functions, so a click-opened menu is never snapshotted. */\n defaultOpen?: boolean;\n /** Mount with the share preview open. Demo/story hook, same reason. */\n defaultShareOpen?: boolean;\n /** Mount on this audience instead of the practice copy. Demo/story hook. */\n defaultAudience?: DisclosureAudience;\n}\n\nexport function AnamnesisExportMenu({\n tab,\n record,\n t,\n config,\n shownVisitIds,\n defaultOpen = false,\n defaultShareOpen = false,\n defaultAudience = 'clinician',\n}: AnamnesisExportMenuProps) {\n const [audience, setAudience] = useState<DisclosureAudience>(defaultAudience);\n const [everyVisit, setEveryVisit] = useState(false);\n const [menuOpen, setMenuOpen] = useState(defaultOpen);\n const [shareOpen, setShareOpen] = useState(defaultShareOpen);\n const [shareAudience, setShareAudience] =\n useState<DisclosureAudience>(defaultAudience);\n // `seq` alternates a zero-width space onto the text, so exporting the same\n // file twice still changes the live region and is announced twice.\n const [status, setStatus] = useState({ text: '', seq: 0 });\n\n const rootRef = useRef<HTMLDivElement>(null);\n const frameRef = useRef<HTMLIFrameElement>(null);\n // The previous print's object URL. Revoked when the next print replaces it —\n // never on load, which would pull the file out from under the viewer.\n const printUrlRef = useRef<string | null>(null);\n // One route at a time: Excel awaits a dynamic import, and a second click\n // during that await writes the same file twice.\n const busyRef = useRef(false);\n const describedById = useId();\n\n // The last print's blob outlives the last print. Released with the surface.\n useEffect(\n () => () => {\n if (printUrlRef.current) URL.revokeObjectURL(printUrlRef.current);\n },\n [],\n );\n\n const build = useCallback(\n (forAudience: DisclosureAudience): ExportDocument =>\n buildAnamnesisExport(tab, {\n record,\n audience: forAudience,\n t,\n config,\n selectedVisitIds: shownVisitIds,\n scope: everyVisit ? 'all' : 'selected',\n }),\n [tab, record, t, config, shownVisitIds, everyVisit],\n );\n\n const tabName = t(`anamnesis.export.tab.${tab}`);\n const audienceBadge = t('anamnesis.export.control.audienceBadge');\n\n /* WHAT THIS COPY DOES AND DOES NOT CARRY — said in BOTH states, not only the\n safe one. The likeliest sequence at the chairside never opens the audience\n control at all, so a menu that only speaks up for the patient copy is\n silent in exactly the state that hands over diagnostic codes and lab\n values. Both lines are derived from the same built patient document, so\n neither can drift from the file. Built only while the menu is open: the\n record is the compile form's live state and rebuilding it per keystroke\n would serialise the whole matrix on every character. */\n const patientExcluded = useMemo(\n () => (menuOpen ? documentDisclosure(build('patient'), t).excluded : []),\n [menuOpen, build, t],\n );\n\n const disclosureLine: Record<OfferedAudience, string> = {\n clinician:\n patientExcluded.length > 0\n ? t('anamnesis.export.control.holds', {\n list: patientExcluded.join(t('anamnesis.export.listSeparator')),\n })\n : t('anamnesis.export.control.holdsNone'),\n patient:\n patientExcluded.length > 0\n ? t('anamnesis.export.control.excludes', {\n list: patientExcluded.join(t('anamnesis.export.listSeparator')),\n })\n : t('anamnesis.export.control.excludesNone'),\n };\n\n // The share preview reads its OWN audience: the dialog is where the choice\n // is made, and it must re-describe the copy as the choice changes.\n const sharePreview = useMemo(\n () =>\n shareOpen\n ? documentDisclosure(build(shareAudience), t)\n : { included: [], excluded: [] },\n [shareOpen, build, shareAudience, t],\n );\n\n const say = (text: string) =>\n setStatus((prev) => ({ text, seq: prev.seq + 1 }));\n\n const run = (\n format: 'pdf' | 'xlsx' | 'csv',\n write: (document: ExportDocument) => boolean | Promise<boolean>,\n ) => {\n if (busyRef.current) return;\n busyRef.current = true;\n const document = build(audience);\n void Promise.resolve(write(document))\n .then((ok) =>\n say(\n ok\n ? t('anamnesis.export.control.ready', {\n file: `${document.fileStem}.${format}`,\n })\n : t('anamnesis.export.control.failed'),\n ),\n )\n .catch(() => say(t('anamnesis.export.control.failed')))\n .finally(() => {\n busyRef.current = false;\n });\n };\n\n const palette = () => pdfPalette(rootRef.current);\n\n const handlePdf = () =>\n run('pdf', (document) => downloadPdf(document, { palette: palette() }));\n const handleXlsx = () => run('xlsx', downloadXlsx);\n const handleCsv = () => run('csv', downloadCsv);\n\n const handlePrint = () => {\n if (busyRef.current) return;\n busyRef.current = true;\n void printPdf(build(audience), frameRef.current, { palette: palette() })\n .then((url) => {\n if (!url) {\n say(t('anamnesis.export.control.failed'));\n return;\n }\n if (printUrlRef.current) URL.revokeObjectURL(printUrlRef.current);\n printUrlRef.current = url;\n say(t('anamnesis.export.control.printing'));\n })\n .catch(() => say(t('anamnesis.export.control.failed')))\n .finally(() => {\n busyRef.current = false;\n });\n };\n\n const openShare = () => {\n setShareAudience(audience);\n setShareOpen(true);\n };\n\n const confirmShare = () => {\n setAudience(shareAudience);\n setShareOpen(false);\n say(\n t('anamnesis.export.share.confirmed', {\n audience: t(`anamnesis.export.audience.${shareAudience}`),\n }),\n );\n };\n\n return (\n <div\n ref={rootRef}\n data-component=\"anamnesis-export-menu\"\n data-tab={tab}\n data-audience={audience}\n className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-end ds:gap-[var(--spacing-xs)]\"\n >\n {/* The audience is sticky across tabs and across every later export, and\n the closed control would otherwise say nothing about it. The one\n setting here that cannot be walked back is the one that gets an\n ambient mark. */}\n {audience !== 'clinician' ? (\n <Badge\n variant=\"warning\"\n size=\"sm\"\n data-testid=\"anamnesis-export-audience\"\n >\n {audienceBadge}\n </Badge>\n ) : null}\n\n {/* `modal` follows the story hook: a menu that mounts open would\n otherwise make the rest of a docs page inert. In the product the\n menu opens from a click and stays modal. */}\n <DropdownMenu.Root\n open={menuOpen}\n onOpenChange={setMenuOpen}\n modal={!defaultOpen}\n >\n <DropdownMenu.Trigger asChild>\n <Button\n type=\"button\"\n intent=\"outline\"\n size=\"sm\"\n endIcon={<ChevronDown aria-hidden=\"true\" />}\n /* WCAG 2.5.3: the accessible name OPENS with the visible label, so\n a speech-input user saying what they read still hits it. */\n aria-label={\n audience === 'clinician'\n ? t('anamnesis.export.control.triggerLabel', { tab: tabName })\n : t('anamnesis.export.control.triggerLabelAudience', {\n tab: tabName,\n audience: audienceBadge,\n })\n }\n data-testid=\"anamnesis-export-trigger\"\n >\n {t('anamnesis.export.control.trigger')}\n </Button>\n </DropdownMenu.Trigger>\n\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.Label>\n {t('anamnesis.export.control.menuLabel', { tab: tabName })}\n </DropdownMenu.Label>\n <DropdownMenu.Separator />\n\n <DropdownMenu.Label>\n {t('anamnesis.export.audienceLabel')}\n </DropdownMenu.Label>\n <DropdownMenu.RadioGroup\n value={audience}\n onValueChange={(next) => setAudience(next as DisclosureAudience)}\n >\n {OFFERED_AUDIENCES.map((option) => (\n <DropdownMenu.RadioItem\n key={option}\n value={option}\n /* The consequence is part of the option, not a caption beside\n it: a `DropdownMenu.Label` is a bare div that Radix's roving\n focus steps straight past, so without this a screen-reader\n clinician picks the patient copy and hears only \"checked\". */\n aria-describedby={`${describedById}-${option}`}\n // Keeps the menu open: the audience is a setting for the five\n // items below it, not an action of its own.\n onSelect={(event) => event.preventDefault()}\n >\n {t(`anamnesis.export.audience.${option}`)}\n </DropdownMenu.RadioItem>\n ))}\n </DropdownMenu.RadioGroup>\n\n <DropdownMenu.Label data-testid=\"anamnesis-export-disclosure\">\n {disclosureLine[audience === 'patient' ? 'patient' : 'clinician']}\n </DropdownMenu.Label>\n {/* One description per option, so each is read on the option it\n belongs to rather than describing whatever is currently ticked. */}\n {OFFERED_AUDIENCES.map((option) => (\n <span\n key={option}\n id={`${describedById}-${option}`}\n className=\"ds:sr-only\"\n >\n {disclosureLine[option]}\n </span>\n ))}\n\n {tab === 'evolution' ? (\n /* SwitchItem, not CheckboxItem: a setting the menu keeps open,\n whose OFF state has to be visible — an unticked checkbox row\n renders as an empty slot. */\n <DropdownMenu.SwitchItem\n checked={everyVisit}\n onCheckedChange={setEveryVisit}\n >\n {t('anamnesis.export.control.everyVisit')}\n </DropdownMenu.SwitchItem>\n ) : null}\n\n <DropdownMenu.Separator />\n\n {/* Share → PDF → Print → Excel → CSV. Deliberate: see the header. */}\n <DropdownMenu.Item\n startIcon={<Share2 aria-hidden=\"true\" />}\n onSelect={openShare}\n >\n {t('anamnesis.export.control.share')}\n </DropdownMenu.Item>\n <DropdownMenu.Item\n startIcon={<FileText aria-hidden=\"true\" />}\n onSelect={handlePdf}\n >\n {t('anamnesis.export.control.pdf')}\n </DropdownMenu.Item>\n <DropdownMenu.Item\n startIcon={<Printer aria-hidden=\"true\" />}\n onSelect={handlePrint}\n >\n {t('anamnesis.export.control.print')}\n </DropdownMenu.Item>\n\n <DropdownMenu.Separator />\n\n <DropdownMenu.Item\n startIcon={<FileSpreadsheet aria-hidden=\"true\" />}\n onSelect={handleXlsx}\n >\n {t('anamnesis.export.control.xlsx')}\n </DropdownMenu.Item>\n <DropdownMenu.Item\n startIcon={<Download aria-hidden=\"true\" />}\n onSelect={handleCsv}\n >\n {t('anamnesis.export.control.csv')}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n\n <AnamnesisShareDialog\n open={shareOpen}\n onOpenChange={setShareOpen}\n audience={shareAudience}\n onAudienceChange={setShareAudience}\n preview={sharePreview}\n onConfirm={confirmShare}\n tabName={tabName}\n t={t}\n />\n\n {/* The print target. Zero-sized rather than `hidden`: a display:none\n frame does not paginate, and the viewer inside it is what raises the\n print dialog. Inert — titled, aria-hidden and out of the tab ring. */}\n <iframe\n ref={frameRef}\n title={t('anamnesis.export.control.printFrame')}\n aria-hidden=\"true\"\n tabIndex={-1}\n data-testid=\"anamnesis-print-frame\"\n className=\"ds:fixed ds:size-0 ds:border-0\"\n />\n\n {/* VISIBLE, not sr-only. Every route's only feedback lands here — a\n sighted clinician whose download was blocked, or whose print dialog\n never came up, would otherwise be looking at a control that appears\n to do nothing and would click it again. */}\n <span\n aria-live=\"polite\"\n data-testid=\"anamnesis-export-status\"\n className=\"type-body-sm ds:text-[color:var(--muted-foreground)]\"\n >\n {status.text ? `${status.text}${status.seq % 2 ? '\\u200b' : ''}` : ''}\n </span>\n </div>\n );\n}\n\n/* ------------------------------ Share dialog ----------------------------- */\n\ninterface AnamnesisShareDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n audience: DisclosureAudience;\n onAudienceChange: (audience: DisclosureAudience) => void;\n preview: { included: string[]; excluded: string[] };\n onConfirm: () => void;\n tabName: string;\n t: TFunction;\n}\n\n/** The SHAPE of a share, not a share. It picks a recipient and describes what\n * that recipient's copy holds and holds back — and it says, in the first thing\n * the reader sees, that nothing leaves this screen. Real delivery is a signed\n * expiring link, a consent gate and an audit of who received what over which\n * channel: platform work, none of which a pattern can stand in for. */\nfunction AnamnesisShareDialog({\n open,\n onOpenChange,\n audience,\n onAudienceChange,\n preview,\n onConfirm,\n tabName,\n t,\n}: AnamnesisShareDialogProps) {\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Content size=\"md\" data-testid=\"anamnesis-share-dialog\">\n <Dialog.Header>\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n <Dialog.Title>\n {t('anamnesis.export.share.title', { tab: tabName })}\n </Dialog.Title>\n <Badge variant=\"warning\" size=\"sm\">\n {t('anamnesis.export.share.mockBadge')}\n </Badge>\n </div>\n <Dialog.Description>\n {t('anamnesis.export.share.subtitle')}\n </Dialog.Description>\n </Dialog.Header>\n\n <Dialog.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <Alert variant=\"warning\" data-testid=\"anamnesis-share-notice\">\n <Alert.Title>{t('anamnesis.export.share.noticeTitle')}</Alert.Title>\n <Alert.Description>\n {t('anamnesis.export.share.notice')}\n </Alert.Description>\n </Alert>\n\n <RadioGroup\n label={t('anamnesis.export.share.audienceLabel')}\n value={audience}\n onValueChange={(next) =>\n onAudienceChange(next as DisclosureAudience)\n }\n >\n {OFFERED_AUDIENCES.map((option) => (\n <Radio\n key={option}\n value={option}\n label={t(`anamnesis.export.audience.${option}`)}\n />\n ))}\n </RadioGroup>\n\n <DisclosureList\n title={t('anamnesis.export.share.includes')}\n items={preview.included}\n emptyText={t('anamnesis.export.share.includesNone')}\n testId=\"anamnesis-share-includes\"\n />\n <DisclosureList\n title={t('anamnesis.export.share.excludes')}\n items={preview.excluded}\n emptyText={t('anamnesis.export.share.excludesNone')}\n testId=\"anamnesis-share-excludes\"\n />\n </Dialog.Body>\n\n <Dialog.Footer divider>\n <Dialog.Close asChild>\n <Button type=\"button\" intent=\"ghost\" size=\"sm\">\n {t('anamnesis.export.share.cancel')}\n </Button>\n </Dialog.Close>\n <Button\n type=\"button\"\n intent=\"primary\"\n size=\"sm\"\n onClick={onConfirm}\n data-testid=\"anamnesis-share-confirm\"\n >\n {t('anamnesis.export.share.confirm')}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\nfunction DisclosureList({\n title,\n items,\n emptyText,\n testId,\n}: {\n title: string;\n items: string[];\n emptyText: string;\n testId: string;\n}) {\n return (\n <section\n data-testid={testId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\"\n >\n <h3 className=\"type-label ds:m-0 ds:text-[color:var(--foreground)]\">\n {title}\n </h3>\n {items.length === 0 ? (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {emptyText}\n </p>\n ) : (\n <ul className=\"type-body-sm ds:m-0 ds:flex ds:list-disc ds:flex-col ds:gap-[var(--spacing-2xs)] ds:ps-[var(--spacing-md)] ds:text-[color:var(--muted-foreground)]\">\n {items.map((item) => (\n <li key={item}>{item}</li>\n ))}\n </ul>\n )}\n </section>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — highlighted-answer rule */\n/* */\n/* A practice can flag a question so that certain answers demand the */\n/* clinician's attention — an allergy answered \"yes\", a consent answered */\n/* \"no\", or a free-text question that must always be read. The rule lives */\n/* on the field definition; this helper evaluates it against one answer */\n/* so the field renderer, an overview card and a host's archive row all */\n/* agree on what counts as highlighted. */\n/* -------------------------------------------------------------------- */\n\nimport { isIntakeAnswered } from './anamnesis-format';\nimport type { IntakeAnswer, IntakeFieldDef } from './anamnesis-types';\n\n/** Whether `answer` satisfies the field's highlight rule. An absent rule or\n * a blank answer is never highlighted: the marker flags what the patient\n * SAID, not what they were asked — so `always` still waits for an answer. */\nexport function isHighlightedAnswer(\n def: IntakeFieldDef,\n answer: IntakeAnswer | undefined,\n): boolean {\n if (!def.highlight || !answer) return false;\n switch (def.highlight) {\n case 'always':\n return isIntakeAnswered(answer);\n case 'whenYes':\n return answer.kind === 'yesNo' && answer.present === 'yes';\n case 'whenNo':\n return answer.kind === 'yesNo' && answer.present === 'no';\n default:\n return false;\n }\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — intake field renderer */\n/* */\n/* Turns one declarative IntakeFieldDef + its current answer into the */\n/* correct kit primitive — never a bare text field where a structured */\n/* answer fits: */\n/* text/textarea → TextInput / TextArea */\n/* number → NumberInput (plain, sized to the answer, the unit */\n/* shown inside the field rather than in the label; */\n/* integer unless the def's `decimal` flag or the legacy */\n/* key set says decimal) */\n/* yesNoDetail → RadioGroup (yes/no/not sure) + conditional detail */\n/* choice → Select (closed enumerated list, one answer) */\n/* multiChoice → Checkbox group (closed list, any number of answers) */\n/* frequency → NumberInput (times/week) + optional detail */\n/* meal → TimePicker + TextInput (24-hour recall entry) */\n/* */\n/* Shared by the patient intake form and the clinician's compile-mode */\n/* review of the patient's answers. In compile mode `showOrigin` renders */\n/* the \"from patient\" marker until the clinician edits the value, at which */\n/* point the surface flips the origin to `clinician` and the marker drops. */\n/* -------------------------------------------------------------------- */\n\nimport type { TFunction } from 'i18next';\nimport { HeartPulse } from 'lucide-react';\nimport { Badge } from '../../components/badge';\nimport { Checkbox } from '../../components/checkbox';\nimport { FormField } from '../../components/form-field';\nimport { TextInput } from '../../components/text-input';\nimport { TextArea } from '../../components/text-area';\nimport { NumberInput } from '../../components/number-input';\nimport { RadioGroup, Radio } from '../../components/radio-group';\nimport { Select, type SelectOption } from '../../components/select';\nimport { TimePicker } from '../../components/time-picker';\nimport type { TimeValue } from '../../components/_shared/time';\nimport {\n intakeFieldHelp,\n intakeFieldLabel,\n intakeFieldLabelWithUnit,\n} from './anamnesis-format';\nimport { isHighlightedAnswer } from './anamnesis-highlight';\nimport { OriginMarker } from './anamnesis-indicators';\nimport type {\n AnswerOrigin,\n IntakeAnswer,\n IntakeFieldDef,\n YesNo,\n} from './anamnesis-types';\n\n/* ------------------------------- Helpers -------------------------------- */\n\nfunction timeToValue(time: string): TimeValue | undefined {\n if (!time) return undefined;\n const [h, m] = time.split(':').map((n) => Number.parseInt(n, 10));\n if (Number.isNaN(h) || Number.isNaN(m)) return undefined;\n return { hours: h, minutes: m };\n}\n\nfunction valueToTime(value: TimeValue): string {\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${pad(value.hours)}:${pad(value.minutes)}`;\n}\n\n/** Is this field's free-text \"Dettagli\" box on screen right now? Mirrors what\n * the case blocks below actually render — a frequency detail is up from the\n * start, a choice detail waits for a selection, a yes/no detail for a \"yes\" —\n * so the intake can hand the whole row to any field showing one. */\nexport function isDetailVisible(\n def: IntakeFieldDef,\n answer?: IntakeAnswer,\n): boolean {\n if (def.detail !== true) return false;\n switch (def.type) {\n case 'yesNoDetail':\n return answer?.kind === 'yesNo' && answer.present === 'yes';\n case 'frequency':\n return true;\n case 'choice':\n return answer?.kind === 'choice' && Boolean(answer.selected);\n default:\n return false;\n }\n}\n\n/** The flag is the heart alone on every question: the words repeated down a\n * column of questions read as noise, and the meaning is in the tooltip and\n * the accessible name either way. */\nconst HIGHLIGHT_WORDS_SR_ONLY = 'ds:sr-only';\n/** With no words the chip is a round mark, not a short pill. */\nconst HIGHLIGHT_CHIP_COMPACT = 'ds:aspect-square ds:justify-center ds:px-0';\n/** Optically centred on the FIRST line of a question that wraps. */\nconst HIGHLIGHT_CHIP_ALIGN = 'ds:mt-[var(--spacing-2xs)]';\n\n/** Number fields captured to one decimal place vs whole numbers. */\nconst DECIMAL_NUMBER_FIELDS = new Set(['weightSelf', 'waterPerDay']);\n\n/** A number field is sized to its answer: four digits fit the small width,\n * a declared bound of 10 000 or more widens it. `IntakeFieldDef` carries no\n * `max` today, so every seeded field takes the small width. */\n/* ------------------------------------------------------------------ */\n/* One width scale for every control */\n/* */\n/* A control that sizes itself invents its own width, and a form of */\n/* four different widths reads as an accident. Three steps only, and a */\n/* field that spans the row keeps its control at its own step rather */\n/* than running the width of the card. */\n/* ------------------------------------------------------------------ */\n\n/** Everything that is not a number: selects, one-line text, details boxes and\n * prose alike. ONE measure — two text boxes of different widths stacked on\n * each other read as an accident, whatever the reason for the difference. */\nconst CONTROL_MEASURE = 'ds:w-full ds:max-w-[44rem]';\n\nfunction numberInline(\n def: Pick<IntakeFieldDef, 'key'> & { max?: number },\n): 'sm' | 'md' {\n return def.max !== undefined && def.max >= 10000 ? 'md' : 'sm';\n}\n\n/* -------------------------------- Props --------------------------------- */\n\nexport interface AnamnesisFieldProps {\n def: IntakeFieldDef;\n answer?: IntakeAnswer;\n onChange: (answer: IntakeAnswer) => void;\n /** Show the \"from patient\" marker when the value still carries patient origin\n * (compile mode). Intake mode leaves this off — the patient owns the form. */\n showOrigin?: boolean;\n origin?: AnswerOrigin;\n /** Render the answer without letting it be changed — the state a compiled\n * questionnaire arrives in, until the reader asks to edit it. Every control\n * is disabled rather than swapped for text, so nothing shifts under the\n * reader when editing is unlocked. */\n readOnly?: boolean;\n /** Grid placement handed down by the section that lays the field out — the\n * whole row for a question that needs the width. */\n className?: string;\n t: TFunction;\n}\n\n/* ------------------------------- Component ------------------------------ */\n\nexport function AnamnesisField({\n def,\n answer,\n onChange,\n showOrigin = false,\n origin,\n readOnly = false,\n className,\n t,\n}: AnamnesisFieldProps) {\n // A number shows its unit inside the field, so its label keeps the\n // question alone; every other type still spells the unit out in the label.\n const label =\n def.type === 'number'\n ? intakeFieldLabel(def, t)\n : intakeFieldLabelWithUnit(def, t);\n const description = intakeFieldHelp(def, t);\n const showMarker = showOrigin && origin === 'patient';\n // Evaluated on the CURRENT answer, so the marker appears the moment the\n // clinician ticks \"yes\" on a flagged question and leaves when they change\n // their mind — the read-only render then shows exactly what was saved.\n const highlighted = isHighlightedAnswer(def, answer);\n // The flag LEADS the question: at the inline end it read as a mark on\n // whatever came next. The origin marker keeps the end — it qualifies the\n // answer, not the question.\n const highlightLabel = t('anamnesis.field.highlighted');\n const labelStart = highlighted ? (\n <span data-testid={`anamnesis-field-${def.key}-highlight`}>\n <Badge\n variant=\"accentSoft\"\n size=\"sm\"\n className={`${HIGHLIGHT_CHIP_ALIGN} ${HIGHLIGHT_CHIP_COMPACT}`}\n leading={<HeartPulse aria-hidden=\"true\" />}\n >\n <span className={HIGHLIGHT_WORDS_SR_ONLY}>{highlightLabel}</span>\n </Badge>\n </span>\n ) : undefined;\n const labelEnd = showMarker ? <OriginMarker t={t} /> : undefined;\n\n let control: React.ReactNode = null;\n\n switch (def.type) {\n case 'text': {\n const value = answer?.kind === 'text' ? answer.text : '';\n control = (\n <FormField\n label={label}\n labelStart={labelStart}\n labelEnd={labelEnd}\n description={description}\n >\n <TextInput\n className={CONTROL_MEASURE}\n disabled={readOnly}\n value={value}\n onChange={(e) => onChange({ kind: 'text', text: e.target.value })}\n />\n </FormField>\n );\n break;\n }\n case 'textarea': {\n const value = answer?.kind === 'text' ? answer.text : '';\n control = (\n <FormField\n label={label}\n labelStart={labelStart}\n labelEnd={labelEnd}\n description={description}\n >\n <TextArea\n disabled={readOnly}\n value={value}\n autoResize\n minRows={2}\n className={CONTROL_MEASURE}\n onChange={(e) => onChange({ kind: 'text', text: e.target.value })}\n />\n </FormField>\n );\n break;\n }\n case 'number': {\n const value = answer?.kind === 'number' ? answer.value : null;\n control = (\n <FormField\n label={label}\n labelStart={labelStart}\n labelEnd={labelEnd}\n description={description}\n >\n <NumberInput\n disabled={readOnly}\n value={value}\n min={0}\n variant=\"plain\"\n unit={def.unit}\n inline={numberInline(def)}\n mode={\n def.decimal || DECIMAL_NUMBER_FIELDS.has(def.key)\n ? 'decimal'\n : 'integer'\n }\n onChange={(next) => onChange({ kind: 'number', value: next })}\n />\n </FormField>\n );\n break;\n }\n case 'frequency': {\n const perWeek = answer?.kind === 'frequency' ? answer.perWeek : null;\n const detail = answer?.kind === 'frequency' ? (answer.detail ?? '') : '';\n control = (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <FormField\n label={label}\n labelStart={labelStart}\n labelEnd={labelEnd}\n description={description}\n >\n <NumberInput\n disabled={readOnly}\n value={perWeek}\n min={0}\n max={21}\n variant=\"plain\"\n inline=\"sm\"\n mode=\"integer\"\n onChange={(next) =>\n onChange({\n kind: 'frequency',\n perWeek: next,\n detail: detail || undefined,\n })\n }\n />\n </FormField>\n {def.detail ? (\n <FormField label={t(`anamnesis.field.${def.key}.detailLabel`)}>\n <TextInput\n className={CONTROL_MEASURE}\n disabled={readOnly}\n value={detail}\n onChange={(e) =>\n onChange({\n kind: 'frequency',\n perWeek,\n detail: e.target.value || undefined,\n })\n }\n />\n </FormField>\n ) : null}\n </div>\n );\n break;\n }\n case 'yesNoDetail': {\n const present: YesNo =\n answer?.kind === 'yesNo' ? answer.present : 'unknown';\n const detail = answer?.kind === 'yesNo' ? (answer.detail ?? '') : '';\n control = (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <RadioGroup\n disabled={readOnly}\n label={label}\n labelStart={labelStart}\n labelEnd={labelEnd}\n description={description}\n variant=\"horizontal\"\n value={present}\n onValueChange={(next) =>\n onChange({\n kind: 'yesNo',\n present: next as YesNo,\n detail: detail || undefined,\n })\n }\n >\n <Radio\n disabled={readOnly}\n value=\"yes\"\n label={t('anamnesis.common.yes')}\n />\n <Radio\n disabled={readOnly}\n value=\"no\"\n label={t('anamnesis.common.no')}\n />\n <Radio\n disabled={readOnly}\n value=\"unknown\"\n label={t('anamnesis.common.notSure')}\n />\n </RadioGroup>\n {isDetailVisible(def, answer) ? (\n <FormField label={t('anamnesis.common.details')}>\n <TextInput\n className={CONTROL_MEASURE}\n disabled={readOnly}\n value={detail}\n onChange={(e) =>\n onChange({\n kind: 'yesNo',\n present,\n detail: e.target.value || undefined,\n })\n }\n />\n </FormField>\n ) : def.detail === true && !readOnly ? (\n /* The row is reserved for this question either way, so the space\n it will need reads as waiting rather than wasted. Inert: it is\n a preview of a control, not one. */\n <div aria-hidden=\"true\" className=\"ds:opacity-50\">\n <FormField label={t('anamnesis.common.details')}>\n <TextInput\n className={CONTROL_MEASURE}\n disabled\n value=\"\"\n placeholder={t('anamnesis.common.detailsPending')}\n />\n </FormField>\n </div>\n ) : null}\n </div>\n );\n break;\n }\n case 'choice': {\n const selected = answer?.kind === 'choice' ? (answer.selected ?? '') : '';\n const detail = answer?.kind === 'choice' ? (answer.detail ?? '') : '';\n const options: SelectOption[] = (def.options ?? []).map((opt) => ({\n value: opt,\n // A practice-added option has no kit translation; show it verbatim\n // rather than the unresolved key.\n label: t(`anamnesis.field.${def.key}.option.${opt}`, {\n defaultValue: opt,\n }),\n }));\n control = (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <FormField\n label={label}\n labelStart={labelStart}\n labelEnd={labelEnd}\n description={description}\n >\n <Select\n className={CONTROL_MEASURE}\n disabled={readOnly}\n options={options}\n value={selected}\n placeholder={t('anamnesis.common.choose')}\n onValueChange={(next) =>\n onChange({\n kind: 'choice',\n selected: next || null,\n detail: detail || undefined,\n })\n }\n />\n </FormField>\n {/* The platform's dropdown_with_text: a free-text detail beside the\n selection, under the SAME shared label the yes/no detail uses. */}\n {def.detail && selected ? (\n <FormField label={t('anamnesis.common.details')}>\n <TextInput\n className={CONTROL_MEASURE}\n disabled={readOnly}\n value={detail}\n onChange={(e) =>\n onChange({\n kind: 'choice',\n selected,\n detail: e.target.value || undefined,\n })\n }\n />\n </FormField>\n ) : null}\n </div>\n );\n break;\n }\n case 'multiChoice': {\n const selected = answer?.kind === 'multiChoice' ? answer.selected : [];\n const toggle = (opt: string) =>\n onChange({\n kind: 'multiChoice',\n selected: selected.includes(opt)\n ? selected.filter((entry) => entry !== opt)\n : [...selected, opt],\n });\n control = (\n <fieldset className=\"ds:m-0 ds:border-0 ds:p-0\">\n <legend className=\"type-label ds:mb-[var(--spacing-2xs)] ds:w-full ds:text-[color:var(--foreground)]\">\n <span className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n {labelStart}\n {labelStart ? ' ' : null}\n <span>{label}</span>\n {labelEnd ? ' ' : null}\n {labelEnd ? (\n <span className=\"ds:ms-auto ds:inline-flex ds:shrink-0 ds:items-center\">\n {labelEnd}\n </span>\n ) : null}\n </span>\n </legend>\n {description ? (\n <p className=\"type-body-sm ds:m-0 ds:mb-[var(--spacing-xs)] ds:text-[color:var(--muted-foreground)]\">\n {description}\n </p>\n ) : null}\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n {(def.options ?? []).map((opt) => (\n <Checkbox\n disabled={readOnly}\n key={opt}\n // A practice-added option has no kit translation; show it\n // verbatim rather than the unresolved key.\n label={t(`anamnesis.field.${def.key}.option.${opt}`, {\n defaultValue: opt,\n })}\n checked={selected.includes(opt)}\n onCheckedChange={() => toggle(opt)}\n />\n ))}\n </div>\n </fieldset>\n );\n break;\n }\n case 'meal': {\n const time = answer?.kind === 'meal' ? answer.time : '';\n const desc = answer?.kind === 'meal' ? answer.description : '';\n control = (\n <fieldset className=\"ds:m-0 ds:border-0 ds:p-0\">\n <legend className=\"type-label ds:mb-[var(--spacing-2xs)] ds:w-full ds:text-[color:var(--foreground)]\">\n <span className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n {labelStart}\n {labelStart ? ' ' : null}\n <span>{label}</span>\n {labelEnd ? ' ' : null}\n {labelEnd ? (\n <span className=\"ds:ms-auto ds:inline-flex ds:shrink-0 ds:items-center\">\n {labelEnd}\n </span>\n ) : null}\n </span>\n </legend>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:sm:flex-row ds:sm:items-start\">\n <FormField label={t('anamnesis.common.time')}>\n <TimePicker\n disabled={readOnly}\n value={timeToValue(time)}\n onChange={(next) =>\n onChange({\n kind: 'meal',\n time: valueToTime(next),\n description: desc,\n })\n }\n />\n </FormField>\n <div className=\"ds:grow\">\n <FormField label={t('anamnesis.common.whatEaten')}>\n <TextInput\n className={CONTROL_MEASURE}\n disabled={readOnly}\n value={desc}\n onChange={(e) =>\n onChange({\n kind: 'meal',\n time,\n description: e.target.value,\n })\n }\n />\n </FormField>\n </div>\n </div>\n </fieldset>\n );\n break;\n }\n }\n\n return (\n <div\n data-testid={`anamnesis-field-${def.key}`}\n data-highlighted={highlighted ? 'true' : undefined}\n // A highlighted answer is \"in risalto\": the brand ACCENT, never the\n // error red — a flagged answer is a clinical fact to notice, not a\n // mistake to fix. The mark is the chip on the question line; the\n // block itself stays unframed so the form keeps one rhythm.\n className={`ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]${\n className ? ` ${className}` : ''\n }`}\n >\n {control}\n </div>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — target arithmetic for the Diagnosis summary strip */\n/* */\n/* Two derivations, both pure and both per-parameter: */\n/* */\n/* • {@link targetStatus} — where the patient stands against one goal, */\n/* as the traffic light the care plan's tiles already speak. */\n/* • {@link targetBoundsFor} — the sane input range the target editor */\n/* accepts, so a mistyped goal cannot become a clinical figure. */\n/* */\n/* There is deliberately NO single percentage across the four metrics. A */\n/* 10% miss on protein is one yoghurt; a 10% miss on weight is seven kilos */\n/* and a different plan. Each band below states the clinical reason it is */\n/* the width it is. */\n/* -------------------------------------------------------------------- */\n\nimport type { TargetStatus } from '../_shared/target-tile';\nimport { configuredParameters } from './anamnesis-config';\nimport type { PracticeAnamnesisConfig } from './anamnesis-config';\nimport type { NumericParameterDef } from './anamnesis-types';\n\nexport type { TargetStatus };\n\n/* ------------------------------ Strip scope ----------------------------- */\n\n/** The strip is the practice's CHOSEN goals — every live parameter whose\n * `goal` flag is set, in capture display order. The kit seeds the four\n * figures a nutrition plan is written in (weight, BMI, daily energy,\n * protein), and the configuration editor's Targets tab toggles the set. A\n * parameter the practice archived is simply absent, so a practice that does\n * not estimate intake gets a two-tile strip rather than a tile reading from\n * nothing. */\nexport function stripParameters(\n config?: PracticeAnamnesisConfig,\n): NumericParameterDef[] {\n return configuredParameters(config).filter((def) => def.goal === true);\n}\n\n/* ------------------------------ Status bands ---------------------------- */\n\n/** How wide \"on target\" and \"approaching\" are for one parameter.\n *\n * `kind` — `absolute` bands are in the parameter's own unit; `relative` ones\n * are a fraction of the target. Absolute is right where the scale itself is\n * narrow and fixed (BMI); relative is right where the target's magnitude\n * varies patient to patient (weight, energy, protein).\n *\n * `sided` — `both` counts an overshoot as a miss; `atLeast` treats the target\n * as a FLOOR (at or above it is met); `atMost` as a CAP. */\nexport interface TargetBand {\n kind: 'absolute' | 'relative';\n /** Within this of the target = on target. */\n onTarget: number;\n /** Within this = approaching; beyond it = off target. */\n approaching: number;\n sided: 'both' | 'atLeast' | 'atMost';\n}\n\n/** Per-parameter bands. Each comment is the clinical reason for the width. */\nexport const TARGET_BANDS: Readonly<Record<string, TargetBand>> = {\n // ±2% of goal weight (≈1.2 kg at 62 kg) is the day-to-day hydration and\n // gut-content swing — indistinguishable from being at target. 10% is the\n // clinically meaningful unit of weight change (the 5–10% loss guidelines are\n // written in), so inside it is the last leg. Two-sided: undershooting a\n // weight goal is not a success, it is a different conversation.\n weight: { kind: 'relative', onTarget: 0.02, approaching: 0.1, sided: 'both' },\n // A circumference goal behaves like a mass goal — same shape, same reasons.\n waist: { kind: 'relative', onTarget: 0.02, approaching: 0.1, sided: 'both' },\n // Absolute, because the BMI scale is narrow and fixed for everyone. 0.5\n // kg/m² is roughly the move a 1.5 kg weighing difference makes at adult\n // height; 2.0 is about a third of the 18.5–24.9 healthy band, so \"still\n // inside the same part of the scale\".\n bmi: { kind: 'absolute', onTarget: 0.5, approaching: 2, sided: 'both' },\n // Dietary-recall energy estimates carry roughly ±10–20% error, so a 5% gap\n // is below the noise floor of the measurement itself and 15% is a different\n // diet, not a rounding difference. Two-sided: over- and under-eating both\n // miss the plan.\n energy: {\n kind: 'relative',\n onTarget: 0.05,\n approaching: 0.15,\n sided: 'both',\n },\n // A FLOOR, not a set-point: the protein target is the amount to reach, and\n // eating more of it is not a miss. Below it, 10% (≈9 g at a 90 g target — an\n // egg and a yoghurt) is a closable gap; beyond that the plan is not running.\n protein: {\n kind: 'relative',\n onTarget: 0,\n approaching: 0.1,\n sided: 'atLeast',\n },\n};\n\n/** The band for a parameter the practice added itself. Two-sided 5% / 15% —\n * wide enough not to shout at a measurement's own noise, narrow enough that\n * \"on target\" still means something. */\nexport const DEFAULT_TARGET_BAND: TargetBand = {\n kind: 'relative',\n onTarget: 0.05,\n approaching: 0.15,\n sided: 'both',\n};\n\n/** The band a parameter is judged by. Never throws on an unknown key. */\nexport function targetBandFor(parameterKey: string): TargetBand {\n return TARGET_BANDS[parameterKey] ?? DEFAULT_TARGET_BAND;\n}\n\n/** A band edge in the parameter's own unit. A relative band against a target\n * of 0 collapses to 0, which is correct: \"within 5% of zero\" is zero. */\nfunction tolerance(band: TargetBand, edge: number, target: number): number {\n return band.kind === 'absolute' ? edge : Math.abs(target) * edge;\n}\n\n/** Where `now` stands against `target`. `null` whenever the question cannot be\n * asked — no target set, or nothing measured yet — so the tile shows no\n * traffic light rather than a green one it has not earned. */\nexport function targetStatus(\n now: number | null,\n target: number | null,\n parameterKey: string,\n): TargetStatus | null {\n if (now == null || !Number.isFinite(now)) return null;\n if (target == null || !Number.isFinite(target)) return null;\n const band = targetBandFor(parameterKey);\n const gap = now - target;\n // The met side of a one-sided goal is met at any distance.\n if (band.sided === 'atLeast' && gap >= 0) return 'onTarget';\n if (band.sided === 'atMost' && gap <= 0) return 'onTarget';\n const distance = Math.abs(gap);\n if (distance <= tolerance(band, band.onTarget, target)) return 'onTarget';\n if (distance <= tolerance(band, band.approaching, target)) {\n return 'approaching';\n }\n return 'offTarget';\n}\n\n/* ------------------------------ Input bounds ---------------------------- */\n\n/** The range and granularity the target editor accepts for one parameter. */\nexport interface TargetBounds {\n min: number;\n max: number;\n step: number;\n}\n\n/** Physiologically sane editor bounds. Wide enough for any real patient,\n * narrow enough that a slipped decimal point is rejected at the input. */\nexport const TARGET_BOUNDS: Readonly<Record<string, TargetBounds>> = {\n weight: { min: 20, max: 400, step: 0.1 },\n bmi: { min: 10, max: 60, step: 0.1 },\n waist: { min: 30, max: 250, step: 1 },\n energy: { min: 500, max: 6000, step: 50 },\n protein: { min: 10, max: 400, step: 5 },\n};\n\n/** Bounds for a parameter, falling back to a non-negative range stepped at the\n * parameter's own precision so a practice-added target is still editable. */\nexport function targetBoundsFor(def: NumericParameterDef): TargetBounds {\n const known = TARGET_BOUNDS[def.key];\n if (known) return known;\n const precision = def.precision ?? 0;\n return { min: 0, max: 10000, step: 10 ** -precision };\n}\n\n/** Whether a drafted target may be committed. Out-of-bounds is rejected at the\n * editor rather than clamped: silently changing a clinician's 620 to 400 is\n * worse than refusing it. `null` is always committable — it clears. */\nexport function isTargetInBounds(\n draft: number | null,\n bounds: TargetBounds,\n): boolean {\n if (draft == null) return true;\n if (!Number.isFinite(draft)) return false;\n return draft >= bounds.min && draft <= bounds.max;\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — the one target editor */\n/* */\n/* A per-patient target is a clinical goal, not a measurement, and it is */\n/* set from exactly one control wherever it appears: a labelled edit */\n/* button that opens a small popover form (value, unit, bounds, Save, */\n/* Clear). Two surfaces mount it — the Diagnosis summary strip and the */\n/* capture blocks' target line — and they must not offer two different */\n/* affordances for the same number. */\n/* */\n/* Why a form and not a live input: both host surfaces are read at a */\n/* glance mid-consultation, where an always-live field turns a stray */\n/* scroll-wheel or tab-through into a changed clinical goal. The form also */\n/* buys room for a real label, the unit, the accepted range, a dirty */\n/* marker and a Clear — a target must be clearable, not only changeable. */\n/* Discoverability is bought back by making the trigger a persistent, */\n/* named button (never hover-only) and by letting an unset target say so */\n/* in the readout it replaces. */\n/* -------------------------------------------------------------------- */\n\nimport { useState } from 'react';\nimport type { TFunction } from 'i18next';\nimport { Pencil } from 'lucide-react';\nimport { Button } from '../../components/button';\nimport { FormField } from '../../components/form-field';\nimport { IconButton } from '../../components/icon-button';\nimport { NumberInput } from '../../components/number-input';\nimport { Popover } from '../../components/popover';\nimport { parameterLabelWithUnit } from './anamnesis-format';\nimport {\n isTargetInBounds,\n targetBoundsFor,\n type TargetBounds,\n} from './anamnesis-targets';\nimport type { NumericParameterDef } from './anamnesis-types';\n\n/* -------------------------------- Props --------------------------------- */\n\nexport interface TargetEditorProps {\n def: NumericParameterDef;\n /** The host's own label for the metric, for the trigger's accessible name. */\n label: string;\n /** The committed target, or `null` when none is set. */\n committed: number | null;\n /** The current-value line (\"Now 74.5 kg\"), reused as the form's context. */\n nowLabel: string;\n t: TFunction;\n onCommit: (target: number | null) => void;\n}\n\n/** Whether two targets are the same goal. `null` is a value here (no target). */\nfunction sameTarget(a: number | null, b: number | null): boolean {\n if (a == null || b == null) return a === b;\n return a === b;\n}\n\nfunction boundsLabel(bounds: TargetBounds, def: NumericParameterDef): string {\n return def.unit\n ? `${bounds.min}–${bounds.max} ${def.unit}`\n : `${bounds.min}–${bounds.max}`;\n}\n\n/** The edit affordance: a labelled button on the tile that opens a small form.\n * The draft is local and discarded on dismiss — nothing is committed until\n * Save, which is the tile's committed/dirty boundary. */\nexport function TargetEditor({\n def,\n label,\n committed,\n nowLabel,\n t,\n onCommit,\n}: TargetEditorProps) {\n const [open, setOpen] = useState(false);\n const [draft, setDraft] = useState<number | null>(committed);\n const bounds = targetBoundsFor(def);\n const inBounds = isTargetInBounds(draft, bounds);\n const dirty = !sameTarget(draft, committed);\n const parameter = parameterLabelWithUnit(def, t);\n const range = boundsLabel(bounds, def);\n\n // Re-seed the draft from the committed value every time the form opens, so a\n // dismissed edit never lingers as a stale draft on the next open.\n const handleOpenChange = (next: boolean) => {\n if (next) setDraft(committed);\n setOpen(next);\n };\n\n const commit = (target: number | null) => {\n onCommit(target);\n setOpen(false);\n };\n\n return (\n <Popover open={open} onOpenChange={handleOpenChange}>\n <Popover.Trigger asChild>\n <IconButton\n icon={<Pencil aria-hidden=\"true\" />}\n intent=\"ghost\"\n size=\"sm\"\n aria-label={t('anamnesis.targets.edit', { parameter: label })}\n data-testid={`anamnesis-target-edit-${def.key}`}\n />\n </Popover.Trigger>\n <Popover.Content\n size=\"md\"\n align=\"start\"\n data-testid={`anamnesis-target-form-${def.key}`}\n >\n <Popover.Close />\n <Popover.Heading>\n {t('anamnesis.targets.editTitle', { parameter })}\n </Popover.Heading>\n <Popover.Description>{nowLabel}</Popover.Description>\n <div className=\"ds:mt-[var(--spacing-md)] ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <FormField\n label={t('anamnesis.targets.editField')}\n description={t('anamnesis.targets.bounds', { range })}\n error={\n inBounds\n ? undefined\n : t('anamnesis.targets.outOfBounds', { range })\n }\n >\n <NumberInput\n value={draft}\n mode={(def.precision ?? 0) > 0 ? 'decimal' : 'integer'}\n min={bounds.min}\n max={bounds.max}\n step={bounds.step}\n onChange={setDraft}\n data-testid={`anamnesis-target-input-${def.key}`}\n />\n </FormField>\n {/* The dirty marker. The tile behind the popover still shows the\n committed goal, so \"changed but not saved\" has to be said. */}\n {dirty && inBounds ? (\n <span className=\"type-meta ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.targets.unsaved')}\n </span>\n ) : null}\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-end ds:gap-[var(--spacing-sm)]\">\n {/* A target must be clearable, not only changeable — a goal that\n no longer applies is not the same as a goal of zero. */}\n <Button\n intent=\"ghost\"\n size=\"sm\"\n disabled={committed == null}\n onClick={() => commit(null)}\n data-testid={`anamnesis-target-clear-${def.key}`}\n >\n {t('anamnesis.targets.clear')}\n </Button>\n <Button\n intent=\"primary\"\n size=\"sm\"\n disabled={!dirty || !inBounds}\n onClick={() => commit(draft)}\n data-testid={`anamnesis-target-save-${def.key}`}\n >\n {t('anamnesis.targets.save')}\n </Button>\n </div>\n </div>\n </Popover.Content>\n </Popover>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Shared present-vs-target tile */\n/* */\n/* One compact KPI cell: the metric's TARGET as the headline figure, the */\n/* patient's current value beneath it, and a traffic-light status chip. */\n/* Extracted from the dietitian care-plan editor so the care plan and the */\n/* anamnesis Diagnosis strip read as one product — the two surfaces show */\n/* the same four nutrition goals and must not drift apart visually. */\n/* */\n/* Two variants: `outlined` (the default — hosts already inside a Card */\n/* keep a flat tile so cards do not nest) and `elevated` (the Card's own */\n/* elevated recipe — surface, card border, shadow — for hosts that want */\n/* the tiles to read as cards, e.g. the anamnesis goals strip). Each tile */\n/* is a `role=\"group\"` with a plain label, NOT a heading, so a host page */\n/* keeps a clean h1 → h2 outline. */\n/* */\n/* Presentational only — every string arrives already translated, and the */\n/* tile owns no state. The optional slots are what let one shell carry */\n/* both a static plan tile and an editable, gauge-carrying record tile. */\n/* -------------------------------------------------------------------- */\n\nimport type { ReactNode } from 'react';\nimport { Badge } from '../../components/badge';\n\n/** Where the patient stands against one target. */\nexport type TargetStatus = 'onTarget' | 'approaching' | 'offTarget';\n\n/** Traffic light → semantic Badge variant. green / amber / red map to the\n * kit's success / warning / error tokens (each carries its own -foreground\n * pairing, so the chip stays legible in all four themes). */\nexport const TARGET_STATUS_VARIANT: Record<\n TargetStatus,\n 'success' | 'warning' | 'error'\n> = {\n onTarget: 'success',\n approaching: 'warning',\n offTarget: 'error',\n};\n\nexport interface TargetTileProps {\n /** `outlined` (default) for hosts already inside a Card; `elevated`\n * mirrors the kit Card's elevated recipe for tiles that read as cards. */\n variant?: 'outlined' | 'elevated';\n /** Metric name, e.g. \"Target weight\". Also the group's accessible name. */\n label: string;\n /** The TARGET, formatted with its unit — the tile's headline figure. */\n target: string;\n /** The patient's current value, already phrased (\"Now 74.5 kg\"). */\n now: string;\n /** Omit (or `null`) when no target is set — the tile then shows no chip. */\n status?: TargetStatus | null;\n /** Translated status text. Required whenever `status` is set: the traffic\n * light is colour PLUS text, never colour alone (WCAG 1.4.1). */\n statusLabel?: string;\n /** Trailing affordance on the status row — e.g. an edit control. */\n action?: ReactNode;\n /** Extra body under the `now` line — e.g. a banded gauge for the current\n * value. Kept adjacent to `now` so it reads as an elaboration of the\n * measured figure, never of the headline target. */\n children?: ReactNode;\n}\n\nexport function TargetTile({\n variant = 'outlined',\n label,\n target,\n now,\n status,\n statusLabel,\n action,\n children,\n}: TargetTileProps) {\n return (\n <div\n role=\"group\"\n aria-label={label}\n className={\n 'ds:flex ds:flex-col ds:items-start ds:gap-[var(--spacing-xs)] ds:rounded-[var(--radius-md)] ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)] ds:pt-[var(--spacing-md)] ds:pb-[var(--spacing-md)] ' +\n // Mirrors the kit Card's `outlined` / `elevated` variant recipes\n // (border + surface + shadow tokens), including the accessible-theme\n // 2px border bump.\n (variant === 'elevated'\n ? 'ds:bg-[var(--card)] ds:border ds:border-[color:var(--card-border)] ds:shadow-[var(--shadow-card)] ds:[.theme-accessible_&]:border-2'\n : 'ds:border ds:border-[color:var(--border)] ds:[.theme-accessible_&]:border-2')\n }\n >\n <span className=\"type-label ds:text-[color:var(--muted-foreground)]\">\n {label}\n </span>\n <span className=\"type-metric ds:[--type-metric-size:var(--font-size-xl)] ds:text-[color:var(--foreground)]\">\n {target}\n </span>\n <span className=\"type-meta ds:text-[color:var(--muted-foreground)]\">\n {now}\n </span>\n {children}\n {status || action ? (\n // One row: the traffic light and whatever affordance the host adds.\n // `mt-auto` pins it to the tile's foot, so a row of tiles stretched to\n // the tallest one lines its chips up instead of leaving a hole.\n <div className=\"ds:mt-auto ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n {status ? (\n <Badge variant={TARGET_STATUS_VARIANT[status]} size=\"sm\" withDot>\n {statusLabel}\n </Badge>\n ) : null}\n {action}\n </div>\n ) : null}\n </div>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — the Diagnosis summary strip */\n/* */\n/* The first thing on the Diagnosis surface, above the view switch and */\n/* therefore above Visit details: one compact row answering \"where is this */\n/* patient now against where we want them\". Four tiles — target weight, */\n/* target BMI, daily energy, protein — the same four the dietitian care */\n/* plan is written in, rendered through the SAME `_shared/target-tile` */\n/* shell so the two surfaces read as one product. */\n/* */\n/* BMI's tile is where the BMI readout moved to. It keeps the kit's */\n/* canonical BMI presentation verbatim (WHO category badge + the shared */\n/* banded gauge from `components/bmi-calculator`); those sit directly */\n/* under the \"Now\" line so the needle reads as an elaboration of the */\n/* MEASURED figure, never of the headline target. */\n/* */\n/* Setting a target is deliberate, not ambient: each tile carries a */\n/* labelled edit button that opens a small popover form (value, unit, */\n/* bounds, Save, Clear). An always-live input on a strip that is read at a */\n/* glance mid-consultation invites a stray scroll-wheel to move a clinical */\n/* goal; the tile itself stays a pure readout and shows only the committed */\n/* value. */\n/* -------------------------------------------------------------------- */\n\nimport type { TFunction } from 'i18next';\nimport { useTranslation } from 'react-i18next';\nimport { bmiCategory } from '../../components/bmi-calculator/bmi';\nimport { TargetTile } from '../_shared/target-tile';\nimport { formatValue, latestParameterValue } from './anamnesis-derive';\nimport { localeOf, parameterLabel } from './anamnesis-format';\nimport { TargetEditor } from './anamnesis-target-editor';\nimport { targetStatus } from './anamnesis-targets';\nimport type { NumericParameterDef, Visit } from './anamnesis-types';\n\n/* ------------------------------ Formatting ------------------------------ */\n\n/** A measured or targeted figure with its unit. The figure follows the app\n * locale; unit symbols are locale-invariant scientific notation, as\n * everywhere else in this pattern. */\nfunction withUnit(\n value: number,\n def: NumericParameterDef,\n locale: string | undefined,\n): string {\n const text = formatValue(value, def.precision, locale);\n return def.unit ? `${text} ${def.unit}` : text;\n}\n\n/* ------------------------------- One tile ------------------------------- */\n\ninterface StripTileProps {\n def: NumericParameterDef;\n visits: readonly Visit[];\n target: number | null;\n t: TFunction;\n onTargetChange: (def: NumericParameterDef, target: number | null) => void;\n}\n\nfunction StripTile({ def, visits, target, t, onTargetChange }: StripTileProps) {\n // `ui.*` namespace — the WHO vocabulary belongs to the shipped BMI\n // component, not to this pattern's story-local `patterns` bundle.\n const { t: tUi } = useTranslation();\n const locale = localeOf(t);\n // The MOST RECENT recording, not the newest visit's cell. A parameter\n // measured at the last appointment but not at this one is still on record,\n // and a tile that called it \"not yet measured\" was answering a question\n // nobody asked — \"where is this patient now\" spans the visits.\n const now = latestParameterValue(visits, def)?.value ?? null;\n const status = targetStatus(now, target, def.key);\n // EVERY tile label states it is a target — the seeded four and any\n // practice-chosen goal alike — via one template over the parameter's\n // effective label (units ride the values, not the label).\n const label = t('anamnesis.targets.tileLabel', {\n name: parameterLabel(def, t),\n });\n // The WHO band describes the CURRENT figure, so it rides the \"Now\" line.\n // A second chip beside the status read as clutter on the one tile that has it.\n const banded = def.computed && now != null;\n const nowLabel =\n now == null\n ? t('anamnesis.targets.nowUnset')\n : banded\n ? t('anamnesis.targets.nowBanded', {\n value: withUnit(now, def, locale),\n band: tUi(`bmiCalculator.category.${bmiCategory(now)}`),\n })\n : t('anamnesis.targets.now', { value: withUnit(now, def, locale) });\n\n return (\n <TargetTile\n variant=\"elevated\"\n label={label}\n target={\n target == null\n ? t('anamnesis.targets.unset')\n : withUnit(target, def, locale)\n }\n now={nowLabel}\n status={status}\n statusLabel={status ? t(`anamnesis.targets.status.${status}`) : undefined}\n action={\n <TargetEditor\n def={def}\n label={label}\n committed={target}\n nowLabel={nowLabel}\n t={t}\n onCommit={(next) => onTargetChange(def, next)}\n />\n }\n />\n );\n}\n\n/* -------------------------------- Props --------------------------------- */\n\nexport interface AnamnesisTargetStripProps {\n /** The record's visits, oldest first. Each tile's \"Now\" is the most recent\n * visit that actually MEASURED its parameter — not the newest visit. */\n visits: readonly Visit[];\n /** The strip's parameters, in order. See `stripParameters`. */\n defs: NumericParameterDef[];\n /** Committed targets by parameter key. */\n targets: Map<string, number>;\n t: TFunction;\n onTargetChange: (def: NumericParameterDef, target: number | null) => void;\n}\n\n/* ------------------------------- Component ------------------------------ */\n\n/** Column count for the tile grid: FOUR PER LINE at most, and never more\n * columns than there are tiles — an empty fourth column left three goals\n * huddled at three-quarters width with a hole beside them. Static class\n * strings, because Tailwind cannot see an interpolated one. */\nfunction gridColumnsClass(count: number): string {\n if (count <= 1) return 'ds:grid-cols-1';\n if (count === 2) return 'ds:grid-cols-2';\n if (count === 3) return 'ds:grid-cols-2 ds:sm:grid-cols-3';\n return 'ds:grid-cols-2 ds:sm:grid-cols-4';\n}\n\nexport function AnamnesisTargetStrip({\n visits,\n defs,\n targets,\n t,\n onTargetChange,\n}: AnamnesisTargetStripProps) {\n if (defs.length === 0) return null;\n return (\n // No wrapper card: the ELEVATED tiles sit directly on the surface as\n // dashboard cards (a card-in-card read as double chrome). The heading\n // stays for the outline and the region name, visually the tiles speak\n // for themselves — every label states it is a target.\n <section\n aria-label={t('anamnesis.targets.title')}\n data-testid=\"anamnesis-target-strip\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <h2 className=\"ds:sr-only\">{t('anamnesis.targets.title')}</h2>\n {/* Same grid as the care plan's nutrition targets, so the plan and the\n record read as one product. */}\n <div\n className={`ds:grid ds:gap-[var(--spacing-md)] ${gridColumnsClass(defs.length)}`}\n >\n {defs.map((def) => (\n <StripTile\n key={def.key}\n def={def}\n visits={visits}\n target={targets.get(def.key) ?? null}\n t={t}\n onTargetChange={onTargetChange}\n />\n ))}\n </div>\n </section>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — compile mode (clinician-facing) */\n/* */\n/* The heart of the demo, and the replacement for the Excel file. Three */\n/* complementary views behind a Tabs switch: */\n/* A. Summary — the patient's returned questionnaire, READ-ONLY: the */\n/* at-a-glance digest, the missing-answer alert, and the full answer */\n/* list one closed disclosure below. Selected on arrival. */\n/* B. Compile — record the current (newest) visit once, no double entry: */\n/* visit meta, any required questionnaire answer that came back blank, */\n/* anthropometrics with a COMPUTED BMI and current-vs-target, a */\n/* many-to-many pathology multi-select, oncological history, therapy, */\n/* blood tests, fasting-mimicking cycles, the nutritional proposal / */\n/* notes, and the annual programme. */\n/* C. Evolution — the parameters-as-rows, visits-as-columns grid with */\n/* deltas + trends, plus a compare-two-visits mode that highlights */\n/* exactly what changed, numeric and non-numeric. */\n/* */\n/* Local, in-memory working state only. */\n/* -------------------------------------------------------------------- */\n\nimport {\n useCallback,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n useEffect,\n} from 'react';\nimport type { TFunction } from 'i18next';\nimport { ChevronDown, Plus, Trash2 } from 'lucide-react';\nimport { Badge } from '../../components/badge';\nimport { Button } from '../../components/button';\nimport { Card } from '../../components/card';\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '../../components/collapsible';\nimport { EmptyState } from '../../components/empty-state';\nimport { FormField } from '../../components/form-field';\nimport { IconButton } from '../../components/icon-button';\nimport { MultiSelect } from '../../components/multi-select';\nimport { NumberInput } from '../../components/number-input';\nimport { RadioGroup, Radio } from '../../components/radio-group';\nimport { Select, type SelectOption } from '../../components/select';\nimport { Tabs } from '../../components/tabs';\nimport { TextArea } from '../../components/text-area';\nimport { TextInput } from '../../components/text-input';\nimport { Timestamp } from '../../components/timestamp';\nimport { DatePicker } from '../../components/date-picker';\nimport {\n allSectionsIncludingArchived,\n assignablePathologyCodes,\n configuredParameters,\n configuredSections,\n isParameterTargetable,\n pathologyLookup,\n type PracticeAnamnesisConfig,\n} from './anamnesis-config';\nimport {\n CALENDAR_DATE_FORMAT,\n deltaInfo,\n formatValue,\n outOfRange,\n parameterValueAt,\n setNumericOnVisit,\n setTargetOnRecord,\n} from './anamnesis-derive';\nimport {\n buildIntakeDigest,\n missingMandatoryAnswers,\n useFieldJump,\n type MissingAnswer,\n} from './anamnesis-digest';\nimport { AnamnesisSummary, TRIGGER_FOCUS_RING } from './anamnesis-summary';\nimport {\n OCCASIONAL_BLOCKS,\n compileBlockDensity,\n} from './anamnesis-compile-blocks';\nimport type { OccasionalBlockId } from './anamnesis-compile-blocks';\nimport type { DisclosureAudience } from './anamnesis-disclosure';\nimport type { AnamnesisExportTab } from './anamnesis-export';\nimport { AnamnesisEvolution, useShownVisitIds } from './anamnesis-evolution';\nimport { AnamnesisExportMenu } from './anamnesis-export-menu';\nimport { AnamnesisField } from './anamnesis-field';\nimport { TargetEditor } from './anamnesis-target-editor';\nimport { AnamnesisTargetStrip } from './anamnesis-target-strip';\nimport { stripParameters } from './anamnesis-targets';\nimport {\n clockSuffix,\n fieldVisible,\n localeOf,\n parameterLabelWithUnit,\n parseCalendarDate,\n pathologyCodeWithLabel,\n pathologyLabel,\n patientAgeLabel,\n sectionLabel,\n toCalendarIso,\n} from './anamnesis-format';\nimport { DeltaIndicator, OutOfRangeBadge } from './anamnesis-indicators';\nimport type {\n AnamnesisRecord,\n IntakeAnswer,\n MedicationEntry,\n NumericParameterDef,\n OpenAnamnesisNote,\n PractitionerOption,\n Visit,\n YesNo,\n} from './anamnesis-types';\n\n/* ------------------------ Sub-block: numeric list ----------------------- */\n\ninterface NumericBlockProps {\n /** Keys whose target is owned by the goals strip — the block still shows\n * the goal beside the measurement but offers no second editor for it.\n * Config-driven: the practice chooses its goals in the Targets tab. */\n stripKeys: ReadonlySet<string>;\n defs: NumericParameterDef[];\n visit: Visit;\n previous?: Visit;\n targets: Map<string, number>;\n t: TFunction;\n onChange: (def: NumericParameterDef, value: number | null) => void;\n /** Make the per-patient target settable for the targetable parameters in\n * this block. Omitted = the target stays the read-only line it has always\n * been (blood tests carry a reference range, not a patient goal). */\n onTargetChange?: (def: NumericParameterDef, target: number | null) => void;\n}\n\n/** Single-visit editable list of numeric parameters (anthropometrics, dietary\n * intake or labs): value input, unit, out-of-range flag, delta vs the previous\n * visit, and — when a target exists — a current-vs-target line.\n *\n * COMPUTED parameters are dropped: there is nothing to type, and BMI (the only\n * one the engine computes) is read in the summary strip at the top of the\n * surface, where it sits beside the targets it is judged against. */\nfunction NumericBlock({\n stripKeys,\n defs,\n visit,\n previous,\n targets,\n t,\n onChange,\n onTargetChange,\n}: NumericBlockProps) {\n const locale = localeOf(t);\n return (\n <div className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:sm:grid-cols-2\">\n {defs\n .filter((def) => !def.computed)\n .map((def) => {\n const value = parameterValueAt(visit, def);\n const prevValue = previous ? parameterValueAt(previous, def) : null;\n const delta = previous ? deltaInfo(value, prevValue, def) : null;\n const flag = outOfRange(value, def.referenceRange);\n const target = targets.get(def.key) ?? null;\n const labelWithUnit = parameterLabelWithUnit(def, t);\n // The strip's goals are set up there; offering a second editor for\n // the same goal on the same screen is how two copies start.\n const settableTarget =\n onTargetChange != null &&\n isParameterTargetable(def.key) &&\n !stripKeys.has(def.key);\n return (\n <div\n key={def.key}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\"\n >\n <FormField label={labelWithUnit}>\n <NumberInput\n value={value}\n mode={(def.precision ?? 0) > 0 ? 'decimal' : 'integer'}\n onChange={(next) => onChange(def, next)}\n />\n </FormField>\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n {flag ? <OutOfRangeBadge flag={flag} t={t} /> : null}\n <DeltaIndicator delta={delta} def={def} t={t} />\n {/* The target is one shared patient goal, read wherever it is\n relevant and set from ONE control — the same popover editor\n the summary strip mounts, never a second affordance. */}\n {settableTarget || target != null ? (\n <span className=\"ds:flex ds:items-center ds:gap-[var(--spacing-2xs)]\">\n <span className=\"type-meta ds:text-[color:var(--muted-foreground)]\">\n {target == null\n ? t('anamnesis.targets.unset')\n : t('anamnesis.grid.target', {\n value: formatValue(target, def.precision, locale),\n unit: def.unit ?? '',\n })}\n </span>\n {settableTarget ? (\n <TargetEditor\n def={def}\n label={labelWithUnit}\n committed={target}\n nowLabel={t('anamnesis.targets.now', {\n value:\n `${formatValue(value, def.precision, locale)} ${def.unit ?? ''}`.trim(),\n })}\n t={t}\n onCommit={(next) => onTargetChange?.(def, next)}\n />\n ) : null}\n </span>\n ) : null}\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n\n/* ------------------------------ Block shell ----------------------------- */\n\nfunction Block({\n titleKey,\n t,\n defaultOpen = true,\n fill,\n fillKind = 'recorded',\n flagged = 0,\n open,\n onOpenChange,\n children,\n}: {\n titleKey: string;\n t: TFunction;\n /** Arrival state for an uncontrolled block. See `anamnesis-compile-blocks`. */\n defaultOpen?: boolean;\n /** Entries already recorded here, named in the header so a folded block never\n * hides that it holds something. `undefined` = no summary. */\n fill?: number | null;\n /** What `fill` counts. `recorded` is history already captured; `outstanding`\n * is work left to do, where \"12 recorded\" would read as the opposite. */\n fillKind?: 'recorded' | 'outstanding';\n /** Of that fill, how many sit outside their reference range. Folding must\n * never be able to hide a flagged value, so the count rides the header. */\n flagged?: number;\n /** Controlled only where something outside has to be able to open it (the\n * jump to a missing answer). Omitted = uncontrolled. */\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n children: React.ReactNode;\n}) {\n // A titled, collapsible section. The compile surface wraps the whole Tabs\n // block in a single elevated Card (like the intake surface and the\n // plan-context hero cards), so each section sits ON that card rather than\n // being its own card. The heading stays an h2 (for heading order) that\n // contains the toggle button, per the accordion-header ARIA pattern; the fill\n // badge sits inside the trigger, so its text is part of the toggle's\n // accessible name and is announced with it.\n return (\n <Collapsible\n variant=\"default\"\n defaultOpen={open === undefined ? defaultOpen : undefined}\n open={open}\n onOpenChange={onOpenChange}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n <h2 className=\"type-title-section ds:m-0 ds:text-[color:var(--foreground)]\">\n <CollapsibleTrigger\n className={\n 'ds:flex ds:w-full ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)] ds:text-start' +\n TRIGGER_FOCUS_RING\n }\n >\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n {t(titleKey)}\n {fill == null ? null : (\n <Badge\n variant={\n fillKind === 'outstanding' && fill > 0 ? 'warning' : 'neutral'\n }\n size=\"sm\"\n >\n {fillKind === 'outstanding'\n ? fill > 0\n ? t('anamnesis.compile.blockOutstanding', { count: fill })\n : t('anamnesis.compile.blockSettled')\n : fill > 0\n ? t('anamnesis.compile.blockFilled', { count: fill })\n : t('anamnesis.compile.blockEmpty')}\n </Badge>\n )}\n {flagged > 0 ? (\n <Badge variant=\"warning\" size=\"sm\">\n {t('anamnesis.compile.blockFlagged', { count: flagged })}\n </Badge>\n ) : null}\n </span>\n <ChevronDown\n aria-hidden=\"true\"\n className=\"ds:size-5 ds:shrink-0 ds:text-[color:var(--muted-foreground)] ds:transition-transform ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none ds:[[data-state=open]_&]:rotate-180\"\n />\n </CollapsibleTrigger>\n </h2>\n <CollapsibleContent\n aria-label={t(titleKey)}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n {children}\n </CollapsibleContent>\n </Collapsible>\n );\n}\n\n/* -------------------------------- Props --------------------------------- */\n\n/** The three Diagnosis views. Also the three export tabs — one vocabulary. */\nexport type AnamnesisCompileView = AnamnesisExportTab;\n\nexport interface AnamnesisCompileProps {\n record: AnamnesisRecord;\n t: TFunction;\n /** Mount flush inside a host section tab (drops the full-page chrome + the\n * patient-name page heading — the host shows the patient banner). */\n embedded?: boolean;\n /** The practice's configured vocabulary. Omitted = the kit-seeded default. */\n config?: PracticeAnamnesisConfig;\n /** A per-patient target was set or cleared (`null` clears it). The surface\n * applies it to its own working record either way; this is the seam a\n * platform host persists through — and the one place a shared target could\n * be reconciled with the care plan, which no story can do. */\n onTargetChange?: (parameterKey: string, target: number | null) => void;\n /** Host status chips rendered at the surface header's end — the slot a\n * platform host uses to fold its OWN record state (signature status,\n * expiry, save feedback, a renew affordance) into the section instead of\n * bolting a second bar above it. Content is host-owned and already\n * translated. The surface itself claims no save state. */\n statusSlot?: ReactNode;\n /** Omit the nutrition-targets strip above the record card — for hosts\n * that present the record without the goals (the isolated single-section\n * demo). Default false: the strip renders. Target editors inside the\n * record blocks are unaffected. */\n hideTargetStrip?: boolean;\n /** Draw the evolution view as one table per anamnesis type (visits\n * grouped by `sourceLabel`). Default false: one grid over every visit. */\n partitionBySource?: boolean;\n /** Route the missing-answer jump to a host questionnaire surface instead\n * of the internal Compila gaps block (e.g. the platform island's fill\n * view). Receives the missing answer the user asked to fix. */\n onMissingAnswerJump?: (missing: MissingAnswer) => void;\n /** Every edit to the working record (visit fields, pathologies, therapy,\n * events, targets) — the persistence seam for hosts that store visit\n * data. Fires AFTER the change lands in state, with the full record;\n * hosts debounce and diff. NOT called for the initial mount. */\n onRecordChange?: (record: AnamnesisRecord) => void;\n /** The practice's operators, offered in the visit's Practitioner select.\n * Host-supplied because the roster is live platform data, not practice\n * vocabulary — it must never be written into the saved config. Omitted or\n * empty leaves a free-text input, so kit mounts without a roster keep\n * working. */\n practitioners?: PractitionerOption[];\n /** The calendar date (ISO) a NEW follow-up visit is created on. A host\n * passes its \"today\"; defaults to the latest visit's date so kit demos\n * and tests stay deterministic (the surface deliberately never reads the\n * wall clock). The date field is editable either way. */\n newVisitDateIso?: string;\n /** The host's side panel, forwarded to the Evolution view. Omitted = the\n * evolution surface reads notes in place. */\n onOpenNote?: OpenAnamnesisNote;\n /** Mount on this view instead of Summary. Demo/story hook only — Chromatic\n * skips play functions, so a click-selected tab is never snapshotted. */\n defaultView?: AnamnesisCompileView;\n /** Mount with the export menu open. Demo/story hook only — Chromatic skips\n * play functions, so a click-opened menu is never snapshotted. */\n defaultExportMenuOpen?: boolean;\n /** Mount with the share preview open. Demo/story hook, same reason. */\n defaultShareOpen?: boolean;\n /** Mount the export control on this audience. Demo/story hook. */\n defaultExportAudience?: DisclosureAudience;\n}\n\n/* ------------------------------- Component ------------------------------ */\n\nexport function AnamnesisCompile({\n record: initial,\n t,\n embedded = false,\n config,\n onTargetChange,\n hideTargetStrip = false,\n partitionBySource = false,\n statusSlot,\n onOpenNote,\n onMissingAnswerJump,\n onRecordChange,\n practitioners,\n newVisitDateIso,\n defaultView = 'summary',\n defaultExportMenuOpen = false,\n defaultShareOpen = false,\n defaultExportAudience = 'clinician',\n}: AnamnesisCompileProps) {\n const [record, setRecord] = useState<AnamnesisRecord>(() =>\n structuredClone(initial),\n );\n\n // Change seam: report every record edit AFTER it lands in state. The\n // initial mount is skipped — nothing changed yet.\n const recordChangeSeenRef = useRef(false);\n useEffect(() => {\n if (!recordChangeSeenRef.current) {\n recordChangeSeenRef.current = true;\n return;\n }\n onRecordChange?.(record);\n // onRecordChange identity changes must not re-fire for the same record.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [record]);\n const nextId = useRef(0);\n\n const { patient, visits } = record;\n const latest: Visit | undefined = visits[visits.length - 1];\n const previous = visits.length > 1 ? visits[visits.length - 2] : undefined;\n const targets = useMemo(\n () =>\n new Map(record.targets.map((x) => [x.parameterKey, x.target] as const)),\n [record.targets],\n );\n\n // CAPTURE surfaces take the live vocabulary; the review of already-recorded\n // answers takes the full one, or archiving a question would erase answers.\n const anthroDefs = useMemo(\n () => configuredParameters(config, 'anthropometric'),\n [config],\n );\n const dietaryDefs = useMemo(\n () => configuredParameters(config, 'dietary'),\n [config],\n );\n const labDefs = useMemo(() => configuredParameters(config, 'lab'), [config]);\n // The summary strip's four: target weight, target BMI, daily energy, protein.\n const stripDefs = useMemo(() => stripParameters(config), [config]);\n const stripKeys = useMemo(\n () => new Set(stripDefs.map((def) => def.key)),\n [stripDefs],\n );\n\n // Arrival density: the every-visit blocks open, the occasional ones folded\n // with a fill summary in their header. A default, not a control. `labDefs`\n // is the list the Blood tests block renders, so its count matches.\n const density = useMemo(\n () => compileBlockDensity(latest, labDefs),\n [latest, labDefs],\n );\n\n // Held HERE, not in each block: Radix Tabs unmounts an inactive panel, so an\n // uncontrolled block would re-fold on every Compile → Evolution → Compile\n // round trip. Seeded once from the arrival policy; her own toggles win after.\n const [occasionalOpen, setOccasionalOpen] = useState<\n Record<OccasionalBlockId, boolean>\n >(() => {\n const seed = compileBlockDensity(latest, labDefs);\n const state = {} as Record<OccasionalBlockId, boolean>;\n for (const id of OCCASIONAL_BLOCKS) state[id] = seed[id].open;\n return state;\n });\n const setBlockOpen = useCallback(\n (id: OccasionalBlockId) => (open: boolean) =>\n setOccasionalOpen((prev) => ({ ...prev, [id]: open })),\n [],\n );\n const historySections = useMemo(\n () => allSectionsIncludingArchived(config),\n [config],\n );\n // Only a question the practice still ASKS can be missing an answer. Demanding\n // one it archived is a gap nobody can close — the intake surface no longer\n // renders the field, so the alert would never clear.\n const liveSections = useMemo(() => configuredSections(config), [config]);\n const pathologies = useMemo(() => pathologyLookup(config), [config]);\n\n // Summary is the arrival tab: the questionnaire is read before the visit is\n // recorded, and the missing-answer alert has to be on screen when she opens\n // the record rather than behind an unselected tab. Controlled, because the\n // alert's jump crosses from Summary to Compile.\n const [view, setView] = useState<AnamnesisCompileView>(defaultView);\n const [gapsOpen, setGapsOpen] = useState(true);\n // Mirrors the evolution picker so the export control can file the view that\n // is on screen.\n const [shownVisitIds, trackShownVisits] = useShownVisitIds();\n const { containerRef, requestJump } = useFieldJump();\n const readAnswer = useCallback(\n (key: string) => record.intake?.answers[key]?.value,\n [record.intake],\n );\n const digest = useMemo(\n () => buildIntakeDigest(historySections, readAnswer, patient.sex, t),\n [historySections, readAnswer, patient.sex, t],\n );\n const missingAnswers = useMemo(\n () => missingMandatoryAnswers(liveSections, readAnswer, patient.sex, t),\n [liveSections, readAnswer, patient.sex, t],\n );\n // Frozen at mount, deliberately. The Compile tab's gap block is the visit's\n // to-do list, so a field must not vanish from under the cursor the instant\n // its answer stops being blank — the live count on Summary is the feedback.\n const [gapKeys] = useState(() => new Set(missingAnswers.map((m) => m.key)));\n\n // Recording an answer is data entry, so the jump crosses to Compile, opens\n // the gap block and lands focus — never a collapsed or unmounted target.\n const jumpToMissing = (target: MissingAnswer) => {\n // A host with its own questionnaire surface (e.g. the platform island's\n // fill view) routes the jump there instead of the Compila gaps block.\n if (onMissingAnswerJump) {\n onMissingAnswerJump(target);\n return;\n }\n setView('compile');\n setGapsOpen(true);\n requestJump(target.key);\n };\n\n // A record with no visit is a different screen, not a variant of the form:\n // there is nothing to compile against, so say so rather than render inputs\n // that write nowhere. Every hook above has already run.\n if (!latest) {\n return (\n <CompileShell embedded={embedded}>\n <Card variant=\"elevated\">\n <Card.Body>\n <EmptyState\n variant=\"first-use\"\n size=\"sm\"\n title={t('anamnesis.empty.noRecord.title')}\n description={t('anamnesis.empty.noRecord.description')}\n />\n </Card.Body>\n </Card>\n </CompileShell>\n );\n }\n\n /* -------- working-state setters -------- */\n\n const patchLatest = (mut: (v: Visit) => Visit) => {\n setRecord((r) => {\n if (r.visits.length === 0) return r;\n const next = r.visits.slice();\n next[next.length - 1] = mut(next[next.length - 1]);\n return { ...r, visits: next };\n });\n };\n\n const onNumericChange = (def: NumericParameterDef, value: number | null) =>\n patchLatest((v) => setNumericOnVisit(v, def, value));\n\n /** Write to the visit the cell belongs to, never to whatever is last. */\n const onGridCellChange = (\n visit: Visit,\n def: NumericParameterDef,\n value: number | null,\n ) =>\n setRecord((r) => {\n return {\n ...r,\n visits: r.visits.map((v) =>\n v.id === visit.id ? setNumericOnVisit(v, def, value) : v,\n ),\n };\n });\n\n /** Targets belong to the RECORD, not to a visit — a goal is not a\n * measurement taken on a day. Same working-state idiom as the cell edits. */\n const setTarget = (def: NumericParameterDef, target: number | null) => {\n setRecord((r) => setTargetOnRecord(r, def.key, target));\n onTargetChange?.(def.key, target);\n };\n\n const setPathologies = (codes: string[]) =>\n patchLatest((v) => ({ ...v, pathologyCodes: codes }));\n\n const updateTherapy = (id: string, patch: Partial<MedicationEntry>) =>\n patchLatest((v) => ({\n ...v,\n therapy: v.therapy.map((m) => (m.id === id ? { ...m, ...patch } : m)),\n }));\n\n const removeTherapy = (id: string) =>\n patchLatest((v) => ({\n ...v,\n therapy: v.therapy.filter((m) => m.id !== id),\n }));\n\n const addTherapy = () => {\n nextId.current += 1;\n const id = `new-${nextId.current}`;\n patchLatest((v) => ({\n ...v,\n therapy: [...v.therapy, { id, name: '', dose: '', kind: 'medication' }],\n }));\n };\n\n /** Append a NEW empty follow-up visit and make it the edited \"latest\" —\n * without this the record type supports many visits but the surface offers\n * no way to ever gain one, so Evolution could never grow a second point in\n * a live host. Cloned EMPTY on purpose: measurements are taken AT the\n * visit, so carrying the previous visit's numbers forward would fabricate\n * data. Lands through the same `onRecordChange` seam as every other edit —\n * a persisting host saves it as a new visit row. */\n const addFollowUpVisit = () => {\n nextId.current += 1;\n const id = `new-visit-${nextId.current}`;\n setRecord((r) => {\n const last = r.visits[r.visits.length - 1];\n if (!last) return r;\n const visit: Visit = {\n id,\n visitType: 'followUp',\n dateIso: newVisitDateIso ?? last.dateIso,\n anthropometrics: {\n weightKg: null,\n heightCm: null,\n waistCm: null,\n hipsCm: null,\n armCm: null,\n phaseAngleDeg: null,\n },\n labs: [],\n pathologyCodes: [],\n therapy: [],\n fmdCycles: [],\n };\n return { ...r, visits: [...r.visits, visit] };\n });\n };\n\n const updateIntakeAnswer = (key: string, answer: IntakeAnswer) => {\n setRecord((r) => ({\n ...r,\n intake: {\n ...r.intake,\n answers: {\n ...r.intake?.answers,\n [key]: { value: answer, origin: 'clinician' },\n },\n },\n }));\n };\n\n /* -------- pathology multi-select options (grouped by family) -------- */\n\n // Resolved through the config LOOKUP, not the shipped constant — a\n // practice-added code has no entry in the kit's map and read `.parentCode`\n // off `undefined`.\n const pathologyOptions: SelectOption[] = assignablePathologyCodes(config).map(\n (code) => {\n const entry = pathologies[code];\n const parent = entry?.parentCode;\n return {\n value: code,\n label: pathologyCodeWithLabel(code, t, entry),\n group: parent\n ? pathologyLabel(parent, t, pathologies[parent])\n : t('anamnesis.pathology.groupGeneral'),\n };\n },\n );\n\n const latestOncological = latest.oncological ?? {};\n const latestAnnual = latest.annualProgramme ?? {\n proposed: false,\n accepted: false,\n };\n\n /* --------------------------------- render -------------------------------- */\n\n const inner = (\n <>\n {/* Header row: the page heading (standalone only) and the host's\n status chips. The surface claims NO save state of its own — the old\n mock autosave chip promised persistence nothing provided; a host\n with real persistence renders its own state via `statusSlot`. The\n row disappears entirely when it has nothing to show. */}\n {!embedded || statusSlot ? (\n <div className=\"ds:flex ds:flex-wrap ds:items-end ds:justify-between ds:gap-[var(--spacing-sm)]\">\n {embedded ? (\n <span />\n ) : (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <h1 className=\"type-title-page ds:m-0 ds:text-[color:var(--foreground)]\">\n {patient.firstName} {patient.lastName}\n </h1>\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {patientAgeLabel(record, t)}\n {' · '}\n {t('anamnesis.compile.visitCount', { visits: visits.length })}\n </p>\n </div>\n )}\n {statusSlot ? (\n <span\n data-testid=\"anamnesis-status-slot\"\n className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\"\n >\n {statusSlot}\n </span>\n ) : null}\n </div>\n ) : null}\n\n {/* One elevated Card holds the view switch + its content, so the compile\n surface reads as a contained record (matching the intake surface and\n the plan-context hero cards) rather than a segmented tab strip and a\n stack of section cards floating on the app-shell background. */}\n {/* The summary strip — first on the surface and a SIBLING of the record\n card, not nested inside it: \"where is this patient against her goals\"\n is its own object, on screen on arrival and while she moves between\n the three views. */}\n {hideTargetStrip ? null : (\n <AnamnesisTargetStrip\n visits={visits}\n defs={stripDefs}\n targets={targets}\n t={t}\n onTargetChange={setTarget}\n />\n )}\n\n <Card variant=\"elevated\">\n <Card.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]\">\n <Tabs\n value={view}\n onValueChange={(next) => setView(next as typeof view)}\n >\n {/* ONE export/share control for the whole surface, sitting beside\n the view switch it acts on — never one per table. A sibling of\n Tabs.List, not a child: a tablist holds tabs only. */}\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <Tabs.List aria-label={t('anamnesis.compile.viewsLabel')}>\n <Tabs.Trigger value=\"summary\">\n {t('anamnesis.compile.tabSummary')}\n </Tabs.Trigger>\n <Tabs.Trigger value=\"compile\">\n {t('anamnesis.compile.tabCompile')}\n </Tabs.Trigger>\n <Tabs.Trigger value=\"evolution\">\n {t('anamnesis.compile.tabEvolution')}\n </Tabs.Trigger>\n </Tabs.List>\n <AnamnesisExportMenu\n tab={view}\n record={record}\n t={t}\n config={config}\n shownVisitIds={shownVisitIds}\n defaultOpen={defaultExportMenuOpen}\n defaultShareOpen={defaultShareOpen}\n defaultAudience={defaultExportAudience}\n />\n </div>\n\n {/* -------------------- Summary view -------------------- */}\n <Tabs.Content value=\"summary\">\n <div className=\"ds:pt-[var(--spacing-md)]\">\n <AnamnesisSummary\n intake={record.intake}\n sections={historySections}\n sex={patient.sex}\n digest={digest}\n missing={missingAnswers}\n onJump={jumpToMissing}\n t={t}\n />\n </div>\n </Tabs.Content>\n\n {/* -------------------- Compile view -------------------- */}\n <Tabs.Content value=\"compile\">\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)] ds:pt-[var(--spacing-md)]\">\n {/* Visit meta */}\n <Block titleKey=\"anamnesis.section.visitMeta\" t={t}>\n <div className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:sm:grid-cols-2\">\n <FormField label={t('anamnesis.field.visitType.label')}>\n <Select\n options={[\n {\n value: 'first',\n label: t('anamnesis.visitType.first'),\n },\n {\n value: 'followUp',\n label: t('anamnesis.visitType.followUp'),\n },\n ]}\n value={latest.visitType}\n onValueChange={(next) =>\n patchLatest((v) => ({\n ...v,\n visitType: (next ||\n 'followUp') as Visit['visitType'],\n }))\n }\n />\n </FormField>\n <FormField label={t('anamnesis.field.practitioner.label')}>\n {/* A practice picks the operator who saw the patient —\n free text only survives where the host has no\n roster to offer (kit demos, tests). */}\n {practitioners && practitioners.length > 0 ? (\n <Select\n options={practitioners}\n value={latest.practitioner ?? ''}\n onValueChange={(next) =>\n patchLatest((v) => ({\n ...v,\n practitioner: next || undefined,\n }))\n }\n />\n ) : (\n <TextInput\n value={latest.practitioner ?? ''}\n onChange={(e) =>\n patchLatest((v) => ({\n ...v,\n practitioner: e.target.value,\n }))\n }\n />\n )}\n </FormField>\n <FormField label={t('anamnesis.header.visitDate')}>\n {/* A real input, like its three siblings — a bare\n readout beside them read as broken. Parsed and\n written as a LOCAL calendar date so the day cannot\n shift by a timezone; a visit stamped with a time\n keeps it, since this control edits only the day. */}\n <DatePicker\n value={parseCalendarDate(latest.dateIso)}\n onChange={(next) =>\n next &&\n patchLatest((v) => ({\n ...v,\n dateIso:\n toCalendarIso(next) + clockSuffix(v.dateIso),\n }))\n }\n />\n </FormField>\n </div>\n {/* The way a record GAINS a visit — beside the visit date\n it seeds. The fresh visit becomes the edited latest;\n everything below now writes to it. */}\n <div>\n <Button\n intent=\"outline\"\n size=\"sm\"\n startIcon={<Plus aria-hidden=\"true\" />}\n data-testid=\"anamnesis-add-visit\"\n onClick={addFollowUpVisit}\n >\n {t('anamnesis.compile.addFollowUpVisit')}\n </Button>\n </div>\n </Block>\n\n {/* Questionnaire gaps — the ONLY intake content on this tab.\n The answers themselves are read on Summary; what is left\n here is the data entry, i.e. what she fills in at the visit.\n Absent gaps, the block does not render at all. */}\n {gapKeys.size > 0 ? (\n <Block\n titleKey=\"anamnesis.section.intakeGaps\"\n t={t}\n open={gapsOpen}\n onOpenChange={setGapsOpen}\n fill={missingAnswers.length}\n fillKind=\"outstanding\"\n >\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.compile.gapsIntro')}\n </p>\n <div\n ref={containerRef}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]\"\n >\n {liveSections.map((section) => {\n const shown = section.fields\n .filter((f) => fieldVisible(f, patient.sex))\n .filter((f) => gapKeys.has(f.key));\n if (shown.length === 0) return null;\n return (\n <div\n key={section.key}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n <h3 className=\"type-title-item ds:m-0 ds:text-[color:var(--foreground)]\">\n {sectionLabel(section, t)}\n </h3>\n {shown.map((field) => {\n const sourced = record.intake?.answers[field.key];\n return (\n <AnamnesisField\n key={field.key}\n def={field}\n answer={sourced?.value}\n origin={sourced?.origin}\n showOrigin\n onChange={(a) =>\n updateIntakeAnswer(field.key, a)\n }\n t={t}\n />\n );\n })}\n </div>\n );\n })}\n </div>\n </Block>\n ) : null}\n\n {/* Anthropometrics */}\n <Block titleKey=\"anamnesis.section.anthropometrics\" t={t}>\n {/* BMI used to be a cell in this grid. It is computed, not\n typed, so it moved to the summary strip beside the\n targets it is judged against — said here so its absence\n from the block that feeds it is never a mystery. */}\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.compile.bmiInStrip')}\n </p>\n <NumericBlock\n stripKeys={stripKeys}\n defs={anthroDefs}\n visit={latest}\n previous={previous}\n targets={targets}\n t={t}\n onChange={onNumericChange}\n onTargetChange={setTarget}\n />\n </Block>\n\n {/* Dietary intake — what the patient eats, estimated at every\n visit. Its own block because it is neither a measurement of\n the body nor a blood result. Rendered only where the\n practice configured it. */}\n {dietaryDefs.length > 0 ? (\n <Block titleKey=\"anamnesis.section.dietary\" t={t}>\n <NumericBlock\n stripKeys={stripKeys}\n defs={dietaryDefs}\n visit={latest}\n previous={previous}\n targets={targets}\n t={t}\n onChange={onNumericChange}\n onTargetChange={setTarget}\n />\n </Block>\n ) : null}\n\n {/* Pathologies — many-to-many coded multi-select */}\n <Block titleKey=\"anamnesis.section.pathologies\" t={t}>\n <FormField\n label={t('anamnesis.compile.pathologiesLabel')}\n description={t('anamnesis.compile.pathologiesHelp')}\n >\n <MultiSelect\n options={pathologyOptions}\n value={latest.pathologyCodes}\n allowClear\n placeholder={t(\n 'anamnesis.compile.pathologiesPlaceholder',\n )}\n onChange={setPathologies}\n />\n </FormField>\n </Block>\n\n {/* Oncological history */}\n <Block\n titleKey=\"anamnesis.section.oncological\"\n t={t}\n open={occasionalOpen.oncological}\n onOpenChange={setBlockOpen('oncological')}\n fill={density.oncological.fill}\n >\n <div className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:sm:grid-cols-2\">\n <FormField label={t('anamnesis.field.tumourType.label')}>\n <TextInput\n value={latestOncological.tumourType ?? ''}\n onChange={(e) =>\n patchLatest((v) => ({\n ...v,\n oncological: {\n ...v.oncological,\n tumourType: e.target.value,\n },\n }))\n }\n />\n </FormField>\n <FormField label={t('anamnesis.field.stage.label')}>\n <TextInput\n value={latestOncological.stage ?? ''}\n onChange={(e) =>\n patchLatest((v) => ({\n ...v,\n oncological: {\n ...v.oncological,\n stage: e.target.value,\n },\n }))\n }\n />\n </FormField>\n <RadioGroup\n label={t('anamnesis.field.metastases.label')}\n variant=\"horizontal\"\n value={latestOncological.metastases?.present ?? 'unknown'}\n onValueChange={(next) =>\n patchLatest((v) => ({\n ...v,\n oncological: {\n ...v.oncological,\n metastases: {\n present: next as YesNo,\n site: v.oncological?.metastases?.site,\n },\n },\n }))\n }\n >\n <Radio value=\"yes\" label={t('anamnesis.common.yes')} />\n <Radio value=\"no\" label={t('anamnesis.common.no')} />\n <Radio\n value=\"unknown\"\n label={t('anamnesis.common.notSure')}\n />\n </RadioGroup>\n <FormField\n label={t('anamnesis.field.treatmentStatus.label')}\n >\n <TextInput\n value={latestOncological.treatmentStatus ?? ''}\n onChange={(e) =>\n patchLatest((v) => ({\n ...v,\n oncological: {\n ...v.oncological,\n treatmentStatus: e.target.value,\n },\n }))\n }\n />\n </FormField>\n </div>\n </Block>\n\n {/* Therapy & supplements */}\n <Block titleKey=\"anamnesis.section.therapy\" t={t}>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {latest.therapy.length === 0 ? (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.compile.noTherapy')}\n </p>\n ) : (\n latest.therapy.map((entry) => (\n <div\n key={entry.id}\n className=\"ds:flex ds:flex-wrap ds:items-end ds:gap-[var(--spacing-sm)]\"\n >\n <div className=\"ds:grow\">\n <FormField\n label={t('anamnesis.field.medName.label')}\n >\n <TextInput\n value={entry.name}\n onChange={(e) =>\n updateTherapy(entry.id, {\n name: e.target.value,\n })\n }\n />\n </FormField>\n </div>\n <FormField label={t('anamnesis.field.medDose.label')}>\n <TextInput\n value={entry.dose ?? ''}\n onChange={(e) =>\n updateTherapy(entry.id, {\n dose: e.target.value,\n })\n }\n />\n </FormField>\n <Badge\n variant={\n entry.kind === 'medication' ? 'info' : 'neutral'\n }\n size=\"md\"\n >\n {t(`anamnesis.medKind.${entry.kind}`)}\n </Badge>\n <IconButton\n icon={<Trash2 aria-hidden=\"true\" />}\n intent=\"ghost\"\n aria-label={t('anamnesis.compile.removeTherapy', {\n name: entry.name,\n })}\n onClick={() => removeTherapy(entry.id)}\n />\n </div>\n ))\n )}\n <div>\n <Button\n intent=\"outline\"\n size=\"sm\"\n startIcon={<Plus aria-hidden=\"true\" />}\n onClick={addTherapy}\n >\n {t('anamnesis.compile.addTherapy')}\n </Button>\n </div>\n </div>\n </Block>\n\n {/* Blood tests */}\n <Block\n titleKey=\"anamnesis.section.labs\"\n t={t}\n open={occasionalOpen.labs}\n onOpenChange={setBlockOpen('labs')}\n fill={density.labs.fill}\n flagged={density.labs.flagged}\n >\n <NumericBlock\n stripKeys={stripKeys}\n defs={labDefs}\n visit={latest}\n previous={previous}\n targets={targets}\n t={t}\n onChange={onNumericChange}\n />\n </Block>\n\n {/* Fasting-mimicking programme cycles */}\n <Block\n titleKey=\"anamnesis.section.fmd\"\n t={t}\n open={occasionalOpen.fmd}\n onOpenChange={setBlockOpen('fmd')}\n fill={density.fmd.fill}\n >\n {latest.fmdCycles.length === 0 ? (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.compile.noFmd')}\n </p>\n ) : (\n <ul className=\"ds:m-0 ds:flex ds:list-none ds:flex-col ds:gap-[var(--spacing-sm)] ds:p-0\">\n {latest.fmdCycles.map((cycle) => (\n <li\n key={cycle.cycleNumber}\n className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]\"\n >\n <span className=\"type-label ds:text-[color:var(--foreground)]\">\n {t('anamnesis.compile.cycleNumber', {\n number: cycle.cycleNumber,\n })}\n </span>\n <span className=\"type-meta ds:text-[color:var(--muted-foreground)]\">\n <Timestamp\n value={cycle.startDateIso}\n format=\"absolute\"\n shape=\"bare\"\n absoluteFormat={CALENDAR_DATE_FORMAT}\n />\n </span>\n <Badge\n variant={cycle.completed ? 'success' : 'warning'}\n size=\"sm\"\n withDot\n >\n {cycle.completed\n ? t('anamnesis.compile.cycleCompleted')\n : t('anamnesis.compile.cycleInProgress')}\n </Badge>\n </li>\n ))}\n </ul>\n )}\n </Block>\n\n {/* Nutritional proposal + clinical notes */}\n <Block titleKey=\"anamnesis.section.proposal\" t={t}>\n <FormField\n label={t('anamnesis.field.nutritionalProposal.label')}\n >\n <TextArea\n value={latest.nutritionalProposal ?? ''}\n autoResize\n minRows={2}\n onChange={(e) =>\n patchLatest((v) => ({\n ...v,\n nutritionalProposal: e.target.value,\n }))\n }\n />\n </FormField>\n <FormField label={t('anamnesis.field.clinicalNotes.label')}>\n <TextArea\n value={latest.clinicalNotes ?? ''}\n autoResize\n minRows={2}\n onChange={(e) =>\n patchLatest((v) => ({\n ...v,\n clinicalNotes: e.target.value,\n }))\n }\n />\n </FormField>\n </Block>\n\n {/* Annual programme */}\n <Block\n titleKey=\"anamnesis.section.annual\"\n t={t}\n open={occasionalOpen.annual}\n onOpenChange={setBlockOpen('annual')}\n fill={density.annual.fill}\n >\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <RadioGroup\n label={t('anamnesis.field.annualProposed.label')}\n variant=\"horizontal\"\n value={latestAnnual.proposed ? 'yes' : 'no'}\n onValueChange={(next) =>\n patchLatest((v) => ({\n ...v,\n annualProgramme: {\n proposed: next === 'yes',\n accepted: v.annualProgramme?.accepted ?? false,\n declineReason: v.annualProgramme?.declineReason,\n },\n }))\n }\n >\n <Radio value=\"yes\" label={t('anamnesis.common.yes')} />\n <Radio value=\"no\" label={t('anamnesis.common.no')} />\n </RadioGroup>\n <RadioGroup\n label={t('anamnesis.field.annualAccepted.label')}\n variant=\"horizontal\"\n value={latestAnnual.accepted ? 'yes' : 'no'}\n onValueChange={(next) =>\n patchLatest((v) => ({\n ...v,\n annualProgramme: {\n proposed: v.annualProgramme?.proposed ?? false,\n accepted: next === 'yes',\n declineReason: v.annualProgramme?.declineReason,\n },\n }))\n }\n >\n <Radio value=\"yes\" label={t('anamnesis.common.yes')} />\n <Radio value=\"no\" label={t('anamnesis.common.no')} />\n </RadioGroup>\n {!latestAnnual.accepted ? (\n <FormField\n label={t('anamnesis.field.annualDeclineReason.label')}\n >\n <TextArea\n value={latestAnnual.declineReason ?? ''}\n autoResize\n minRows={2}\n onChange={(e) =>\n patchLatest((v) => ({\n ...v,\n annualProgramme: {\n proposed: v.annualProgramme?.proposed ?? false,\n accepted: v.annualProgramme?.accepted ?? false,\n declineReason: e.target.value,\n },\n }))\n }\n />\n </FormField>\n ) : null}\n </div>\n </Block>\n </div>\n </Tabs.Content>\n\n {/* -------------------- Evolution view -------------------- */}\n <Tabs.Content value=\"evolution\">\n <div className=\"ds:pt-[var(--spacing-md)]\">\n <Block titleKey=\"anamnesis.section.evolution\" t={t}>\n <AnamnesisEvolution\n record={record}\n t={t}\n editable\n config={config}\n framed={false}\n onCellChange={onGridCellChange}\n onVisitSelectionChange={trackShownVisits}\n onOpenNote={onOpenNote}\n partitionBySource={partitionBySource}\n />\n </Block>\n </div>\n </Tabs.Content>\n </Tabs>\n </Card.Body>\n </Card>\n </>\n );\n\n return <CompileShell embedded={embedded}>{inner}</CompileShell>;\n}\n\n/** The surface's page chrome, shared by the record and its empty state. */\nfunction CompileShell({\n embedded,\n children,\n}: {\n embedded: boolean;\n children: React.ReactNode;\n}) {\n if (embedded) {\n return (\n <div className=\"ds:flex ds:w-full ds:flex-col ds:gap-[var(--spacing-lg)]\">\n {children}\n </div>\n );\n }\n return (\n <div className=\"ds:min-h-[100dvh] ds:w-full ds:bg-[color:var(--app-shell-background)] ds:py-[var(--spacing-lg)]\">\n <div className=\"ds:mx-auto ds:flex ds:w-full ds:max-w-[76rem] ds:flex-col ds:gap-[var(--spacing-lg)] ds:px-[var(--spacing-md)]\">\n {children}\n </div>\n </div>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — intake mode (patient-facing) */\n/* */\n/* The pre-visit questionnaire the patient completes themselves via a */\n/* link. Only patient-answerable questions (no labs, no clinician-only */\n/* measurements). A read-only visit header, an overall progress bar, free */\n/* in-page section navigation via a disclosure Accordion (any section */\n/* reachable at any time), and sex-conditional fields. Answers live in */\n/* memory and are recorded on submit — there is no draft save. */\n/* -------------------------------------------------------------------- */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport type { TFunction } from 'i18next';\nimport { SendHorizontal } from 'lucide-react';\nimport {\n Accordion,\n AccordionItem,\n AccordionTrigger,\n AccordionContent,\n} from '../../components/accordion';\nimport { Button } from '../../components/button';\nimport { Card } from '../../components/card';\nimport { DescriptionList } from '../../components/description-list';\nimport { EmptyState } from '../../components/empty-state';\nimport { Progress } from '../../components/progress';\nimport { Timestamp } from '../../components/timestamp';\nimport {\n configuredSections,\n type PracticeAnamnesisConfig,\n} from './anamnesis-config';\nimport {\n CALENDAR_DATE_FORMAT,\n calendarFormatFor,\n latestVisit,\n} from './anamnesis-derive';\nimport {\n AnamnesisMissingAnswers,\n missingMandatoryAnswers,\n useFieldJump,\n type MissingAnswer,\n} from './anamnesis-digest';\nimport { AnamnesisField } from './anamnesis-field';\nimport {\n fieldVisible,\n isIntakeAnswered,\n patientAgeLabel,\n sectionLabel,\n} from './anamnesis-format';\nimport type {\n AnamnesisRecord,\n IntakeAnswer,\n IntakeFieldDef,\n IntakeFieldType,\n IntakeSectionDef,\n} from './anamnesis-types';\n\n/* ------------------------------- Helpers -------------------------------- */\n\n/** Field types whose control is intrinsically compact — a number, a select,\n * a times-per-week count or a yes/no row. A free-text detail no longer\n * disqualifies one: a field earns the whole row only once that detail is\n * actually on screen (see `spansRow`), not for being able to have one. */\nconst SHORT_FIELD_TYPES: ReadonlySet<IntakeFieldType> = new Set([\n 'number',\n 'choice',\n 'frequency',\n 'yesNoDetail',\n]);\n\nfunction isShortField(field: IntakeFieldDef): boolean {\n return SHORT_FIELD_TYPES.has(field.type);\n}\n\n/** A section made only of short fields reads like a lab form, so on a wide\n * card it runs up to four across; one holding any prose field runs two, which\n * is what a mixed section can fill. A single capped column left half the row\n * empty and was rejected on review. */\nexport function isLabGridSection(section: IntakeSectionDef): boolean {\n return section.fields.length > 0 && section.fields.every(isShortField);\n}\n\n/** A `text` field the practice marked long-form takes the row like prose. */\nfunction isLongFormText(field: IntakeFieldDef) {\n return field.type === 'text' && field.longForm === true;\n}\n\n/** Which questions need the whole row rather than one cell. A detail box is\n * live: the field takes the row the moment that box appears, and the\n * questions after it shuffle by a cell. Deliberately unanimated — a form\n * reflowing under the reader's cursor should be instant, not a transition. */\n/** A field that CAN reveal a details box owns its row from the start, answered\n * or not: reserving the space is what keeps the section still — letting it\n * claim the row on answer shuffled every question after it under the cursor. */\nfunction spansRow(field: IntakeFieldDef): boolean {\n if (field.type === 'textarea') return true;\n if (isLongFormText(field)) return true;\n return field.detail === true && DETAILED_FIELD_TYPES.has(field.type);\n}\n\n/** The types whose `detail: true` renders a details box — see\n * `isDetailVisible`, which decides whether it is on screen YET. */\nconst DETAILED_FIELD_TYPES: ReadonlySet<IntakeFieldType> = new Set([\n 'yesNoDetail',\n 'frequency',\n 'choice',\n]);\n\n/** The card is the container the sections size against. The thresholds are px\n * because a container query's `rem` follows the HOST root font-size, so a rem\n * threshold would move on a non-16px root. */\nconst SECTION_FIELDS_GRID =\n 'ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-lg)] ds:@[640px]/intake:grid-cols-2 ds:@[960px]/intake:grid-cols-3 ds:@[1280px]/intake:grid-cols-4';\nconst SECTION_FIELDS_MIXED =\n 'ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-lg)] ds:@[640px]/intake:grid-cols-2';\n/** Whole-row placement. In a one-column grid it is already the whole row, so\n * it needs no breakpoint of its own. */\nconst FIELD_SPANS_ROW = 'ds:col-span-full';\n\n/** Field key → answer. Exported so hosts can type the `onSubmit` seam. */\nexport type IntakeAnswerMap = Partial<Record<string, IntakeAnswer>>;\ntype AnswerMap = IntakeAnswerMap;\n\nfunction seedAnswers(record: AnamnesisRecord): AnswerMap {\n const out: AnswerMap = {};\n const source = record.intake?.answers ?? {};\n for (const [key, sourced] of Object.entries(source)) {\n if (sourced) out[key] = sourced.value;\n }\n return out;\n}\n\n/* -------------------------------- Props --------------------------------- */\n\nexport interface AnamnesisIntakeProps {\n record: AnamnesisRecord;\n t: TFunction;\n /** Mount flush inside a host section tab (drops the full-page chrome + own\n * page title). */\n embedded?: boolean;\n /** The practice's configured questionnaire. Omitted = the kit-seeded form. */\n config?: PracticeAnamnesisConfig;\n /** Demo/story hook: which section is open on mount. Defaults to the first. */\n defaultOpenSection?: string;\n /** The questionnaire was submitted: receives the full answer map. The\n * surface keeps its own draft state either way — this is the seam a\n * platform host persists through (mirrors `onTargetChange`). */\n onSubmit?: (answers: IntakeAnswerMap) => void;\n /** Open the section containing this field key and move focus to it on\n * mount — the landing half of a host-routed missing-answer jump. */\n jumpToField?: string;\n /** Render the answers without letting them be changed, and drop the footer\n * action. The state an ALREADY-COMPILED questionnaire arrives in: a reader\n * should be able to tell at a glance that this has been answered, and has\n * to ask before overwriting the patient's own words. */\n readOnly?: boolean;\n}\n\n/* ------------------------------- Component ------------------------------ */\n\nexport function AnamnesisIntake({\n record,\n t,\n embedded = false,\n config,\n defaultOpenSection,\n onSubmit,\n jumpToField,\n readOnly = false,\n}: AnamnesisIntakeProps) {\n const { patient } = record;\n // A questionnaire can be sent before any visit exists, so the header rows it\n // would date are rendered only when there is a visit to date them against.\n // The reference is the record's, not this surface's: reading `visits[0]` here\n // dated the header to the FIRST visit and aged the patient years behind the\n // same patient's compile screen.\n const referenceVisit = latestVisit(record);\n const [answers, setAnswers] = useState<AnswerMap>(() => seedAnswers(record));\n\n const [submitted, setSubmitted] = useState(\n () => record.intake?.submittedAtIso != null,\n );\n\n const onFieldChange = (key: string, answer: IntakeAnswer) => {\n setAnswers((prev) => ({ ...prev, [key]: answer }));\n };\n\n // CAPTURE surface: archived questions are not asked again.\n const visibleSections = useMemo(\n () =>\n configuredSections(config)\n .map((section) => ({\n ...section,\n fields: section.fields.filter((f) => fieldVisible(f, patient.sex)),\n }))\n .filter((section) => section.fields.length > 0),\n [config, patient.sex],\n );\n\n // Free navigation stays the default, but the missing-answer jump has to be\n // able to open a section, so the disclosure is controlled. Every section\n // opens on arrival; a section folds itself once every one of its questions\n // is answered AND the reader moves on (see collapseIfComplete) — a finished\n // section left open is noise, one folded under the cursor is a trap.\n const sectionsToOpen = (): string[] =>\n visibleSections.map((section) => section.key);\n const collapseIfComplete = (\n section: IntakeSectionDef,\n event: React.FocusEvent<HTMLDivElement>,\n ) => {\n // Only a move to ANOTHER part of the questionnaire folds it — leaving\n // the page, switching tabs or opening a menu is not \"moving on\".\n const next = event.relatedTarget;\n if (!(next instanceof Node)) return;\n if (event.currentTarget.contains(next)) return;\n if (!containerRef.current?.contains(next)) return;\n // The section the host jumped the reader to stays open on its own.\n if (section.key === defaultOpenSection) return;\n const complete = section.fields.every((field) =>\n isIntakeAnswered(answers[field.key]),\n );\n if (!complete) return;\n setOpenSections((prev) => prev.filter((key) => key !== section.key));\n };\n const [openSections, setOpenSections] = useState<string[]>(() =>\n sectionsToOpen(),\n );\n const openSectionKey = (key: string) =>\n setOpenSections((prev) => (prev.includes(key) ? prev : [...prev, key]));\n\n // Re-seed when the host swaps the QUESTIONNAIRE — `record.intake` — and\n // only then. Without any re-seed, a host that refreshes in place keeps\n // showing the PREVIOUS questionnaire's answers, and a freshly created\n // interview arrives already full. But keying it on the whole record threw\n // the reader's unsaved answers away every time the host re-read anything\n // else about the record — moving the visit's date, deleting another\n // interview from the archive — because the record object was new even\n // though the questionnaire was not. A host that keeps `intake`\n // referentially stable while its answers are unchanged keeps the draft.\n const [seededFrom, setSeededFrom] = useState(record.intake);\n if (record.intake !== seededFrom) {\n setSeededFrom(record.intake);\n const seeded = seedAnswers(record);\n setAnswers(seeded);\n setOpenSections(sectionsToOpen());\n }\n const { containerRef, requestJump } = useFieldJump();\n\n const missing = useMemo(\n () =>\n missingMandatoryAnswers(\n visibleSections,\n (key) => answers[key],\n patient.sex,\n t,\n ),\n [visibleSections, answers, patient.sex, t],\n );\n\n const jumpToMissing = (target: MissingAnswer) => {\n openSectionKey(target.sectionKey);\n requestJump(target.key);\n };\n\n // Host-routed landing: open the section holding `jumpToField` and focus\n // it once per target — the arrival half of onMissingAnswerJump.\n useEffect(() => {\n if (!jumpToField) return;\n const holder = visibleSections.find((section) =>\n section.fields.some((field) => field.key === jumpToField),\n );\n if (!holder) return;\n openSectionKey(holder.key);\n requestJump(jumpToField);\n // visibleSections is stable for a mounted surface; re-running on target\n // change only is deliberate.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [jumpToField]);\n\n const { answeredCount, totalCount } = useMemo(() => {\n let answered = 0;\n let total = 0;\n for (const section of visibleSections) {\n for (const field of section.fields) {\n total += 1;\n if (isIntakeAnswered(answers[field.key])) answered += 1;\n }\n }\n return { answeredCount: answered, totalCount: total };\n }, [visibleSections, answers]);\n\n const percentComplete =\n totalCount === 0 ? 0 : Math.round((answeredCount / totalCount) * 100);\n const progressCaption = t('anamnesis.intake.answered', {\n answered: answeredCount,\n total: totalCount,\n });\n const showMissing = missing.length > 0 && (answeredCount > 0 || submitted);\n\n const inner = (\n <>\n {/* Questionnaire title. Dropped when embedded — the host section tab\n already labels it, and the patient's identity is set by context. */}\n {embedded ? null : (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <h1 className=\"type-title-page ds:m-0 ds:text-[color:var(--foreground)]\">\n {t('anamnesis.intake.title')}\n </h1>\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.intake.subtitle')}\n </p>\n </div>\n )}\n\n {/* Read-only patient + visit header — standalone only. The patient\n self-completes via a link, so surface who the questionnaire is for.\n Dropped when embedded: the host already shows a patient banner. */}\n {embedded ? null : (\n <DescriptionList layout=\"inline\" labelWidth=\"fixed\" divider=\"between\">\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('anamnesis.header.name')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n {patient.firstName} {patient.lastName}\n </DescriptionList.Detail>\n </DescriptionList.Row>\n {referenceVisit ? (\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('anamnesis.header.age')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n {patientAgeLabel(record, t)}\n </DescriptionList.Detail>\n </DescriptionList.Row>\n ) : null}\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('anamnesis.header.dob')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n <Timestamp\n value={patient.dateOfBirthIso}\n format=\"absolute\"\n shape=\"bare\"\n absoluteFormat={CALENDAR_DATE_FORMAT}\n />\n </DescriptionList.Detail>\n </DescriptionList.Row>\n {referenceVisit ? (\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('anamnesis.header.visitDate')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n <Timestamp\n value={referenceVisit.dateIso}\n format=\"absolute\"\n shape=\"bare\"\n // A visit is an interview with a time now: the header must\n // say 15:27 when the record does, and must not UTC-pin a\n // local timestamp (the date-only DOB above keeps the pin).\n absoluteFormat={calendarFormatFor(referenceVisit.dateIso)}\n />\n </DescriptionList.Detail>\n </DescriptionList.Row>\n ) : null}\n </DescriptionList>\n )}\n\n {/* Progress indication */}\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <Progress value={percentComplete} ariaLabel={progressCaption} />\n <p\n className=\"type-meta ds:m-0 ds:text-[color:var(--muted-foreground)]\"\n aria-live=\"polite\"\n >\n {progressCaption}\n </p>\n </div>\n\n {/* Missing required answers. Held back until the patient has actually\n started, so a pristine form is never met with a list of failures. */}\n {showMissing ? (\n <AnamnesisMissingAnswers\n missing={missing}\n t={t}\n onJump={jumpToMissing}\n // `missing` recomputes on every answer, so a live region would\n // re-read the whole list per keystroke. The alert sits directly\n // above the form in document order and carries its own jump button.\n announce=\"off\"\n />\n ) : null}\n\n {/* Section navigation + fields — free disclosure navigation, on a white\n card so the questions read clearly against the app-shell background. */}\n <Card variant=\"elevated\">\n <Card.Body ref={containerRef} className=\"ds:@container/intake\">\n <section\n aria-label={t('anamnesis.intake.sectionsLabel')}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <h2 className=\"type-title-section ds:m-0 ds:text-[color:var(--foreground)]\">\n {t('anamnesis.intake.sectionsLabel')}\n </h2>\n {visibleSections.length === 0 ? (\n <EmptyState\n variant=\"first-use\"\n size=\"sm\"\n title={t('anamnesis.empty.noQuestions.title')}\n description={t('anamnesis.empty.noQuestions.description')}\n />\n ) : (\n <Accordion\n type=\"multiple\"\n variant=\"default\"\n value={openSections}\n onValueChange={setOpenSections}\n >\n {visibleSections.map((section) => {\n const sectionAnswered = section.fields.filter((f) =>\n isIntakeAnswered(answers[f.key]),\n ).length;\n const allShort = isLabGridSection(section);\n return (\n <AccordionItem\n key={section.key}\n value={section.key}\n onBlur={(event) => collapseIfComplete(section, event)}\n >\n <AccordionTrigger>\n <span className=\"ds:flex ds:w-full ds:flex-wrap ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <span>{sectionLabel(section, t)}</span>\n <span className=\"type-meta ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.intake.sectionProgress', {\n answered: sectionAnswered,\n total: section.fields.length,\n })}\n </span>\n </span>\n </AccordionTrigger>\n <AccordionContent>\n {/* Mobile is untouched either way: both layouts are\n one column until the card is wide enough to take\n a second. */}\n <div\n data-testid={`anamnesis-intake-section-${section.key}-fields`}\n data-layout={allShort ? 'short' : 'mixed'}\n className={\n allShort\n ? SECTION_FIELDS_GRID\n : SECTION_FIELDS_MIXED\n }\n >\n {section.fields.map((field) => (\n <AnamnesisField\n readOnly={readOnly}\n key={field.key}\n def={field}\n answer={answers[field.key]}\n // Only an all-short section can reach three or\n // more columns; the words then drop AT that\n // threshold, by container query, not here.\n className={\n spansRow(field) ? FIELD_SPANS_ROW : undefined\n }\n onChange={(answer) =>\n onFieldChange(field.key, answer)\n }\n t={t}\n />\n ))}\n </div>\n </AccordionContent>\n </AccordionItem>\n );\n })}\n </Accordion>\n )}\n </section>\n </Card.Body>\n </Card>\n\n {/* Footer actions — submit only; the product has no draft save.\n Absent while read-only: there is nothing to save until the\n reader asks to edit. */}\n {readOnly ? null : (\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <p\n className=\"type-meta ds:m-0 ds:text-[color:var(--muted-foreground)]\"\n aria-live=\"polite\"\n >\n {submitted\n ? t('anamnesis.intake.submittedNotice')\n : t('anamnesis.intake.unsentNotice')}\n </p>\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]\">\n <Button\n intent=\"primary\"\n startIcon={<SendHorizontal aria-hidden=\"true\" />}\n data-testid=\"anamnesis-intake-submit\"\n onClick={() => {\n setSubmitted(true);\n onSubmit?.(answers);\n }}\n >\n {t('anamnesis.intake.submit')}\n </Button>\n </div>\n </div>\n )}\n </>\n );\n\n if (embedded) {\n return (\n <div className=\"ds:flex ds:w-full ds:flex-col ds:gap-[var(--spacing-lg)]\">\n {inner}\n </div>\n );\n }\n return (\n <div className=\"ds:min-h-[100dvh] ds:w-full ds:bg-[color:var(--app-shell-background)] ds:py-[var(--spacing-xl)]\">\n <div className=\"ds:mx-auto ds:flex ds:w-full ds:max-w-[48rem] ds:flex-col ds:gap-[var(--spacing-lg)] ds:px-[var(--spacing-md)]\">\n {inner}\n </div>\n </div>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — read-only mode (care plan section) */\n/* */\n/* The same record rendered with ZERO edit affordances: a definition-list */\n/* presentation (dt/dd values, not greyed-out form fields), read-only */\n/* badges for pathologies and statuses, and the evolution section with */\n/* editing turned off so trends, ticking visits and a file of the view stay */\n/* available. Not a screenshot of compile mode with disabled inputs — a */\n/* genuine read presentation. */\n/* -------------------------------------------------------------------- */\n\nimport type { TFunction } from 'i18next';\nimport { Badge } from '../../components/badge';\nimport { Card } from '../../components/card';\nimport { DescriptionList } from '../../components/description-list';\nimport { EmptyState } from '../../components/empty-state';\nimport { Timestamp } from '../../components/timestamp';\nimport {\n allParametersIncludingArchived,\n allSectionsIncludingArchived,\n pathologyLookup,\n type PracticeAnamnesisConfig,\n} from './anamnesis-config';\nimport {\n calendarFormatFor,\n deltaInfo,\n formatValue,\n outOfRange,\n parameterValueAt,\n} from './anamnesis-derive';\nimport { AnamnesisEvolution, useShownVisitIds } from './anamnesis-evolution';\nimport { AnamnesisExportMenu } from './anamnesis-export-menu';\nimport {\n localeOf,\n parameterLabel,\n pathologyCodeWithLabel,\n patientAgeLabel,\n} from './anamnesis-format';\nimport { DeltaIndicator, OutOfRangeBadge } from './anamnesis-indicators';\nimport { AnamnesisAnswerList } from './anamnesis-summary';\nimport type {\n AnamnesisRecord,\n NumericParameterDef,\n OpenAnamnesisNote,\n Visit,\n} from './anamnesis-types';\n\n/* ------------------------------- Helpers -------------------------------- */\n\nfunction Block({\n titleKey,\n t,\n children,\n}: {\n titleKey: string;\n t: TFunction;\n children: React.ReactNode;\n}) {\n // A plain titled section. The read-only surface wraps every section in a\n // single elevated Card (like the intake and compile surfaces), so each section\n // sits ON that card rather than being its own card — no stack of separate cards\n // floating on the app-shell background.\n return (\n <section className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <h2 className=\"type-title-section ds:m-0 ds:text-[color:var(--foreground)]\">\n {t(titleKey)}\n </h2>\n {children}\n </section>\n );\n}\n\n/* ------------------------- Read-only numeric list ----------------------- */\n\nfunction ReadOnlyNumericList({\n defs,\n visit,\n previous,\n targets,\n t,\n}: {\n defs: NumericParameterDef[];\n visit: Visit;\n previous?: Visit;\n targets: Map<string, number>;\n t: TFunction;\n}) {\n const locale = localeOf(t);\n return (\n <DescriptionList layout=\"inline\" labelWidth=\"fixed\" divider=\"between\">\n {defs.map((def) => {\n const value = parameterValueAt(visit, def);\n const prevValue = previous ? parameterValueAt(previous, def) : null;\n const delta = previous ? deltaInfo(value, prevValue, def) : null;\n const flag = outOfRange(value, def.referenceRange);\n const target = targets.get(def.key) ?? null;\n return (\n <DescriptionList.Row key={def.key}>\n <DescriptionList.Term>\n {parameterLabel(def, t)}\n {def.unit ? ` (${def.unit})` : ''}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)] ds:tabular-nums\">\n <span className=\"ds:text-[color:var(--foreground)]\">\n {formatValue(value, def.precision, locale)}\n </span>\n {flag ? <OutOfRangeBadge flag={flag} t={t} /> : null}\n <DeltaIndicator delta={delta} def={def} t={t} />\n {target != null ? (\n <span className=\"type-meta ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.grid.target', {\n value: formatValue(target, def.precision, locale),\n unit: def.unit ?? '',\n })}\n </span>\n ) : null}\n </span>\n </DescriptionList.Detail>\n </DescriptionList.Row>\n );\n })}\n </DescriptionList>\n );\n}\n\n/* -------------------------------- Props --------------------------------- */\n\nexport interface AnamnesisReadOnlyProps {\n record: AnamnesisRecord;\n t: TFunction;\n /** Mount flush inside a host section tab (drops the full-page chrome + the\n * patient-name page heading). */\n embedded?: boolean;\n /** The practice's configured vocabulary. Omitted = the kit-seeded default. */\n config?: PracticeAnamnesisConfig;\n /** The host's side panel, forwarded to the Evolution block. Omitted = the\n * evolution surface reads notes in place. */\n onOpenNote?: OpenAnamnesisNote;\n /** Draw the evolution block as one table per anamnesis type (visits\n * grouped by `sourceLabel`). Default false: one grid over every visit. */\n partitionBySource?: boolean;\n}\n\n/* ------------------------------- Component ------------------------------ */\n\nexport function AnamnesisReadOnly({\n record,\n t,\n embedded = false,\n config,\n onOpenNote,\n partitionBySource = false,\n}: AnamnesisReadOnlyProps) {\n const { patient, visits } = record;\n const latest: Visit | undefined = visits[visits.length - 1];\n const previous = visits.length > 1 ? visits[visits.length - 2] : undefined;\n const targets = new Map(\n record.targets.map((x) => [x.parameterKey, x.target] as const),\n );\n // Every list here is HISTORY: archived descriptors stay, so a value recorded\n // under one still renders.\n const anthroDefs = allParametersIncludingArchived(config, 'anthropometric');\n const dietaryDefs = allParametersIncludingArchived(config, 'dietary');\n const labDefs = allParametersIncludingArchived(config, 'lab');\n const historySections = allSectionsIncludingArchived(config);\n const pathologies = pathologyLookup(config);\n // Before the early return: the trend's export control files the columns on\n // screen, and a hook after a conditional return would break the hook order.\n const [shownVisitIds, trackShownVisits] = useShownVisitIds();\n\n // Nothing recorded yet: a deliberate empty state, not a card of em dashes.\n if (!latest) {\n return (\n <ReadOnlyShell embedded={embedded}>\n <Card variant=\"elevated\">\n <Card.Body>\n <EmptyState\n variant=\"first-use\"\n size=\"sm\"\n title={t('anamnesis.empty.noRecord.title')}\n description={t('anamnesis.empty.noRecord.description')}\n />\n </Card.Body>\n </Card>\n </ReadOnlyShell>\n );\n }\n\n const oncological = latest.oncological;\n const annual = latest.annualProgramme;\n\n const inner = (\n <>\n {/* Header — dropped when embedded (the host shows the patient banner). */}\n {embedded ? null : (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <h1 className=\"type-title-page ds:m-0 ds:text-[color:var(--foreground)]\">\n {patient.firstName} {patient.lastName}\n </h1>\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.readOnly.subtitle')}\n </p>\n </div>\n )}\n\n {/* One elevated Card holds every section, so the read-only surface reads\n as a contained record (matching the intake and compile surfaces)\n rather than a stack of section cards floating on the app-shell\n background. */}\n <Card variant=\"elevated\">\n <Card.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]\">\n {/* Patient + visit meta */}\n <Block titleKey=\"anamnesis.readOnly.summary\" t={t}>\n <DescriptionList\n layout=\"inline\"\n labelWidth=\"fixed\"\n divider=\"between\"\n >\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('anamnesis.header.name')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n {patient.firstName} {patient.lastName}\n </DescriptionList.Detail>\n </DescriptionList.Row>\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('anamnesis.header.age')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n {patientAgeLabel(record, t)}\n </DescriptionList.Detail>\n </DescriptionList.Row>\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('anamnesis.header.visitDate')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n <Timestamp\n value={latest.dateIso}\n format=\"absolute\"\n shape=\"bare\"\n absoluteFormat={calendarFormatFor(latest.dateIso)}\n />\n </DescriptionList.Detail>\n </DescriptionList.Row>\n {latest.practitioner ? (\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('anamnesis.field.practitioner.label')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n {latest.practitioner}\n </DescriptionList.Detail>\n </DescriptionList.Row>\n ) : null}\n </DescriptionList>\n </Block>\n\n {/* Anthropometrics */}\n <Block titleKey=\"anamnesis.section.anthropometrics\" t={t}>\n <ReadOnlyNumericList\n defs={anthroDefs}\n visit={latest}\n previous={previous}\n targets={targets}\n t={t}\n />\n </Block>\n\n {/* Dietary intake */}\n {dietaryDefs.length > 0 ? (\n <Block titleKey=\"anamnesis.section.dietary\" t={t}>\n <ReadOnlyNumericList\n defs={dietaryDefs}\n visit={latest}\n previous={previous}\n targets={targets}\n t={t}\n />\n </Block>\n ) : null}\n\n {/* Pathologies */}\n <Block titleKey=\"anamnesis.section.pathologies\" t={t}>\n {latest.pathologyCodes.length > 0 ? (\n <div className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-xs)]\">\n {latest.pathologyCodes.map((code) => (\n <Badge key={code} variant=\"neutral\" size=\"md\">\n {pathologyCodeWithLabel(code, t, pathologies[code])}\n </Badge>\n ))}\n </div>\n ) : (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.readOnly.none')}\n </p>\n )}\n </Block>\n\n {/* Oncological history */}\n {oncological ? (\n <Block titleKey=\"anamnesis.section.oncological\" t={t}>\n <DescriptionList\n layout=\"inline\"\n labelWidth=\"fixed\"\n divider=\"between\"\n >\n {oncological.tumourType ? (\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('anamnesis.field.tumourType.label')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n {oncological.tumourType}\n </DescriptionList.Detail>\n </DescriptionList.Row>\n ) : null}\n {oncological.stage ? (\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('anamnesis.field.stage.label')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n {oncological.stage}\n </DescriptionList.Detail>\n </DescriptionList.Row>\n ) : null}\n {oncological.treatmentStatus ? (\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('anamnesis.field.treatmentStatus.label')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n {oncological.treatmentStatus}\n </DescriptionList.Detail>\n </DescriptionList.Row>\n ) : null}\n </DescriptionList>\n </Block>\n ) : null}\n\n {/* Therapy & supplements */}\n <Block titleKey=\"anamnesis.section.therapy\" t={t}>\n {latest.therapy.length > 0 ? (\n <ul className=\"ds:m-0 ds:flex ds:list-none ds:flex-col ds:gap-[var(--spacing-sm)] ds:p-0\">\n {latest.therapy.map((entry) => (\n <li\n key={entry.id}\n className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]\"\n >\n <span className=\"type-label ds:text-[color:var(--foreground)]\">\n {entry.name}\n </span>\n {entry.dose ? (\n <span className=\"type-meta ds:text-[color:var(--muted-foreground)]\">\n {entry.dose}\n </span>\n ) : null}\n <Badge\n variant={entry.kind === 'medication' ? 'info' : 'neutral'}\n size=\"sm\"\n >\n {t(`anamnesis.medKind.${entry.kind}`)}\n </Badge>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.readOnly.none')}\n </p>\n )}\n </Block>\n\n {/* Blood tests */}\n <Block titleKey=\"anamnesis.section.labs\" t={t}>\n <ReadOnlyNumericList\n defs={labDefs}\n visit={latest}\n previous={previous}\n targets={targets}\n t={t}\n />\n </Block>\n\n {/* Nutritional proposal + notes */}\n {latest.nutritionalProposal || latest.clinicalNotes ? (\n <Block titleKey=\"anamnesis.section.proposal\" t={t}>\n {latest.nutritionalProposal ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <span className=\"type-label ds:text-[color:var(--foreground)]\">\n {t('anamnesis.field.nutritionalProposal.label')}\n </span>\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {latest.nutritionalProposal}\n </p>\n </div>\n ) : null}\n {latest.clinicalNotes ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <span className=\"type-label ds:text-[color:var(--foreground)]\">\n {t('anamnesis.field.clinicalNotes.label')}\n </span>\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {latest.clinicalNotes}\n </p>\n </div>\n ) : null}\n </Block>\n ) : null}\n\n {/* Annual programme */}\n {annual ? (\n <Block titleKey=\"anamnesis.section.annual\" t={t}>\n <div className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-xs)]\">\n <Badge\n variant={annual.proposed ? 'success' : 'neutral'}\n size=\"md\"\n withDot\n >\n {t('anamnesis.field.annualProposed.label')}:{' '}\n {annual.proposed\n ? t('anamnesis.common.yes')\n : t('anamnesis.common.no')}\n </Badge>\n <Badge\n variant={annual.accepted ? 'success' : 'neutral'}\n size=\"md\"\n withDot\n >\n {t('anamnesis.field.annualAccepted.label')}:{' '}\n {annual.accepted\n ? t('anamnesis.common.yes')\n : t('anamnesis.common.no')}\n </Badge>\n </div>\n </Block>\n ) : null}\n\n {/* Patient intake answers — the same read-only renderer the compile\n surface's Summary tab uses, so there is one presentation of a\n recorded questionnaire, not two that can drift apart. */}\n {record.intake && Object.keys(record.intake.answers).length > 0 ? (\n <Block titleKey=\"anamnesis.section.patientIntake\" t={t}>\n <AnamnesisAnswerList\n intake={record.intake}\n sections={historySections}\n sex={patient.sex}\n t={t}\n />\n </Block>\n ) : null}\n\n {/* Evolution — read-only grid; every visit a column, PDF/print of\n the view from the toolbar. */}\n <Block titleKey=\"anamnesis.section.evolution\" t={t}>\n <AnamnesisEvolution\n record={record}\n t={t}\n config={config}\n framed={false}\n onOpenNote={onOpenNote}\n partitionBySource={partitionBySource}\n onVisitSelectionChange={trackShownVisits}\n exportSlot={\n <AnamnesisExportMenu\n tab=\"evolution\"\n record={record}\n t={t}\n config={config}\n shownVisitIds={shownVisitIds}\n />\n }\n />\n </Block>\n </Card.Body>\n </Card>\n </>\n );\n\n return <ReadOnlyShell embedded={embedded}>{inner}</ReadOnlyShell>;\n}\n\n/** The surface's page chrome, shared by the record and its empty state. */\nfunction ReadOnlyShell({\n embedded,\n children,\n}: {\n embedded: boolean;\n children: React.ReactNode;\n}) {\n if (embedded) {\n return (\n <div className=\"ds:flex ds:w-full ds:flex-col ds:gap-[var(--spacing-lg)]\">\n {children}\n </div>\n );\n }\n return (\n <div className=\"ds:min-h-[100dvh] ds:w-full ds:bg-[color:var(--app-shell-background)] ds:py-[var(--spacing-lg)]\">\n <div className=\"ds:mx-auto ds:flex ds:w-full ds:max-w-[76rem] ds:flex-col ds:gap-[var(--spacing-lg)] ds:px-[var(--spacing-md)]\">\n {children}\n </div>\n </div>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — questionnaire mode */\n/* */\n/* ONE surface for both actors. The clinician and the patient answer the */\n/* SAME questionnaire — the practice creates two forms when the two roles */\n/* must be asked different things — so there is no separate doctor-fill */\n/* form and no bespoke measurement blocks. Numeric questions carry their */\n/* own unit, which is what the trend tab plots over successive */\n/* interviews. */\n/* */\n/* Two built-in tabs, because those are the only two things this surface */\n/* does: answer the questionnaire, and compare its numbers over time. The */\n/* compile mode's eleven bespoke blocks are deliberately absent. A host */\n/* may prepend its own tabs (`leadingTabs`) — the platform island puts an */\n/* Overview of every module's latest interview first — and drive the */\n/* selected tab from outside, so \"edit this interview\" can land on the */\n/* questionnaire from a card on a tab this surface knows nothing about. */\n/* */\n/* ALWAYS EDITABLE. Editing is entered from the host's overview, so the */\n/* questionnaire tab never needs an Edit gate of its own: whoever reaches */\n/* it came here to answer. */\n/* */\n/* NO CARD OF ITS OWN. Both tab panels already bring their own surface — */\n/* the questionnaire its card, the trend its frame — so wrapping them */\n/* nested a card inside a card inside the host's own panel, three borders */\n/* deep for one questionnaire. */\n/* -------------------------------------------------------------------- */\n\nimport { useMemo, useState, type ReactNode } from 'react';\nimport type { TFunction } from 'i18next';\nimport { Card } from '../../components/card';\nimport { Tabs } from '../../components/tabs';\nimport { AnamnesisIntake, type IntakeAnswerMap } from './anamnesis-intake';\nimport { AnamnesisEvolution, useShownVisitIds } from './anamnesis-evolution';\nimport { AnamnesisExportMenu } from './anamnesis-export-menu';\nimport { EmptyState } from '../../components/empty-state';\nimport type { AnamnesisEmptyState } from './anamnesis';\nimport { AnamnesisTargetStrip } from './anamnesis-target-strip';\nimport { stripParameters } from './anamnesis-targets';\nimport { allParametersIncludingArchived } from './anamnesis-config';\nimport { setTargetOnRecord } from './anamnesis-derive';\nimport type { PracticeAnamnesisConfig } from './anamnesis-config';\nimport type { AnamnesisRecord, NumericParameterDef } from './anamnesis-types';\n\nexport interface AnamnesisQuestionnaireProps {\n record: AnamnesisRecord;\n t: TFunction;\n /** The practice's configured vocabulary. Omitted = the kit-seeded default. */\n config?: PracticeAnamnesisConfig;\n /** The questionnaire was submitted — receives the full answer map. The\n * surface keeps its own working copy either way; this is the seam a\n * platform host persists through. */\n onSubmit?: (answers: IntakeAnswerMap) => void;\n /** Open the section containing this field key and focus it on mount. */\n jumpToField?: string;\n /** Host status chips (signature / expiry / save feedback) above the tabs. */\n statusSlot?: ReactNode;\n /** A per-patient goal target was set or cleared (`null` clears it). The\n * surface keeps its own working copy either way — this is the seam a\n * platform host persists through. Omit it and the goals strip still\n * renders and still edits, it simply persists nowhere. */\n onTargetChange?: (parameterKey: string, target: number | null) => void;\n /** Omit the goals strip above the card. Default false: it renders whenever\n * the vocabulary marks at least one parameter as a goal. */\n hideTargetStrip?: boolean;\n /** Host tabs rendered BEFORE the built-in questionnaire and trend tabs,\n * inside the same tab strip. Each value must be unique and must not\n * collide with `questionnaire` / `trend`. */\n leadingTabs?: ReadonlyArray<AnamnesisLeadingTab>;\n /** Controlled selected tab — a leading tab's value, `questionnaire` or\n * `trend`. Pair with `onTabChange`; omit for uncontrolled. */\n tab?: AnamnesisQuestionnaireTab;\n /** The user picked another tab. Fires in both modes, so an uncontrolled\n * host can still observe the selection. */\n onTabChange?: (tab: AnamnesisQuestionnaireTab) => void;\n /** Uncontrolled initial tab. Defaults to the first leading tab when there\n * is one, else the questionnaire. Demo/story hook too — Chromatic skips\n * play functions, so a click-selected tab is never snapshotted. */\n defaultTab?: AnamnesisQuestionnaireTab;\n /** Lock the questionnaire (every control disabled, no footer). A host with\n * nothing to edit — no interview selected yet — must not offer a Submit\n * that would post into the void. */\n readOnly?: boolean;\n /** Render this INSTEAD of the questionnaire in its tab panel — the host's\n * restriction message when the reader may not see the answers. The tab\n * strip stays, so the trend and the host's own tabs remain reachable;\n * unmounting the whole surface for one withheld panel took them with it. */\n questionnaireSlot?: ReactNode;\n /** Rendered INSIDE the questionnaire's tab panel, above the questionnaire —\n * the host's per-interview controls (its date, its signature state). They\n * belong to the interview being answered, so they show only when it does;\n * in the shared tab header they sat beside host tabs about other things. */\n questionnaireHeaderSlot?: ReactNode;\n /** ONE empty presentation in EVERY tab panel while the record has nothing\n * to show — the host decides when. The tab strip stays exactly as it is, so\n * the layout does not jump the moment the first interview is created. */\n emptyState?: AnamnesisEmptyState;\n /** One trend table per anamnesis type instead of one grid over every\n * module's visits. Default false. */\n partitionBySource?: boolean;\n}\n\n/** A host-supplied tab that precedes the built-in ones. */\nexport interface AnamnesisLeadingTab {\n value: string;\n label: string;\n content: ReactNode;\n}\n\n/** The built-in tab values, widened so a host's leading-tab values type\n * without a cast. */\nexport type AnamnesisQuestionnaireTab =\n | 'questionnaire'\n | 'trend'\n | (string & {});\n\nconst NO_LEADING_TABS: ReadonlyArray<AnamnesisLeadingTab> = [];\n\n/** The one empty presentation of questionnaire mode. Every panel that has\n * nothing to show renders this same card, so an empty record reads as one\n * state rather than three unrelated placeholders. */\nfunction AnamnesisEmptyCard({\n variant = 'first-use',\n testId = 'anamnesis-empty-card',\n title,\n description,\n primaryAction,\n secondaryAction,\n}: AnamnesisEmptyState & {\n variant?: 'first-use' | 'no-results';\n testId?: string;\n}) {\n return (\n <Card variant=\"elevated\" data-testid={testId}>\n <Card.Body>\n <EmptyState\n variant={variant}\n size=\"md\"\n title={title}\n description={description}\n primaryAction={primaryAction}\n secondaryAction={secondaryAction}\n />\n </Card.Body>\n </Card>\n );\n}\n\nexport function AnamnesisQuestionnaire({\n record,\n t,\n config,\n onSubmit,\n jumpToField,\n statusSlot,\n onTargetChange,\n hideTargetStrip = false,\n leadingTabs = NO_LEADING_TABS,\n readOnly = false,\n questionnaireSlot,\n questionnaireHeaderSlot,\n emptyState,\n partitionBySource = false,\n tab: tabProp,\n onTabChange,\n defaultTab,\n}: AnamnesisQuestionnaireProps) {\n // Controlled when the host passes `tab`, uncontrolled otherwise — the same\n // split as the kit's Tabs itself, so a host that only wants to observe the\n // selection is not forced to own it.\n const [internalTab, setInternalTab] = useState<AnamnesisQuestionnaireTab>(\n () => defaultTab ?? leadingTabs[0]?.value ?? 'questionnaire',\n );\n const tab = tabProp ?? internalTab;\n const selectTab = (next: AnamnesisQuestionnaireTab) => {\n if (tabProp === undefined) setInternalTab(next);\n onTabChange?.(next);\n };\n\n // Targets belong to the RECORD, not to a visit — a goal is not a measurement\n // taken on a day — so edits land on a working copy of the record and the\n // host persists through the callback. Same idiom as the compile surface.\n const [working, setWorking] = useState<AnamnesisRecord>(record);\n\n // RE-SEED WHEN THE HOST HANDS US A DIFFERENT RECORD. A host that reloads the\n // page to show new data gets fresh state for free; one that swaps the record\n // in place — the AlfaDocs island creating an interview, or opening a past one\n // from its archive — does not, and this surface would go on showing the\n // PREVIOUS record's answers. That reads as \"nothing\n // happened\", which is worse than a slow reload.\n //\n // Adjusting state during render is React's own prescription for\n // derived-from-props state; it re-renders immediately, before children see\n // the stale values, and beats an effect that paints the wrong thing first.\n const [seededFrom, setSeededFrom] = useState(record);\n if (record !== seededFrom) {\n setSeededFrom(record);\n setWorking(record);\n }\n const targets = useMemo(\n () =>\n new Map(working.targets.map((x) => [x.parameterKey, x.target] as const)),\n [working.targets],\n );\n const stripDefs = useMemo(() => stripParameters(config), [config]);\n // The trend plots ONE SERIES PER NUMERIC QUESTION. A questionnaire whose\n // questions are all boolean, text or choice has nothing numeric to compare,\n // so the grid would draw an empty frame and the shared evolution empty state\n // would tell the reader to \"record the first visit\" — a concept this surface\n // does not have. Say the true thing instead.\n const numericDefs = useMemo(\n () => allParametersIncludingArchived(config),\n [config],\n );\n const setTarget = (def: NumericParameterDef, target: number | null) => {\n setWorking((r) => setTargetOnRecord(r, def.key, target));\n onTargetChange?.(def.key, target);\n };\n // The trend files what is on screen: the export control mirrors the columns\n // the picker shows. `working`, so a goal set this session rides into the file.\n const [shownVisitIds, trackShownVisits] = useShownVisitIds();\n\n const trendPanel = (\n <AnamnesisEvolution\n record={working}\n t={t}\n config={config}\n /* Read-only: values are answered in the questionnaire, never typed into\n the grid — one place to answer a question. */\n framed={false}\n partitionBySource={partitionBySource}\n /* This tab is the one host that steps back for the module cards, so it\n is the one host that asks for them — the read-only and compile\n surfaces keep their own card and leave the blocks bare. */\n cardBlocks\n onVisitSelectionChange={trackShownVisits}\n exportSlot={\n <AnamnesisExportMenu\n tab=\"evolution\"\n record={working}\n t={t}\n config={config}\n shownVisitIds={shownVisitIds}\n />\n }\n />\n );\n\n return (\n // The goals strip and the tabs are two objects, not one run-on block: an\n // explicit column gap keeps the strip from sitting flush on the card\n // below it, which read as a rendering fault rather than as a heading.\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]\">\n {/* A sibling of the card, not nested in it: \"where is this patient\n against her goals\" is its own object, on screen while she moves\n between the questionnaire and its trend. Nice-to-have scope — a\n host that has not funded goal storage omits it. */}\n {hideTargetStrip || emptyState || working.visits.length === 0 ? null : (\n <AnamnesisTargetStrip\n visits={working.visits}\n defs={stripDefs}\n targets={targets}\n t={t}\n onTargetChange={setTarget}\n />\n )}\n <Tabs value={tab} onValueChange={selectTab}>\n {/* A sibling of Tabs.List, not a child: a tablist holds tabs only. */}\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <Tabs.List aria-label={t('anamnesis.compile.viewsLabel')}>\n {leadingTabs.map((leading) => (\n <Tabs.Trigger key={leading.value} value={leading.value}>\n {leading.label}\n </Tabs.Trigger>\n ))}\n <Tabs.Trigger value=\"questionnaire\">\n {t('anamnesis.compile.tabCompile')}\n </Tabs.Trigger>\n <Tabs.Trigger value=\"trend\">\n {t('anamnesis.compile.tabEvolution')}\n </Tabs.Trigger>\n </Tabs.List>\n {statusSlot ? (\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]\">\n {statusSlot}\n </div>\n ) : null}\n </div>\n\n {/* `forceMount` + hidden-when-inactive keeps typed answers and the host's\n tab alive across switches; the trend remounts instead (its sparklines\n size at mount) except while `emptyState` hides them, see below. */}\n {leadingTabs.map((leading) => (\n <Tabs.Content\n key={leading.value}\n value={leading.value}\n forceMount\n className=\"ds:data-[state=inactive]:hidden\"\n >\n {emptyState ? (\n <AnamnesisEmptyCard {...emptyState} />\n ) : (\n leading.content\n )}\n </Tabs.Content>\n ))}\n\n <Tabs.Content\n value=\"questionnaire\"\n forceMount\n className=\"ds:data-[state=inactive]:hidden\"\n >\n {emptyState ? (\n <AnamnesisEmptyCard {...emptyState} />\n ) : (\n <>\n {/* `embedded` unconditionally: the questionnaire sits inside\n this card's tab panel, so its own page chrome would double\n the heading the tab already provides. */}\n {questionnaireHeaderSlot ? (\n <div className=\"ds:mb-[var(--spacing-md)] ds:flex ds:flex-wrap ds:items-end ds:justify-between ds:gap-[var(--spacing-sm)]\">\n {questionnaireHeaderSlot}\n </div>\n ) : null}\n {questionnaireSlot ?? (\n <AnamnesisIntake\n record={working}\n t={t}\n embedded\n config={config}\n onSubmit={onSubmit}\n jumpToField={jumpToField}\n readOnly={readOnly}\n />\n )}\n </>\n )}\n </Tabs.Content>\n\n {/* Force-mounted only while empty: the sparklines that must not size\n themselves behind a hidden panel are not rendered then, and the\n same card in every panel is what keeps the tab switch seamless. */}\n <Tabs.Content\n value=\"trend\"\n forceMount={emptyState ? true : undefined}\n className=\"ds:data-[state=inactive]:hidden\"\n >\n {emptyState ? (\n <AnamnesisEmptyCard {...emptyState} />\n ) : numericDefs.length === 0 ? (\n <AnamnesisEmptyCard\n variant=\"no-results\"\n testId=\"anamnesis-trend-empty\"\n title={t('anamnesis.questionnaire.noNumeric.title')}\n description={t('anamnesis.questionnaire.noNumeric.description')}\n />\n ) : working.visits.length === 0 ? (\n /* The evolution's own bare no-visits state sat on the page ground\n while the questionnaire's sat in a card: same shell for both. */\n <AnamnesisEmptyCard\n testId=\"anamnesis-trend-empty\"\n title={t('anamnesis.empty.noVisits.title')}\n description={t('anamnesis.empty.noVisits.description')}\n />\n ) : partitionBySource ? (\n /* Each module block brings its own card, so a card here would nest\n three elevated surfaces inside a fourth — a box in a box. */\n trendPanel\n ) : (\n /* One grid, so it needs the same elevated card as the\n questionnaire's sections: otherwise it is the one surface on the\n tab sitting bare on the page. */\n <Card variant=\"elevated\">\n <Card.Body>{trendPanel}</Card.Body>\n </Card>\n )}\n </Tabs.Content>\n </Tabs>\n </div>\n );\n}\n\nAnamnesisQuestionnaire.displayName = 'AnamnesisQuestionnaire';\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — mode router */\n/* */\n/* One tool, three host contexts, driven by a `mode` prop: */\n/* intake — patient self-completion (Anamnesis section) */\n/* compile — clinician record + evolution (Diagnostic section) */\n/* readOnly — the same record, no edit affordances (Care plan section) */\n/* */\n/* Standalone it renders as a full-page `<main>`. Set `embedded` when it */\n/* mounts inside a host context's section tab (e.g. the Patient Folder's */\n/* Anamnesis / Diagnosis tabs): the surface drops its full-page chrome + own */\n/* page heading, and the root renders a plain `<div>` (the host owns the */\n/* `<main>` landmark and the section heading). */\n/* */\n/* The surface takes `t` as a prop (rather than calling useTranslation */\n/* itself) so the RTL/CJK stories can drive it with a locale-pinned */\n/* `getFixedT` without the surface knowing. */\n/* -------------------------------------------------------------------- */\n\nimport type { ReactNode } from 'react';\nimport type { TFunction } from 'i18next';\nimport type { PracticeAnamnesisConfig } from './anamnesis-config';\nimport {\n AnamnesisCompile,\n type AnamnesisCompileView,\n} from './anamnesis-compile';\nimport type { DisclosureAudience } from './anamnesis-disclosure';\nimport { AnamnesisIntake, type IntakeAnswerMap } from './anamnesis-intake';\nimport type { MissingAnswer } from './anamnesis-digest';\nimport { AnamnesisReadOnly } from './anamnesis-readonly';\nimport { AnamnesisQuestionnaire } from './anamnesis-questionnaire';\nimport type {\n AnamnesisLeadingTab,\n AnamnesisQuestionnaireTab,\n} from './anamnesis-questionnaire';\nimport type {\n AnamnesisMode,\n AnamnesisRecord,\n OpenAnamnesisNote,\n PractitionerOption,\n} from './anamnesis-types';\n\n/** Rendered in EVERY tab panel of questionnaire mode while the record has\n * nothing to show — the host decides when (typically: no interview exists\n * yet) and supplies the copy and the create actions. */\nexport interface AnamnesisEmptyState {\n title: string;\n description?: string;\n primaryAction?: { label: string; onClick: () => void };\n secondaryAction?: { label: string; onClick: () => void; href?: string };\n}\n\nexport interface AnamnesisProps {\n /** Which host context to render. */\n mode: AnamnesisMode;\n record: AnamnesisRecord;\n t: TFunction;\n /** Override the cascade / test marker (defaults to `anamnesis`). Stories\n * pass a per-mode marker so each render is independently addressable. */\n dataComponent?: string;\n /** Mount flush inside a host section tab: drops the full-page chrome + own\n * page heading, and renders a `<div>` instead of a `<main>` landmark. */\n embedded?: boolean;\n /** The practice's own vocabulary — parameters, questionnaire, pathology\n * codes. Omit it and the kit-seeded default is used, so every existing\n * mount keeps working unchanged. */\n config?: PracticeAnamnesisConfig;\n /** Compile mode only: a per-patient target was set or cleared. The surface\n * keeps its own working copy either way — this is the seam a platform host\n * persists through. */\n onTargetChange?: (parameterKey: string, target: number | null) => void;\n /** Compile mode only: host status chips (signature / expiry / renew /\n * save feedback) rendered at the surface header's end. */\n statusSlot?: ReactNode;\n /** Compile mode only: omit the nutrition-targets strip above the record —\n * for hosts that present the record without the goals (e.g. the isolated\n * single-section demo). Default false: the strip renders. */\n hideTargetStrip?: boolean;\n /** Compile / readOnly modes: the host's side panel. Wire it to whatever\n * opens a panel in the host shell — in the AlfaDocs folder, the Control\n * Room's `openTool`. Omitted = notes are read in place. */\n onOpenNote?: OpenAnamnesisNote;\n /** Intake mode only: the questionnaire was submitted — receives the full\n * answer map. The surface keeps its own draft state either way; this is\n * the seam a platform host persists through (mirrors `onTargetChange`). */\n onIntakeSubmit?: (answers: IntakeAnswerMap) => void;\n /** Intake mode only: open the section containing this field key and move\n * focus to it on mount — the landing half of `onMissingAnswerJump`. */\n intakeJumpToField?: string;\n /** Intake and questionnaire modes: render the answers without letting them\n * be changed and drop the submit footer — a host's read of a past\n * interview, or a questionnaire with nothing selected to edit. */\n readOnly?: boolean;\n /** Questionnaire mode only: render this instead of the questionnaire in its\n * tab panel (a restriction message), keeping the tab strip and the trend. */\n questionnaireSlot?: ReactNode;\n /** Questionnaire mode only: the host's per-interview controls, rendered\n * inside the questionnaire panel above the questionnaire. */\n questionnaireHeaderSlot?: ReactNode;\n /** Questionnaire mode only: one empty presentation in every tab panel\n * while the record has nothing to show; the tab strip stays put. */\n emptyState?: AnamnesisEmptyState;\n /** Compile, questionnaire and readOnly modes: draw the trend as one table\n * per anamnesis type (visits grouped by `sourceLabel`). Default false. */\n partitionBySource?: boolean;\n /** Compile mode only: route the Summary's missing-answer jump to a host\n * questionnaire surface instead of the internal Compila gaps block. */\n onMissingAnswerJump?: (missing: MissingAnswer) => void;\n /** Compile mode only: every edit to the working record — the visit-data\n * persistence seam (hosts debounce + diff). See `AnamnesisCompileProps`. */\n onRecordChange?: (record: AnamnesisRecord) => void;\n /** Questionnaire mode only: host tabs rendered before the built-in\n * questionnaire and trend tabs, in the same strip. When given and no tab\n * is selected, the first one is the default. */\n leadingTabs?: ReadonlyArray<AnamnesisLeadingTab>;\n /** Questionnaire mode only: controlled selected tab — a leading tab's\n * value, `questionnaire` or `trend`. Pair with `onQuestionnaireTabChange`. */\n questionnaireTab?: AnamnesisQuestionnaireTab;\n /** Questionnaire mode only: the user picked another tab. */\n onQuestionnaireTabChange?: (tab: AnamnesisQuestionnaireTab) => void;\n /** Questionnaire mode only: uncontrolled initial tab. Demo/story hook\n * too — Chromatic skips play functions. */\n defaultQuestionnaireTab?: AnamnesisQuestionnaireTab;\n /** Compile mode only: the practice's operators, offered in the visit's\n * Practitioner select. Omitted or empty keeps the free-text input. */\n practitioners?: PractitionerOption[];\n /** Compile mode only: the calendar date a NEW follow-up visit is created\n * on. A host passes its \"today\"; defaults to the latest visit's date. */\n newVisitDateIso?: string;\n /** Compile mode only: mount on this view instead of Summary. Demo/story\n * hook only, for the same Chromatic reason as the flags below. */\n defaultView?: AnamnesisCompileView;\n /** Compile mode only: mount the export control open / on a given audience.\n * Demo/story hooks only — Chromatic skips play functions, so a click-opened\n * menu or dialog is never snapshotted. */\n defaultExportMenuOpen?: boolean;\n defaultShareOpen?: boolean;\n defaultExportAudience?: DisclosureAudience;\n}\n\nexport function Anamnesis({\n mode,\n record,\n t,\n dataComponent = 'anamnesis',\n embedded = false,\n config,\n onTargetChange,\n hideTargetStrip,\n statusSlot,\n onOpenNote,\n onIntakeSubmit,\n intakeJumpToField,\n readOnly,\n onMissingAnswerJump,\n onRecordChange,\n leadingTabs,\n questionnaireTab,\n onQuestionnaireTabChange,\n questionnaireSlot,\n questionnaireHeaderSlot,\n emptyState,\n partitionBySource,\n defaultQuestionnaireTab,\n practitioners,\n newVisitDateIso,\n defaultView,\n defaultExportMenuOpen,\n defaultShareOpen,\n defaultExportAudience,\n}: AnamnesisProps) {\n const surface =\n mode === 'intake' ? (\n <AnamnesisIntake\n record={record}\n t={t}\n embedded={embedded}\n config={config}\n onSubmit={onIntakeSubmit}\n jumpToField={intakeJumpToField}\n readOnly={readOnly}\n />\n ) : mode === 'questionnaire' ? (\n <AnamnesisQuestionnaire\n record={record}\n t={t}\n config={config}\n onSubmit={onIntakeSubmit}\n jumpToField={intakeJumpToField}\n statusSlot={statusSlot}\n onTargetChange={onTargetChange}\n hideTargetStrip={hideTargetStrip}\n leadingTabs={leadingTabs}\n tab={questionnaireTab}\n onTabChange={onQuestionnaireTabChange}\n defaultTab={defaultQuestionnaireTab}\n readOnly={readOnly}\n questionnaireSlot={questionnaireSlot}\n questionnaireHeaderSlot={questionnaireHeaderSlot}\n emptyState={emptyState}\n partitionBySource={partitionBySource}\n />\n ) : mode === 'compile' ? (\n <AnamnesisCompile\n record={record}\n t={t}\n embedded={embedded}\n config={config}\n onTargetChange={onTargetChange}\n hideTargetStrip={hideTargetStrip}\n statusSlot={statusSlot}\n onOpenNote={onOpenNote}\n onMissingAnswerJump={onMissingAnswerJump}\n onRecordChange={onRecordChange}\n practitioners={practitioners}\n newVisitDateIso={newVisitDateIso}\n defaultView={defaultView}\n defaultExportMenuOpen={defaultExportMenuOpen}\n defaultShareOpen={defaultShareOpen}\n defaultExportAudience={defaultExportAudience}\n partitionBySource={partitionBySource}\n />\n ) : (\n <AnamnesisReadOnly\n record={record}\n t={t}\n embedded={embedded}\n config={config}\n onOpenNote={onOpenNote}\n partitionBySource={partitionBySource}\n />\n );\n\n if (embedded) {\n return (\n <div\n data-component={dataComponent}\n data-mode={mode}\n className=\"ds:w-full\"\n >\n {surface}\n </div>\n );\n }\n\n return (\n <main\n data-component={dataComponent}\n data-mode={mode}\n aria-label={t('anamnesis.mainLabel', {\n mode: t(`anamnesis.mode.${mode}`),\n })}\n className=\"ds:w-full\"\n >\n {surface}\n </main>\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — shared list-reorder idiom (drag + keyboard) */\n/* */\n/* MIRRORS the kit's established DnD idiom — the Sidebar favourites */\n/* section (src/components/sidebar/sidebar.tsx, SidebarFavorites / */\n/* SidebarFavoriteItem): a grip handle per row, HTML5 drag-and-drop */\n/* mounted on the ROW (buttons don't start HTML5 drags reliably in every */\n/* browser, so the whole row is the drag target and the grip is the */\n/* visual + keyboard affordance), keyboard reorder on the handle */\n/* (Alt+ArrowUp / Alt+ArrowDown, Alt+Home / Alt+End), and a polite */\n/* live-region announcement of every move. */\n/* */\n/* Mirrored rather than extracted: the sidebar's implementation is welded */\n/* to its own context (icon-mode gating, SidebarSection's live region, */\n/* reveal-on-hover chrome), so a shared helper could not be lifted without */\n/* touching the sidebar's behaviour — and components must never import */\n/* from patterns, so the shared home would have had to be a new component. */\n/* */\n/* A11y contract (the same one the sidebar keeps): */\n/* • focus stays on the moved row's handle — rows are keyed, so React */\n/* moves the DOM node instead of remounting it; */\n/* • every move is announced with the new position via aria-live; */\n/* • the handle names its row and teaches the key command. */\n/* -------------------------------------------------------------------- */\n\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n type DragEvent,\n type KeyboardEvent,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { cva } from 'class-variance-authority';\nimport type { TFunction } from 'i18next';\nimport { GripVertical } from 'lucide-react';\nimport { IconButton } from '../../components/icon-button';\n\n/* Drag affordances — byte-identical to the sidebar's favoriteRowClasses\n * variants. The base is empty because the host row keeps its own layout\n * classes and merges these on top. */\nconst reorderRowClasses = cva('', {\n variants: {\n dragging: {\n true: 'ds:opacity-60',\n false: '',\n },\n dropTarget: {\n true: 'ds:outline-[length:var(--focus-ring-width)] ds:outline-dashed ds:outline-[var(--primary)] ds:outline-offset-[-2px]',\n false: '',\n },\n },\n defaultVariants: { dragging: false, dropTarget: false },\n});\n\n/* -------------------------------- Context -------------------------------- */\n\ninterface ReorderContextValue {\n onReorder: (from: number, to: number) => void;\n count: number;\n dragSource: number | null;\n setDragSource: (index: number | null) => void;\n announce: (message: string) => void;\n t: TFunction;\n}\n\nconst ReorderContext = createContext<ReorderContextValue | null>(null);\n\n/* --------------------------------- Group --------------------------------- */\n\nexport interface AnamnesisReorderGroupProps {\n /** Number of rows in the group — bounds keyboard moves and gives the\n * announcement its \"of {{total}}\". */\n count: number;\n /** Move a row from `from` to `to` — both DISPLAY indices of the group. */\n onReorder: (from: number, to: number) => void;\n t: TFunction;\n children: ReactNode;\n}\n\n/** One reorderable list. Renders its children untouched plus a visually\n * hidden polite live region the rows announce their moves into. Nesting is\n * fine — a row binds to its NEAREST group, and a drag never crosses groups\n * (each group tracks its own drag source). */\nexport function AnamnesisReorderGroup({\n count,\n onReorder,\n t,\n children,\n}: AnamnesisReorderGroupProps) {\n const [dragSource, setDragSource] = useState<number | null>(null);\n const [liveMessage, setLiveMessage] = useState('');\n // Re-emit identical announcements by toggling an invisible suffix so\n // screen-readers treat repeated moves as distinct (sidebar idiom).\n const announceToggle = useRef(false);\n const announce = useCallback((message: string) => {\n announceToggle.current = !announceToggle.current;\n setLiveMessage(announceToggle.current ? message : `${message}\\u200b`);\n }, []);\n\n const value = useMemo<ReorderContextValue>(\n () => ({ onReorder, count, dragSource, setDragSource, announce, t }),\n [onReorder, count, dragSource, announce, t],\n );\n\n return (\n <ReorderContext.Provider value={value}>\n {children}\n <span role=\"status\" aria-live=\"polite\" className=\"ds:sr-only\">\n {liveMessage}\n </span>\n </ReorderContext.Provider>\n );\n}\n\n/* ---------------------------------- Row ----------------------------------- */\n\nexport interface AnamnesisReorderRowRender {\n /** Spread onto the element that drags as one unit (the `<li>`, the section\n * header row…). `className` carries the dragging / drop-target affordances —\n * merge it with the row's own classes. */\n rowProps: {\n draggable: true;\n onDragStart: (event: DragEvent<HTMLElement>) => void;\n onDragEnd: () => void;\n onDragOver: (event: DragEvent<HTMLElement>) => void;\n onDragLeave: () => void;\n onDrop: (event: DragEvent<HTMLElement>) => void;\n className: string;\n };\n /** The grip button — mount it INSIDE the row's action group so the drag\n * affordance sits with the row's other controls. */\n handle: ReactElement;\n}\n\nexport interface AnamnesisReorderRowProps {\n /** Zero-based DISPLAY position of this row within its group. */\n index: number;\n /** Accessible name of the row — names the handle and the announcements. */\n label: string;\n children: (row: AnamnesisReorderRowRender) => ReactElement;\n}\n\nexport function AnamnesisReorderRow({\n index,\n label,\n children,\n}: AnamnesisReorderRowProps) {\n const group = useContext(ReorderContext);\n const [isDropTarget, setIsDropTarget] = useState(false);\n if (!group) {\n throw new Error(\n 'AnamnesisReorderRow must render inside an AnamnesisReorderGroup',\n );\n }\n const { t } = group;\n\n const moveFromTo = (from: number, to: number) => {\n const clamped = Math.max(0, Math.min(group.count - 1, to));\n if (clamped === from) return;\n group.onReorder(from, clamped);\n group.announce(\n t('anamnesis.configEditor.reorderAnnounce', {\n name: label,\n to: clamped + 1,\n total: group.count,\n }),\n );\n };\n\n const onHandleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (!event.altKey) return;\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n moveFromTo(index, index - 1);\n } else if (event.key === 'ArrowDown') {\n event.preventDefault();\n moveFromTo(index, index + 1);\n } else if (event.key === 'Home') {\n event.preventDefault();\n moveFromTo(index, 0);\n } else if (event.key === 'End') {\n event.preventDefault();\n moveFromTo(index, group.count - 1);\n }\n };\n\n const isDragging = group.dragSource === index;\n\n const rowProps: AnamnesisReorderRowRender['rowProps'] = {\n draggable: true,\n onDragStart: (event) => {\n group.setDragSource(index);\n event.dataTransfer.effectAllowed = 'move';\n // Firefox requires data to initiate a drag.\n event.dataTransfer.setData('text/plain', String(index));\n },\n onDragEnd: () => {\n group.setDragSource(null);\n setIsDropTarget(false);\n },\n onDragOver: (event) => {\n // Only a drag that started in THIS group may target the row.\n if (group.dragSource === null) return;\n event.preventDefault();\n event.dataTransfer.dropEffect = 'move';\n setIsDropTarget(true);\n },\n onDragLeave: () => setIsDropTarget(false),\n onDrop: (event) => {\n event.preventDefault();\n const source = group.dragSource;\n setIsDropTarget(false);\n group.setDragSource(null);\n if (source === null || source === index) return;\n moveFromTo(source, index);\n },\n className: reorderRowClasses({\n dragging: isDragging,\n dropTarget: isDropTarget && !isDragging,\n }),\n };\n\n const handle = (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<GripVertical aria-hidden=\"true\" />}\n aria-label={t('anamnesis.configEditor.reorderHandle', { name: label })}\n className=\"ds:cursor-grab ds:active:cursor-grabbing\"\n onKeyDown={onHandleKeyDown}\n />\n );\n\n return children({ rowProps, handle });\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — practice-configuration editor */\n/* */\n/* A PROVISIONAL editor over `PracticeAnamnesisConfig` — the three */\n/* model-backed vocabularies (questionnaire sections + fields, numeric */\n/* parameters, pathology codes) with the operations the resolver contract */\n/* supports: relabel, help text (intake fields only — nothing else renders */\n/* it), reorder, archive/restore, and free-form add. The PRODUCTION */\n/* editor is still gated on the customer's real specification (six */\n/* vocabularies, mandatory / at-a-glance columns) — see anamnesis.mdx */\n/* § Practice configuration. */\n/* */\n/* Contract obligations the UI enforces (the resolvers cannot): */\n/* • Entries are NEVER removed — archive (`enabled: false`) only, so */\n/* recorded answers survive under the history resolvers. */\n/* • Locked keys (weight / height / bmi) offer no archive control — */\n/* resolvers refuse the archive, but a whole-list replace could drop */\n/* them physically, so the editor never offers the path at all. */\n/* • `locked` is never written; the resolvers stamp it from the key set. */\n/* • Keys are derived from the label at creation and immutable after — */\n/* renaming a key would orphan every answer recorded under it. */\n/* */\n/* Controlled: the host owns the config state and passes it back down to */\n/* every mounted anamnesis surface's `config` prop — one shared object is */\n/* the whole live-update story. */\n/* -------------------------------------------------------------------- */\n\nimport { useState } from 'react';\nimport type { TFunction } from 'i18next';\nimport { Archive, ArchiveRestore, Lock, Pencil, Plus } from 'lucide-react';\nimport { Badge } from '../../components/badge';\nimport { Button } from '../../components/button';\nimport { Card } from '../../components/card';\nimport { Dialog } from '../../components/dialog';\nimport { FormField } from '../../components/form-field';\nimport { IconButton } from '../../components/icon-button';\nimport { IconButtonGroup } from '../../components/icon-button-group';\nimport { List } from '../../components/list';\nimport { Select, type SelectOption } from '../../components/select';\nimport { Switch } from '../../components/switch';\nimport { Tabs } from '../../components/tabs';\nimport { TextArea } from '../../components/text-area';\nimport { TextInput } from '../../components/text-input';\nimport {\n SEEDED_ANAMNESIS_CONFIG,\n allParametersIncludingArchived,\n allPathologiesIncludingArchived,\n allSectionsIncludingArchived,\n configuredParameters,\n configuredPathologies,\n configuredSections,\n type PracticeAnamnesisConfig,\n} from './anamnesis-config';\nimport {\n intakeFieldHelp,\n intakeFieldLabel,\n parameterLabelWithUnit,\n pathologyCodeWithLabel,\n sectionLabel,\n} from './anamnesis-format';\nimport {\n AnamnesisReorderGroup,\n AnamnesisReorderRow,\n} from './anamnesis-reorder';\nimport type {\n BetterDirection,\n ConfigurableDescriptor,\n IntakeFieldDef,\n IntakeFieldType,\n IntakeSectionDef,\n NumericParameterDef,\n ParameterGroup,\n PathologyCode,\n} from './anamnesis-types';\n\nexport interface AnamnesisConfigEditorProps {\n /** The practice's vocabulary — materialised (every list present). Build the\n * initial value with `seededConfigDraft()`, never from the module constants\n * directly: the editor patches lists immutably, but a shared array identity\n * with the kit seed would leak one accidental in-place edit into every\n * other mount in the session. */\n config: Required<PracticeAnamnesisConfig>;\n onConfigChange: (next: Required<PracticeAnamnesisConfig>) => void;\n t: TFunction;\n /** Override the cascade / test marker (defaults to `anamnesis-config-editor`). */\n dataComponent?: string;\n}\n\n/** A per-entry deep-enough clone of the kit seed: sections own their `fields`\n * arrays and parameters their `referenceRange` objects, so no array or object\n * identity is shared with the module constants. */\nexport function seededConfigDraft(): Required<PracticeAnamnesisConfig> {\n return {\n parameters: SEEDED_ANAMNESIS_CONFIG.parameters.map((def) => ({\n ...def,\n ...(def.referenceRange\n ? { referenceRange: { ...def.referenceRange } }\n : {}),\n })),\n intakeSections: SEEDED_ANAMNESIS_CONFIG.intakeSections.map((section) => ({\n ...section,\n fields: section.fields.map((field) => ({ ...field })),\n })),\n pathologies: SEEDED_ANAMNESIS_CONFIG.pathologies.map((code) => ({\n ...code,\n })),\n };\n}\n\n/* ------------------------------ Key derivation --------------------------- */\n\n/** Derive an immutable camelCase key from a practice label — the practice\n * never types identifiers, and a labelled entry can never render as a raw\n * key. Uniquified with a numeric suffix on collision. Practice-derived keys\n * are practice-LOCAL: they do not join any shared cross-practice vocabulary\n * (the curated-library question — decision 0.3 — is still open). */\nexport function keyFromLabel(\n label: string,\n taken: ReadonlySet<string>,\n): string {\n const words = label\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^a-zA-Z0-9]+/g, ' ')\n .trim()\n .split(/\\s+/)\n .filter(Boolean);\n const base =\n words.length === 0\n ? 'entry'\n : words\n .map((word, index) =>\n index === 0\n ? word.toLowerCase()\n : word[0].toUpperCase() + word.slice(1).toLowerCase(),\n )\n .join('');\n let key = base;\n let suffix = 2;\n while (taken.has(key)) {\n key = `${base}${suffix}`;\n suffix += 1;\n }\n return key;\n}\n\n/* ------------------------------ List patching ---------------------------- */\n\n/** Move a display-ordered subset entry from `from` to `to`, returning the new\n * display order — or null when the move is out of bounds or a no-op. */\nfunction moveIndex<T>(\n displayed: readonly T[],\n from: number,\n to: number,\n): T[] | null {\n if (from === to) return null;\n if (from < 0 || from >= displayed.length) return null;\n if (to < 0 || to >= displayed.length) return null;\n const next = [...displayed];\n const [entry] = next.splice(from, 1);\n next.splice(to, 0, entry);\n return next;\n}\n\n/* ------------------------------- Dialog state ---------------------------- */\n\ntype EditTarget =\n | { kind: 'parameter'; entry: NumericParameterDef }\n | { kind: 'section'; entry: IntakeSectionDef }\n | { kind: 'field'; sectionKey: string; entry: IntakeFieldDef }\n | { kind: 'pathology'; entry: PathologyCode };\n\ntype AddTarget =\n | { kind: 'parameter' }\n | { kind: 'section' }\n | { kind: 'field'; sectionKey: string }\n | { kind: 'pathology' };\n\n/** The add dialog's answer-type list — UI-level entries: the two number\n * variants both map onto `type: 'number'`, with and without the `decimal`\n * flag; everything else maps one-to-one. */\nconst ADD_FIELD_TYPES = [\n 'text',\n 'textarea',\n 'numberInteger',\n 'numberDecimal',\n 'yesNoDetail',\n 'choice',\n 'choiceWithText',\n 'multiChoice',\n 'frequency',\n 'meal',\n] as const;\ntype AddFieldTypeChoice = (typeof ADD_FIELD_TYPES)[number];\n\n/** Seeded field keys — options on THESE are i18n key suffixes, so the editor\n * shows them read-only; a practice-added field's options are verbatim\n * practice wording and stay editable. */\nconst SEEDED_FIELD_KEYS: ReadonlySet<string> = new Set(\n SEEDED_ANAMNESIS_CONFIG.intakeSections.flatMap((section) =>\n section.fields.map((field) => field.key),\n ),\n);\n\n/** The UI label for a field's answer type — number splits into its integer /\n * decimal variants. */\nfunction fieldTypeLabel(def: IntakeFieldDef, t: TFunction): string {\n const key =\n def.type === 'number'\n ? def.decimal\n ? 'numberDecimal'\n : 'numberInteger'\n : def.type === 'choice' && def.detail\n ? 'choiceWithText'\n : def.type;\n return t(`anamnesis.configEditor.type.${key}`);\n}\n\nconst DIRECTIONS: BetterDirection[] = ['down', 'up', 'toRange'];\n\nconst GROUPS: ParameterGroup[] = ['anthropometric', 'dietary', 'lab'];\n\n/* ------------------------------- The editor ------------------------------ */\n\nexport function AnamnesisConfigEditor({\n config,\n onConfigChange,\n t,\n dataComponent = 'anamnesis-config-editor',\n}: AnamnesisConfigEditorProps) {\n const [editing, setEditing] = useState<EditTarget | null>(null);\n const [adding, setAdding] = useState<AddTarget | null>(null);\n\n /* ---------------------------- Patch helpers ---------------------------- */\n\n const patchParameters = (\n map: (def: NumericParameterDef) => NumericParameterDef,\n ) => onConfigChange({ ...config, parameters: config.parameters.map(map) });\n\n const patchSections = (\n map: (section: IntakeSectionDef) => IntakeSectionDef,\n ) =>\n onConfigChange({\n ...config,\n intakeSections: config.intakeSections.map(map),\n });\n\n const patchField = (\n sectionKey: string,\n fieldKey: string,\n map: (field: IntakeFieldDef) => IntakeFieldDef,\n ) =>\n patchSections((section) =>\n section.key === sectionKey\n ? {\n ...section,\n fields: section.fields.map((field) =>\n field.key === fieldKey ? map(field) : field,\n ),\n }\n : section,\n );\n\n const patchPathologies = (map: (code: PathologyCode) => PathologyCode) =>\n onConfigChange({ ...config, pathologies: config.pathologies.map(map) });\n\n /* ------------------------------- Reorder -------------------------------- */\n // Rewrites `order` as the displayed index across the FULL sibling subset —\n // archived rows included, because the history resolvers order the whole\n // subset while capture filters live-first; rewriting only live rows would\n // let the editor's order diverge from the history surfaces'. `from`/`to`\n // are display indices, handed over by the drag-and-drop / keyboard idiom\n // in `anamnesis-reorder.tsx`.\n\n const reorderParameter = (\n group: ParameterGroup,\n from: number,\n to: number,\n ) => {\n const displayed = allParametersIncludingArchived(config, group);\n const moved = moveIndex(displayed, from, to);\n if (!moved) return;\n // Match by key: the displayed entries are resolver-stamped copies, not\n // the config's own object identities.\n const orderByKey = new Map(moved.map((def, i) => [def.key, i] as const));\n patchParameters((def) =>\n orderByKey.has(def.key)\n ? { ...def, order: orderByKey.get(def.key) }\n : def,\n );\n };\n\n const reorderSection = (from: number, to: number) => {\n const moved = moveIndex(allSectionsIncludingArchived(config), from, to);\n if (!moved) return;\n const orderByKey = new Map(\n moved.map((section, i) => [section.key, i] as const),\n );\n patchSections((section) =>\n orderByKey.has(section.key)\n ? { ...section, order: orderByKey.get(section.key) }\n : section,\n );\n };\n\n const reorderField = (\n section: IntakeSectionDef,\n from: number,\n to: number,\n ) => {\n const moved = moveIndex(section.fields, from, to);\n if (!moved) return;\n const orderByKey = new Map(\n moved.map((field, i) => [field.key, i] as const),\n );\n patchSections((candidate) =>\n candidate.key === section.key\n ? {\n ...candidate,\n fields: candidate.fields.map((field) =>\n orderByKey.has(field.key)\n ? { ...field, order: orderByKey.get(field.key) }\n : field,\n ),\n }\n : candidate,\n );\n };\n\n /* ------------------------------ Row actions ----------------------------- */\n\n const setEnabled = (target: EditTarget, enabled: boolean | undefined) => {\n if (target.kind === 'parameter')\n patchParameters((def) =>\n def.key === target.entry.key ? { ...def, enabled } : def,\n );\n else if (target.kind === 'section')\n patchSections((section) =>\n section.key === target.entry.key ? { ...section, enabled } : section,\n );\n else if (target.kind === 'field')\n patchField(target.sectionKey, target.entry.key, (field) => ({\n ...field,\n enabled,\n }));\n else\n patchPathologies((code) =>\n code.code === target.entry.code ? { ...code, enabled } : code,\n );\n };\n\n /* -------------------------------- Render -------------------------------- */\n\n const liveParameters = configuredParameters(config).length;\n const allParameters = allParametersIncludingArchived(config).length;\n const liveFields = configuredSections(config).reduce(\n (count, section) => count + section.fields.length,\n 0,\n );\n const allFields = allSectionsIncludingArchived(config).reduce(\n (count, section) => count + section.fields.length,\n 0,\n );\n const livePathologies = configuredPathologies(config).length;\n const allPathologies = allPathologiesIncludingArchived(config).length;\n const trackedGoals = configuredParameters(config).filter(\n (def) => def.goal === true,\n ).length;\n\n return (\n <div\n data-component={dataComponent}\n data-mode=\"config\"\n className=\"ds:flex ds:w-full ds:flex-col ds:gap-[var(--spacing-lg)]\"\n >\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <h2 className=\"type-title-section ds:m-0 ds:text-[color:var(--foreground)]\">\n {t('anamnesis.configEditor.title')}\n </h2>\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.configEditor.intro')}\n </p>\n </div>\n\n <Card variant=\"elevated\">\n <Card.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <Tabs defaultValue=\"questionnaire\">\n <Tabs.List aria-label={t('anamnesis.configEditor.tabsLabel')}>\n <Tabs.Trigger value=\"questionnaire\">\n {t('anamnesis.configEditor.tabQuestionnaire')}\n </Tabs.Trigger>\n <Tabs.Trigger value=\"parameters\">\n {t('anamnesis.configEditor.tabParameters')}\n </Tabs.Trigger>\n <Tabs.Trigger value=\"pathologies\">\n {t('anamnesis.configEditor.tabPathologies')}\n </Tabs.Trigger>\n <Tabs.Trigger value=\"targets\">\n {t('anamnesis.configEditor.tabTargets')}\n </Tabs.Trigger>\n </Tabs.List>\n\n {/* ------------------------ Questionnaire ----------------------- */}\n <Tabs.Content value=\"questionnaire\">\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)] ds:pt-[var(--spacing-md)]\">\n <p className=\"type-meta ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {`${t('anamnesis.configEditor.panelLive', {\n count: liveFields,\n })} · ${t('anamnesis.configEditor.panelNotCaptured', {\n // Not \"archived\": this also counts live questions inside\n // an archived section, which capture drops as a whole.\n count: allFields - liveFields,\n })}`}\n </p>\n <AnamnesisReorderGroup\n count={allSectionsIncludingArchived(config).length}\n onReorder={reorderSection}\n t={t}\n >\n {allSectionsIncludingArchived(config).map(\n (section, sectionIndex) => {\n const archived = section.enabled === false;\n const liveInSection = section.fields.filter(\n (field) => field.enabled !== false,\n ).length;\n return (\n <AnamnesisReorderRow\n key={section.key}\n index={sectionIndex}\n label={sectionLabel(section, t)}\n >\n {({\n rowProps: sectionRowProps,\n handle: sectionHandle,\n }) => (\n <section className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {/* The HEADER row is the drag unit — dragging the whole\n section (fields included) would make the drop target\n ambiguous under long field lists. */}\n <div\n {...sectionRowProps}\n className={[\n 'ds:flex ds:flex-wrap ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]',\n sectionRowProps.className,\n ]\n .filter(Boolean)\n .join(' ')}\n >\n <h3 className=\"type-title-item ds:m-0 ds:flex ds:items-center ds:gap-[var(--spacing-xs)] ds:text-[color:var(--foreground)]\">\n {sectionLabel(section, t)}\n {archived ? (\n <Badge size=\"sm\" variant=\"neutral\">\n {t('anamnesis.configEditor.archived')}\n </Badge>\n ) : null}\n </h3>\n <IconButtonGroup\n aria-label={t(\n 'anamnesis.configEditor.rowActions',\n {\n name: sectionLabel(section, t),\n },\n )}\n >\n {sectionHandle}\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<Pencil aria-hidden=\"true\" />}\n aria-label={t(\n 'anamnesis.configEditor.edit',\n {\n name: sectionLabel(section, t),\n },\n )}\n onClick={() =>\n setEditing({\n kind: 'section',\n entry: section,\n })\n }\n />\n {archived ? (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={\n <ArchiveRestore aria-hidden=\"true\" />\n }\n aria-label={t(\n 'anamnesis.configEditor.restore',\n { name: sectionLabel(section, t) },\n )}\n onClick={() =>\n setEnabled(\n { kind: 'section', entry: section },\n undefined,\n )\n }\n />\n ) : (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<Archive aria-hidden=\"true\" />}\n aria-label={t(\n 'anamnesis.configEditor.archive',\n { name: sectionLabel(section, t) },\n )}\n onClick={() =>\n setEnabled(\n { kind: 'section', entry: section },\n false,\n )\n }\n />\n )}\n </IconButtonGroup>\n </div>\n {liveInSection === 0 && !archived ? (\n <p className=\"type-meta ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t(\n 'anamnesis.configEditor.sectionEmptyCapture',\n )}\n </p>\n ) : null}\n {section.fields.length > 0 ? (\n <AnamnesisReorderGroup\n count={section.fields.length}\n onReorder={(from, to) =>\n reorderField(section, from, to)\n }\n t={t}\n >\n <List divider=\"divided\">\n {section.fields.map((field, fieldIndex) => (\n <AnamnesisReorderRow\n key={field.key}\n index={fieldIndex}\n label={intakeFieldLabel(field, t)}\n >\n {({ rowProps, handle }) => (\n <List.Item\n {...rowProps}\n title={\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n {intakeFieldLabel(field, t)}\n {field.required === true ? (\n <Badge\n size=\"sm\"\n variant=\"info\"\n >\n {t(\n 'anamnesis.configEditor.requiredBadge',\n )}\n </Badge>\n ) : null}\n {field.enabled === false ? (\n <Badge\n size=\"sm\"\n variant=\"neutral\"\n >\n {t(\n 'anamnesis.configEditor.archived',\n )}\n </Badge>\n ) : null}\n </span>\n }\n description={[\n fieldTypeLabel(field, t),\n intakeFieldHelp(field, t),\n ]\n .filter(Boolean)\n .join(' · ')}\n trailing={\n <IconButtonGroup\n aria-label={t(\n 'anamnesis.configEditor.rowActions',\n {\n name: intakeFieldLabel(\n field,\n t,\n ),\n },\n )}\n >\n {handle}\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={\n <Pencil aria-hidden=\"true\" />\n }\n aria-label={t(\n 'anamnesis.configEditor.edit',\n {\n name: intakeFieldLabel(\n field,\n t,\n ),\n },\n )}\n onClick={() =>\n setEditing({\n kind: 'field',\n sectionKey: section.key,\n entry: field,\n })\n }\n />\n {field.enabled === false ? (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={\n <ArchiveRestore aria-hidden=\"true\" />\n }\n aria-label={t(\n 'anamnesis.configEditor.restore',\n {\n name: intakeFieldLabel(\n field,\n t,\n ),\n },\n )}\n onClick={() =>\n setEnabled(\n {\n kind: 'field',\n sectionKey:\n section.key,\n entry: field,\n },\n undefined,\n )\n }\n />\n ) : (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={\n <Archive aria-hidden=\"true\" />\n }\n aria-label={t(\n 'anamnesis.configEditor.archive',\n {\n name: intakeFieldLabel(\n field,\n t,\n ),\n },\n )}\n onClick={() =>\n setEnabled(\n {\n kind: 'field',\n sectionKey:\n section.key,\n entry: field,\n },\n false,\n )\n }\n />\n )}\n </IconButtonGroup>\n }\n />\n )}\n </AnamnesisReorderRow>\n ))}\n </List>\n </AnamnesisReorderGroup>\n ) : null}\n {/* Free-form add stays visually secondary: the\n curated-vs-free-form question (0.3) is open, and\n the kit-seeded set is the primary story. */}\n <div>\n <Button\n intent=\"ghost\"\n size=\"sm\"\n startIcon={<Plus aria-hidden=\"true\" />}\n onClick={() =>\n setAdding({\n kind: 'field',\n sectionKey: section.key,\n })\n }\n >\n {t('anamnesis.configEditor.addQuestion')}\n </Button>\n </div>\n </section>\n )}\n </AnamnesisReorderRow>\n );\n },\n )}\n </AnamnesisReorderGroup>\n <div>\n <Button\n intent=\"outline\"\n size=\"sm\"\n startIcon={<Plus aria-hidden=\"true\" />}\n onClick={() => setAdding({ kind: 'section' })}\n >\n {t('anamnesis.configEditor.addSection')}\n </Button>\n </div>\n </div>\n </Tabs.Content>\n\n {/* ------------------------- Parameters ------------------------- */}\n <Tabs.Content value=\"parameters\">\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)] ds:pt-[var(--spacing-md)]\">\n <p className=\"type-meta ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {`${t('anamnesis.configEditor.panelLive', {\n count: liveParameters,\n })} · ${t('anamnesis.configEditor.panelArchived', {\n count: allParameters - liveParameters,\n })}`}\n </p>\n {GROUPS.map((group) => {\n const displayed = allParametersIncludingArchived(\n config,\n group,\n );\n if (displayed.length === 0) return null;\n return (\n <section\n key={group}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <h3 className=\"type-title-item ds:m-0 ds:text-[color:var(--foreground)]\">\n {t(`anamnesis.group.${group}`)}\n </h3>\n <AnamnesisReorderGroup\n count={displayed.length}\n onReorder={(from, to) =>\n reorderParameter(group, from, to)\n }\n t={t}\n >\n <List divider=\"divided\">\n {displayed.map((def, index) => {\n const meta = [\n parameterRangeText(def, t),\n t(\n `anamnesis.configEditor.direction.${def.betterDirection}`,\n ),\n def.locked\n ? t('anamnesis.configEditor.lockedHint')\n : null,\n ]\n .filter(Boolean)\n .join(' · ');\n return (\n <AnamnesisReorderRow\n key={def.key}\n index={index}\n label={parameterLabelWithUnit(def, t)}\n >\n {({ rowProps, handle }) => (\n <List.Item\n {...rowProps}\n title={\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n {parameterLabelWithUnit(def, t)}\n {def.locked ? (\n <Badge\n size=\"sm\"\n variant=\"neutral\"\n leading={\n <Lock aria-hidden=\"true\" />\n }\n >\n {t('anamnesis.configEditor.locked')}\n </Badge>\n ) : null}\n {def.enabled === false ? (\n <Badge size=\"sm\" variant=\"neutral\">\n {t(\n 'anamnesis.configEditor.archived',\n )}\n </Badge>\n ) : null}\n </span>\n }\n description={meta}\n trailing={\n <IconButtonGroup\n aria-label={t(\n 'anamnesis.configEditor.rowActions',\n {\n name: parameterLabelWithUnit(\n def,\n t,\n ),\n },\n )}\n >\n {handle}\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<Pencil aria-hidden=\"true\" />}\n aria-label={t(\n 'anamnesis.configEditor.edit',\n {\n name: parameterLabelWithUnit(\n def,\n t,\n ),\n },\n )}\n onClick={() =>\n setEditing({\n kind: 'parameter',\n entry: def,\n })\n }\n />\n {def.locked ? null : def.enabled ===\n false ? (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={\n <ArchiveRestore aria-hidden=\"true\" />\n }\n aria-label={t(\n 'anamnesis.configEditor.restore',\n {\n name: parameterLabelWithUnit(\n def,\n t,\n ),\n },\n )}\n onClick={() =>\n setEnabled(\n {\n kind: 'parameter',\n entry: def,\n },\n undefined,\n )\n }\n />\n ) : (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={\n <Archive aria-hidden=\"true\" />\n }\n aria-label={t(\n 'anamnesis.configEditor.archive',\n {\n name: parameterLabelWithUnit(\n def,\n t,\n ),\n },\n )}\n onClick={() =>\n setEnabled(\n {\n kind: 'parameter',\n entry: def,\n },\n false,\n )\n }\n />\n )}\n </IconButtonGroup>\n }\n />\n )}\n </AnamnesisReorderRow>\n );\n })}\n </List>\n </AnamnesisReorderGroup>\n </section>\n );\n })}\n <div>\n <Button\n intent=\"outline\"\n size=\"sm\"\n startIcon={<Plus aria-hidden=\"true\" />}\n onClick={() => setAdding({ kind: 'parameter' })}\n >\n {t('anamnesis.configEditor.addParameter')}\n </Button>\n </div>\n </div>\n </Tabs.Content>\n\n {/* ------------------------- Pathologies ------------------------ */}\n <Tabs.Content value=\"pathologies\">\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)] ds:pt-[var(--spacing-md)]\">\n <p className=\"type-meta ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {`${t('anamnesis.configEditor.panelLive', {\n count: livePathologies,\n })} · ${t('anamnesis.configEditor.panelArchived', {\n count: allPathologies - livePathologies,\n })}`}\n </p>\n <List divider=\"divided\">\n {allPathologiesIncludingArchived(config).map((code) => {\n const isHeading = config.pathologies.some(\n (candidate) =>\n candidate.parentCode === code.code &&\n candidate.enabled !== false,\n );\n const meta = [\n code.parentCode\n ? t('anamnesis.configEditor.subCodeOf', {\n code: code.parentCode,\n })\n : null,\n isHeading\n ? t('anamnesis.configEditor.familyHeading')\n : null,\n ]\n .filter(Boolean)\n .join(' · ');\n return (\n <List.Item\n key={code.code}\n title={\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n {pathologyCodeWithLabel(code.code, t, code)}\n {code.enabled === false ? (\n <Badge size=\"sm\" variant=\"neutral\">\n {t('anamnesis.configEditor.archived')}\n </Badge>\n ) : null}\n </span>\n }\n description={meta || undefined}\n trailing={\n <IconButtonGroup\n aria-label={t('anamnesis.configEditor.rowActions', {\n name: pathologyCodeWithLabel(code.code, t, code),\n })}\n >\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<Pencil aria-hidden=\"true\" />}\n aria-label={t('anamnesis.configEditor.edit', {\n name: pathologyCodeWithLabel(\n code.code,\n t,\n code,\n ),\n })}\n onClick={() =>\n setEditing({ kind: 'pathology', entry: code })\n }\n />\n {code.enabled === false ? (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<ArchiveRestore aria-hidden=\"true\" />}\n aria-label={t(\n 'anamnesis.configEditor.restore',\n {\n name: pathologyCodeWithLabel(\n code.code,\n t,\n code,\n ),\n },\n )}\n onClick={() =>\n setEnabled(\n { kind: 'pathology', entry: code },\n undefined,\n )\n }\n />\n ) : (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<Archive aria-hidden=\"true\" />}\n aria-label={t(\n 'anamnesis.configEditor.archive',\n {\n name: pathologyCodeWithLabel(\n code.code,\n t,\n code,\n ),\n },\n )}\n onClick={() =>\n setEnabled(\n { kind: 'pathology', entry: code },\n false,\n )\n }\n />\n )}\n </IconButtonGroup>\n }\n />\n );\n })}\n </List>\n <div>\n <Button\n intent=\"outline\"\n size=\"sm\"\n startIcon={<Plus aria-hidden=\"true\" />}\n onClick={() => setAdding({ kind: 'pathology' })}\n >\n {t('anamnesis.configEditor.addCode')}\n </Button>\n </div>\n </div>\n </Tabs.Content>\n {/* -------------------------- Targets --------------------------- */}\n {/* The practice's tracked goals — WHICH parameters ride the goals\n strip. Membership only: each patient's target VALUE is set on\n the goal tile above the record, where the current-vs-target\n status is read. Computed BMI is a perfectly valid goal — the\n rows are the live capture set, computed included. */}\n <Tabs.Content value=\"targets\">\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)] ds:pt-[var(--spacing-md)]\">\n <p className=\"type-meta ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.configEditor.panelTracked', {\n count: trackedGoals,\n })}\n </p>\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.configEditor.targetsIntro')}\n </p>\n {GROUPS.map((group) => {\n const live = configuredParameters(config, group);\n if (live.length === 0) return null;\n return (\n <section\n key={group}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <h3 className=\"type-title-item ds:m-0 ds:text-[color:var(--foreground)]\">\n {t(`anamnesis.group.${group}`)}\n </h3>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {live.map((def) => (\n <Switch\n key={def.key}\n label={parameterLabelWithUnit(def, t)}\n checked={def.goal === true}\n onCheckedChange={(checked) =>\n patchParameters((candidate) =>\n candidate.key === def.key\n ? { ...candidate, goal: checked === true }\n : candidate,\n )\n }\n />\n ))}\n </div>\n </section>\n );\n })}\n </div>\n </Tabs.Content>\n </Tabs>\n </Card.Body>\n </Card>\n\n <EditDialog\n editing={editing}\n onClose={() => setEditing(null)}\n config={config}\n onConfigChange={onConfigChange}\n t={t}\n />\n <AddDialog\n adding={adding}\n onClose={() => setAdding(null)}\n config={config}\n onConfigChange={onConfigChange}\n t={t}\n />\n </div>\n );\n}\n\n/* ------------------------------ Range display ---------------------------- */\n\nfunction parameterRangeText(\n def: NumericParameterDef,\n t: TFunction,\n): string | null {\n const range = def.referenceRange;\n if (!range) return null;\n if (range.min != null && range.max != null)\n return `${range.min}–${range.max}`;\n if (range.max != null)\n return t('anamnesis.range.atMost', { value: range.max });\n if (range.min != null)\n return t('anamnesis.range.atLeast', { value: range.min });\n return null;\n}\n\n/* ------------------------------- Edit dialog ----------------------------- */\n\n/** Relabel + help. The practice override is stored only when non-empty —\n * clearing the input deletes the override so the kit translation resumes.\n * Help text is offered on INTAKE FIELDS only; no other vocabulary renders it. */\nfunction EditDialog({\n editing,\n onClose,\n config,\n onConfigChange,\n t,\n}: {\n editing: EditTarget | null;\n onClose: () => void;\n config: Required<PracticeAnamnesisConfig>;\n onConfigChange: (next: Required<PracticeAnamnesisConfig>) => void;\n t: TFunction;\n}) {\n // Keyed remount resets the form state whenever a different row opens.\n return (\n <Dialog\n open={editing !== null}\n onOpenChange={(open) => {\n if (!open) onClose();\n }}\n >\n {editing ? (\n <EditDialogBody\n key={editKeyOf(editing)}\n editing={editing}\n onClose={onClose}\n config={config}\n onConfigChange={onConfigChange}\n t={t}\n />\n ) : null}\n </Dialog>\n );\n}\n\nfunction editKeyOf(editing: EditTarget): string {\n return editing.kind === 'pathology'\n ? `pathology:${editing.entry.code}`\n : editing.kind === 'field'\n ? `field:${editing.sectionKey}:${editing.entry.key}`\n : `${editing.kind}:${editing.entry.key}`;\n}\n\nfunction EditDialogBody({\n editing,\n onClose,\n config,\n onConfigChange,\n t,\n}: {\n editing: EditTarget;\n onClose: () => void;\n config: Required<PracticeAnamnesisConfig>;\n onConfigChange: (next: Required<PracticeAnamnesisConfig>) => void;\n t: TFunction;\n}) {\n const entry = editing.entry;\n const kitLabel = effectiveKitLabel(editing, t);\n const [label, setLabel] = useState(entry.label ?? '');\n const [helpText, setHelpText] = useState(\n editing.kind === 'field' ? (entry.helpText ?? '') : '',\n );\n const [required, setRequired] = useState(\n editing.kind === 'field' && editing.entry.required === true,\n );\n // (Multi-)choice options: editable on PRACTICE-ADDED fields (verbatim\n // wording), read-only on seeded ones (i18n key suffixes — editing them\n // would break every locale's option labels).\n const editableField = editing.kind === 'field' ? editing.entry : null;\n const isChoiceField =\n editableField !== null &&\n (editableField.type === 'choice' || editableField.type === 'multiChoice');\n const optionsEditable =\n isChoiceField && !SEEDED_FIELD_KEYS.has(editableField.key);\n const [options, setOptions] = useState(\n optionsEditable ? (editableField.options ?? []).join(', ') : '',\n );\n const editedOptions = options\n .split(',')\n .map((option) => option.trim())\n .filter(Boolean);\n const optionsValid = !optionsEditable || editedOptions.length > 0;\n\n const save = () => {\n const nextLabel = label.trim();\n const patch = (descriptor: ConfigurableDescriptor) => {\n const next = { ...descriptor };\n if (nextLabel) next.label = nextLabel;\n else delete next.label;\n return next;\n };\n if (editing.kind === 'parameter')\n onConfigChange({\n ...config,\n parameters: config.parameters.map((def) =>\n def.key === editing.entry.key\n ? (patch(def) as NumericParameterDef)\n : def,\n ),\n });\n else if (editing.kind === 'section')\n onConfigChange({\n ...config,\n intakeSections: config.intakeSections.map((section) =>\n section.key === editing.entry.key\n ? (patch(section) as IntakeSectionDef)\n : section,\n ),\n });\n else if (editing.kind === 'field') {\n const nextHelp = helpText.trim();\n onConfigChange({\n ...config,\n intakeSections: config.intakeSections.map((section) =>\n section.key === editing.sectionKey\n ? {\n ...section,\n fields: section.fields.map((field) => {\n if (field.key !== editing.entry.key) return field;\n const next = patch(field) as IntakeFieldDef;\n if (nextHelp) next.helpText = nextHelp;\n else delete next.helpText;\n if (optionsEditable) next.options = editedOptions;\n if (required) next.required = true;\n else delete next.required;\n return next;\n }),\n }\n : section,\n ),\n });\n } else\n onConfigChange({\n ...config,\n pathologies: config.pathologies.map((code) =>\n code.code === (entry as PathologyCode).code\n ? (patch(code) as PathologyCode)\n : code,\n ),\n });\n onClose();\n };\n\n return (\n <Dialog.Content size=\"sm\">\n <Dialog.Header>\n <Dialog.Title>\n {t('anamnesis.configEditor.editTitle', { name: kitLabel })}\n </Dialog.Title>\n <Dialog.Description>\n {editing.kind === 'pathology'\n ? t('anamnesis.configEditor.codeLine', {\n code: (entry as PathologyCode).code,\n })\n : editing.kind === 'field'\n ? `${t('anamnesis.configEditor.keyLine', {\n key: editing.entry.key,\n })} ${t('anamnesis.configEditor.typeLine', {\n type: fieldTypeLabel(editing.entry, t),\n })}`\n : t('anamnesis.configEditor.keyLine', {\n key: (entry as { key: string }).key,\n })}\n </Dialog.Description>\n </Dialog.Header>\n <Dialog.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <FormField\n label={t('anamnesis.configEditor.labelField')}\n description={t('anamnesis.configEditor.labelFieldHelp')}\n >\n <TextInput\n value={label}\n onChange={(event) => setLabel(event.target.value)}\n placeholder={kitLabel}\n />\n </FormField>\n {editing.kind === 'field' ? (\n <FormField label={t('anamnesis.configEditor.helpField')} optional>\n <TextArea\n value={helpText}\n onChange={(event) => setHelpText(event.target.value)}\n minRows={2}\n />\n </FormField>\n ) : null}\n {editing.kind === 'field' ? (\n <Switch\n label={t('anamnesis.configEditor.requiredField')}\n checked={required}\n onCheckedChange={(checked) => setRequired(checked === true)}\n />\n ) : null}\n {optionsEditable ? (\n <FormField\n label={t('anamnesis.configEditor.optionsField')}\n description={t('anamnesis.configEditor.optionsFieldHelp')}\n required\n >\n <TextInput\n value={options}\n onChange={(event) => setOptions(event.target.value)}\n />\n </FormField>\n ) : isChoiceField ? (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.configEditor.optionsCurrent', {\n list: (editableField.options ?? [])\n .map((opt) =>\n t(`anamnesis.field.${editableField.key}.option.${opt}`, {\n defaultValue: opt,\n }),\n )\n .join(', '),\n })}\n </p>\n ) : null}\n </Dialog.Body>\n <Dialog.Footer>\n <Button intent=\"ghost\" onClick={onClose}>\n {t('anamnesis.configEditor.cancel')}\n </Button>\n <Button intent=\"primary\" onClick={save} disabled={!optionsValid}>\n {t('anamnesis.configEditor.save')}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n );\n}\n\n/** The KIT label for a descriptor — what renders when no practice override is\n * set. Used as the label input's placeholder so clearing the field shows what\n * wording resumes. */\nfunction effectiveKitLabel(editing: EditTarget, t: TFunction): string {\n if (editing.kind === 'parameter')\n return parameterLabelWithUnit({ ...editing.entry, label: undefined }, t);\n if (editing.kind === 'section')\n return sectionLabel({ ...editing.entry, label: undefined }, t);\n if (editing.kind === 'field')\n return intakeFieldLabel({ ...editing.entry, label: undefined }, t);\n return pathologyCodeWithLabel(editing.entry.code, t, {\n ...editing.entry,\n label: undefined,\n });\n}\n\n/** Whether an add-dialog type choice needs an options list. */\nfunction isChoiceType(value: AddFieldTypeChoice | ''): boolean {\n return (\n value === 'choice' || value === 'choiceWithText' || value === 'multiChoice'\n );\n}\n\n/* -------------------------------- Add dialog ----------------------------- */\n\n/** Free-form add — the SECONDARY path (decision 0.3, still open: the curated\n * kit-seeded library is the primary story). Keys/codes derive from the label\n * at creation and never change; a free-form entry is practice-local. */\nfunction AddDialog({\n adding,\n onClose,\n config,\n onConfigChange,\n t,\n}: {\n adding: AddTarget | null;\n onClose: () => void;\n config: Required<PracticeAnamnesisConfig>;\n onConfigChange: (next: Required<PracticeAnamnesisConfig>) => void;\n t: TFunction;\n}) {\n return (\n <Dialog\n open={adding !== null}\n onOpenChange={(open) => {\n if (!open) onClose();\n }}\n >\n {adding ? (\n <AddDialogBody\n key={\n adding.kind === 'field' ? `field:${adding.sectionKey}` : adding.kind\n }\n adding={adding}\n onClose={onClose}\n config={config}\n onConfigChange={onConfigChange}\n t={t}\n />\n ) : null}\n </Dialog>\n );\n}\n\nfunction AddDialogBody({\n adding,\n onClose,\n config,\n onConfigChange,\n t,\n}: {\n adding: AddTarget;\n onClose: () => void;\n config: Required<PracticeAnamnesisConfig>;\n onConfigChange: (next: Required<PracticeAnamnesisConfig>) => void;\n t: TFunction;\n}) {\n const [label, setLabel] = useState('');\n const [group, setGroup] = useState<ParameterGroup | ''>('');\n const [direction, setDirection] = useState<BetterDirection | ''>('');\n const [unit, setUnit] = useState('');\n const [rangeMin, setRangeMin] = useState('');\n const [rangeMax, setRangeMax] = useState('');\n const [precision, setPrecision] = useState<'0' | '1' | '2'>('0');\n const [fieldType, setFieldType] = useState<AddFieldTypeChoice | ''>('');\n const [options, setOptions] = useState('');\n const [helpText, setHelpText] = useState('');\n const [code, setCode] = useState('');\n const [required, setRequired] = useState(false);\n const [parentCode, setParentCode] = useState('');\n\n const groupOptions: SelectOption[] = GROUPS.map((value) => ({\n value,\n label: t(`anamnesis.group.${value}`),\n }));\n const directionOptions: SelectOption[] = DIRECTIONS.map((value) => ({\n value,\n label: t(`anamnesis.configEditor.direction.${value}`),\n }));\n const typeOptions: SelectOption[] = ADD_FIELD_TYPES.map((value) => ({\n value,\n label: t(`anamnesis.configEditor.type.${value}`),\n }));\n const parentOptions: SelectOption[] = config.pathologies\n // Top-level LIVE families only — a new live sub-code under an archived\n // parent would be assignable while its family heading is not offered.\n .filter((candidate) => !candidate.parentCode && candidate.enabled !== false)\n .map((candidate) => ({\n value: candidate.code,\n label: pathologyCodeWithLabel(candidate.code, t, candidate),\n }));\n\n const choiceOptions = options\n .split(',')\n .map((option) => option.trim())\n .filter(Boolean);\n\n const valid =\n adding.kind === 'parameter'\n ? label.trim() !== '' && group !== '' && direction !== ''\n : adding.kind === 'field'\n ? label.trim() !== '' &&\n fieldType !== '' &&\n (!isChoiceType(fieldType) || choiceOptions.length > 0)\n : adding.kind === 'section'\n ? label.trim() !== ''\n : label.trim() !== '' &&\n code.trim() !== '' &&\n // A duplicate code would collide with the existing entry\n // everywhere codes are matched (lookup, archive, edit) —\n // uniqueness is the add gate, matching keyFromLabel's guarantee\n // on the other vocabularies.\n !config.pathologies.some(\n (candidate) =>\n candidate.code.toLowerCase() === code.trim().toLowerCase(),\n );\n\n const save = () => {\n const trimmedLabel = label.trim();\n if (adding.kind === 'parameter') {\n const taken = new Set(config.parameters.map((def) => def.key));\n const parseBound = (raw: string): number | undefined => {\n if (raw.trim() === '') return undefined;\n const value = Number(raw);\n return Number.isFinite(value) ? value : undefined;\n };\n const min = parseBound(rangeMin);\n const max = parseBound(rangeMax);\n const entry: NumericParameterDef = {\n key: keyFromLabel(trimmedLabel, taken),\n label: trimmedLabel,\n group: group as ParameterGroup,\n betterDirection: direction as BetterDirection,\n precision: Number(precision),\n ...(unit.trim() ? { unit: unit.trim() } : {}),\n ...(min != null || max != null\n ? {\n referenceRange: {\n ...(min != null ? { min } : {}),\n ...(max != null ? { max } : {}),\n },\n }\n : {}),\n };\n onConfigChange({ ...config, parameters: [...config.parameters, entry] });\n } else if (adding.kind === 'field') {\n const taken = new Set(\n config.intakeSections.flatMap((section) =>\n section.fields.map((field) => field.key),\n ),\n );\n const resolvedType: IntakeFieldType =\n fieldType === 'numberInteger' || fieldType === 'numberDecimal'\n ? 'number'\n : fieldType === 'choiceWithText'\n ? 'choice'\n : (fieldType as IntakeFieldType);\n const entry: IntakeFieldDef = {\n key: keyFromLabel(trimmedLabel, taken),\n label: trimmedLabel,\n type: resolvedType,\n ...(fieldType === 'numberDecimal' ? { decimal: true } : {}),\n ...(fieldType === 'choiceWithText' ? { detail: true } : {}),\n ...(isChoiceType(fieldType) ? { options: choiceOptions } : {}),\n ...(helpText.trim() ? { helpText: helpText.trim() } : {}),\n ...(required ? { required: true } : {}),\n };\n onConfigChange({\n ...config,\n intakeSections: config.intakeSections.map((section) =>\n section.key === adding.sectionKey\n ? { ...section, fields: [...section.fields, entry] }\n : section,\n ),\n });\n } else if (adding.kind === 'section') {\n const taken = new Set(\n config.intakeSections.map((section) => section.key),\n );\n const entry: IntakeSectionDef = {\n key: keyFromLabel(trimmedLabel, taken),\n label: trimmedLabel,\n fields: [],\n };\n onConfigChange({\n ...config,\n intakeSections: [...config.intakeSections, entry],\n });\n } else {\n const entry: PathologyCode = {\n code: code.trim(),\n label: trimmedLabel,\n ...(parentCode ? { parentCode } : {}),\n };\n onConfigChange({\n ...config,\n pathologies: [...config.pathologies, entry],\n });\n }\n onClose();\n };\n\n const title =\n adding.kind === 'parameter'\n ? t('anamnesis.configEditor.addParameterTitle')\n : adding.kind === 'field'\n ? t('anamnesis.configEditor.addQuestionTitle', {\n section: sectionLabelForKey(config, adding.sectionKey, t),\n })\n : adding.kind === 'section'\n ? t('anamnesis.configEditor.addSectionTitle')\n : t('anamnesis.configEditor.addCodeTitle');\n\n return (\n <Dialog.Content size=\"sm\">\n <Dialog.Header>\n <Dialog.Title>{title}</Dialog.Title>\n <Dialog.Description>\n {t('anamnesis.configEditor.addNote')}\n </Dialog.Description>\n </Dialog.Header>\n <Dialog.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n {adding.kind === 'pathology' ? (\n <FormField label={t('anamnesis.configEditor.codeField')} required>\n <TextInput\n value={code}\n onChange={(event) => setCode(event.target.value)}\n />\n </FormField>\n ) : null}\n <FormField label={t('anamnesis.configEditor.labelField')} required>\n <TextInput\n value={label}\n onChange={(event) => setLabel(event.target.value)}\n />\n </FormField>\n {adding.kind === 'parameter' ? (\n <>\n <FormField label={t('anamnesis.configEditor.groupField')} required>\n <Select\n options={groupOptions}\n value={group}\n onValueChange={(value) => setGroup(value as ParameterGroup)}\n placeholder={t('anamnesis.configEditor.selectPlaceholder')}\n aria-label={t('anamnesis.configEditor.groupField')}\n />\n </FormField>\n <FormField\n label={t('anamnesis.configEditor.directionField')}\n required\n >\n <Select\n options={directionOptions}\n value={direction}\n onValueChange={(value) =>\n setDirection(value as BetterDirection)\n }\n placeholder={t('anamnesis.configEditor.selectPlaceholder')}\n aria-label={t('anamnesis.configEditor.directionField')}\n />\n </FormField>\n <div className=\"ds:grid ds:grid-cols-2 ds:gap-[var(--spacing-md)]\">\n <FormField label={t('anamnesis.configEditor.unitField')} optional>\n <TextInput\n value={unit}\n onChange={(event) => setUnit(event.target.value)}\n />\n </FormField>\n <FormField\n label={t('anamnesis.configEditor.precisionField')}\n optional\n >\n <Select\n options={[\n { value: '0', label: '0' },\n { value: '1', label: '1' },\n { value: '2', label: '2' },\n ]}\n value={precision}\n onValueChange={(value) =>\n setPrecision((value || '0') as '0' | '1' | '2')\n }\n aria-label={t('anamnesis.configEditor.precisionField')}\n />\n </FormField>\n </div>\n <div className=\"ds:grid ds:grid-cols-2 ds:gap-[var(--spacing-md)]\">\n <FormField\n label={t('anamnesis.configEditor.rangeMinField')}\n optional\n >\n <TextInput\n inputMode=\"decimal\"\n value={rangeMin}\n onChange={(event) => setRangeMin(event.target.value)}\n />\n </FormField>\n <FormField\n label={t('anamnesis.configEditor.rangeMaxField')}\n optional\n >\n <TextInput\n inputMode=\"decimal\"\n value={rangeMax}\n onChange={(event) => setRangeMax(event.target.value)}\n />\n </FormField>\n </div>\n </>\n ) : null}\n {adding.kind === 'field' ? (\n <>\n <FormField label={t('anamnesis.configEditor.typeField')} required>\n <Select\n options={typeOptions}\n value={fieldType}\n onValueChange={(value) =>\n setFieldType(value as AddFieldTypeChoice)\n }\n placeholder={t('anamnesis.configEditor.selectPlaceholder')}\n aria-label={t('anamnesis.configEditor.typeField')}\n />\n </FormField>\n {isChoiceType(fieldType) ? (\n <FormField\n label={t('anamnesis.configEditor.optionsField')}\n description={t('anamnesis.configEditor.optionsFieldHelp')}\n required\n >\n <TextInput\n value={options}\n onChange={(event) => setOptions(event.target.value)}\n />\n </FormField>\n ) : null}\n <FormField label={t('anamnesis.configEditor.helpField')} optional>\n <TextArea\n value={helpText}\n onChange={(event) => setHelpText(event.target.value)}\n minRows={2}\n />\n </FormField>\n <Switch\n label={t('anamnesis.configEditor.requiredField')}\n checked={required}\n onCheckedChange={(checked) => setRequired(checked === true)}\n />\n </>\n ) : null}\n {adding.kind === 'pathology' ? (\n <FormField\n label={t('anamnesis.configEditor.parentField')}\n description={t('anamnesis.configEditor.parentFieldHelp')}\n optional\n >\n <Select\n options={parentOptions}\n value={parentCode}\n onValueChange={(value) => setParentCode(value)}\n placeholder={t('anamnesis.configEditor.selectPlaceholder')}\n clearable\n aria-label={t('anamnesis.configEditor.parentField')}\n />\n </FormField>\n ) : null}\n {adding.kind === 'section' ? (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.configEditor.sectionNeedsQuestion')}\n </p>\n ) : null}\n </Dialog.Body>\n <Dialog.Footer>\n <Button intent=\"ghost\" onClick={onClose}>\n {t('anamnesis.configEditor.cancel')}\n </Button>\n <Button intent=\"primary\" onClick={save} disabled={!valid}>\n {t('anamnesis.configEditor.add')}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n );\n}\n\nfunction sectionLabelForKey(\n config: Required<PracticeAnamnesisConfig>,\n sectionKey: string,\n t: TFunction,\n): string {\n const section = config.intakeSections.find(\n (candidate) => candidate.key === sectionKey,\n );\n return section ? sectionLabel(section, t) : sectionKey;\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis — the record, as notes on a host's notes timeline */\n/* */\n/* A host that already has a Notes tool does not need a second one. This */\n/* maps the record's two kinds of dated writing — the notes recorded AT a */\n/* visit, and the clinical events recorded AGAINST the record — onto the */\n/* kit's `NotesPanelNote`, so both hosts feed the ONE `NotesPanel` they */\n/* already own instead of each growing a bespoke panel that can drift. */\n/* */\n/* A VISIT NOTE IS A NOTE. Someone wrote prose about a patient on a date; */\n/* it has an author (the practitioner) and it is clinician-only */\n/* (`notes.clinicalNotes` in anamnesis-disclosure.ts), so it carries */\n/* `clinical: true` and earns the card's Clinical badge. */\n/* */\n/* AN EVENT IS NOT. \"Chemotherapy started\" is a dated fact, not writing: */\n/* nobody authored it, and it is not clinician-only. It belongs on the */\n/* same timeline — the whole point is reading a note against what was */\n/* happening — but it must be TELLABLE APART, so it carries no author */\n/* (no avatar, no byline), no Clinical badge, and a one-line body naming */\n/* what kind of thing it was and, when the practice did not decide it, */\n/* who did. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport type { TFunction } from 'i18next';\nimport type { NotesPanelNote } from '../../components/notes-panel';\nimport { eventDetail } from './anamnesis-events';\nimport { visitNotes, hasVisitNotes } from './anamnesis-visit-note';\nimport type { AnamnesisNoteTarget, AnamnesisRecord } from './anamnesis-types';\n\n/**\n * The note id a target addresses. The host hands this to `NotesPanel`'s\n * `currentNoteId`; the panel marks, scrolls to and focuses that note. Namespaced\n * so anamnesis notes can share a timeline with the host's own without a\n * collision.\n */\nexport function anamnesisNoteId(target: AnamnesisNoteTarget): string {\n return target.kind === 'visit'\n ? `anamnesis-visit-${target.visitId}`\n : `anamnesis-event-${target.eventId}`;\n}\n\n/**\n * The record's notes and events as one timeline, newest first — the order\n * `NotesPanel` documents for `notes` (it re-sorts only to lead with pinned).\n *\n * A host with notes of its own concatenates and re-sorts by `dateIso`: this is\n * a contribution to the patient's timeline, not a replacement for it.\n */\nexport function anamnesisNotes(\n record: AnamnesisRecord,\n t: TFunction,\n): NotesPanelNote[] {\n const fromVisits: NotesPanelNote[] = record.visits\n .filter(hasVisitNotes)\n .map((visit) => ({\n id: anamnesisNoteId({ kind: 'visit', visitId: visit.id }),\n dateIso: visit.dateIso,\n author: visit.practitioner ? { name: visit.practitioner } : undefined,\n clinical: true,\n contentFormat: 'markdown' as const,\n // The visit type leads: in a timeline of dates, \"First visit\" is the\n // thing that tells the reader where in the story they are. Each field\n // label then LEADS its own text rather than owning a line of its own —\n // the card clamps to five lines, and a label on a line by itself spends\n // one of them saying nothing the text below it does not.\n content: [\n `**${t(`anamnesis.visitType.${visit.visitType}`)}**`,\n ...visitNotes(visit).map(\n (note) =>\n `**${t(`anamnesis.field.${note.field}.label`)}** — ${note.text}`,\n ),\n ].join('\\n\\n'),\n }));\n\n const fromEvents: NotesPanelNote[] = (record.events ?? []).map((event) => ({\n id: anamnesisNoteId({ kind: 'event', eventId: event.id }),\n dateIso: event.dateIso,\n // No author and not clinical — see the header. The card renders the date\n // itself, so the body carries the label without repeating it.\n clinical: false,\n // The three channels above are all VISUAL. Without this the card falls back\n // to its own region label, \"Clinical note\", and a screen reader introduces\n // a gym membership as one.\n 'aria-label': t('anamnesis.rail.eventLabel'),\n contentFormat: 'markdown' as const,\n content: `**${t(`anamnesis.event.label.${event.labelKey}`)}** — ${eventDetail(\n event,\n t,\n )}`,\n }));\n\n return [...fromVisits, ...fromEvents].sort((a, b) =>\n b.dateIso.localeCompare(a.dateIso),\n );\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — story-local i18n bundles */\n/* */\n/* Registered onto the kit's shared i18next singleton under the `patterns` */\n/* namespace, keyed `anamnesis.*`. English is the source/fallback; Italian */\n/* is complete (this is an Italian nutrition-clinic demo). Arabic (RTL) and */\n/* Japanese (CJK) cover the evolution slice the locale stories render; */\n/* anything else falls back to English by design. */\n/* */\n/* Registered at runtime by hosts via `registerAnamnesisBundles` (exported */\n/* from the pattern's public entry) — never copy these keys into */\n/* src/i18n/locales/*.json; the bundle rides the pattern, not the kit's */\n/* locale files. */\n/* -------------------------------------------------------------------- */\n\nimport type { i18n as I18nInstance } from 'i18next';\n\nexport const PATTERN_NS = 'patterns';\n\n/* ------------------------------- English -------------------------------- */\n\nconst EN = {\n anamnesis: {\n mainLabel: 'Anamnesis record — {{mode}}',\n mode: {\n intake: 'Intake',\n compile: 'Compile',\n questionnaire: 'Questionnaire',\n readOnly: 'Read-only',\n },\n common: {\n yes: 'Yes',\n no: 'No',\n unknown: 'Unknown',\n notSure: 'Not sure',\n choose: 'Choose…',\n details: 'Details',\n detailsPending: 'Appears when answered “Yes”',\n time: 'Time',\n whatEaten: 'What did you eat?',\n },\n header: {\n name: 'Name',\n age: 'Age',\n dob: 'Date of birth',\n visitDate: 'Visit date',\n years: '{{age}} years',\n },\n origin: { fromPatient: 'From patient' },\n delta: {\n improved: 'Improved',\n worsened: 'Worsened',\n unchanged: 'Unchanged',\n aria: '{{valence}}: {{change}}',\n },\n range: {\n aboveRange: 'Above range',\n belowRange: 'Below range',\n atMost: '≤ {{value}}',\n atLeast: '≥ {{value}}',\n },\n group: {\n anthropometric: 'Anthropometrics',\n dietary: 'Dietary intake',\n lab: 'Blood tests',\n },\n visitType: { first: 'First visit', followUp: 'Follow-up' },\n medKind: { medication: 'Medication', supplement: 'Supplement' },\n section: {\n reason: 'Reason for visit',\n pharmacological: 'Pharmacological history',\n familyHistory: 'Family history',\n symptoms: 'Symptoms',\n otherHistory: 'Other history',\n dietaryHistory: 'Dietary history',\n recall24h: '24-hour recall',\n foodFrequency: 'Weekly food frequency',\n visitMeta: 'Visit details',\n patientIntake: 'Patient intake',\n intakeGaps: 'Unanswered questions',\n anthropometrics: 'Anthropometrics',\n dietary: 'Dietary intake',\n pathologies: 'Pathologies',\n oncological: 'Oncological history',\n therapy: 'Therapy & supplements',\n labs: 'Blood tests',\n fmd: 'Fasting-mimicking programme',\n proposal: 'Nutritional proposal & notes',\n annual: 'Annual programme',\n evolution: 'Evolution',\n },\n intake: {\n title: 'Pre-visit questionnaire',\n subtitle: 'Please complete this before your first visit.',\n sectionsLabel: 'Questionnaire sections',\n answered: '{{answered}} of {{total}} questions answered',\n sectionProgress: '{{answered}} of {{total}} answered',\n submit: 'Save',\n unsentNotice:\n 'Your answers are recorded when you submit this questionnaire.',\n submittedNotice: 'Answers saved.',\n },\n compile: {\n tabSummary: 'Summary',\n tabCompile: 'Compile',\n tabEvolution: 'Evolution',\n viewsLabel: 'Record views',\n visitCount: '{{visits}} visits',\n bmiInStrip:\n 'BMI is computed from weight and height — it is read in the summary at the top of this record.',\n gapsIntro:\n 'These required questions came back unanswered. Record them with the patient.',\n noIntake: 'The patient has not submitted a questionnaire.',\n pathologiesLabel: 'Assigned pathologies',\n pathologiesHelp:\n 'Select every applicable code — a patient may hold several at once.',\n pathologiesPlaceholder: 'Search codes…',\n noTherapy: 'No therapy or supplements recorded.',\n addTherapy: 'Add medication',\n removeTherapy: 'Remove {{name}}',\n noFmd: 'No fasting-mimicking cycles recorded.',\n cycleNumber: 'Cycle {{number}}',\n cycleCompleted: 'Completed',\n cycleInProgress: 'In progress',\n blockEmpty: 'Nothing recorded',\n blockFilled_one: '{{count}} recorded',\n blockFilled_other: '{{count}} recorded',\n blockFlagged_one: '{{count}} out of range',\n blockFlagged_other: '{{count}} out of range',\n blockOutstanding_one: '{{count}} still to answer',\n blockOutstanding_other: '{{count}} still to answer',\n blockSettled: 'All answered',\n addFollowUpVisit: 'Add follow-up visit',\n },\n // Practice-configuration editor (provisional — the production editor is\n // gated on the customer's real specification; see anamnesis.mdx).\n configEditor: {\n title: 'Anamnesis configuration',\n intro:\n 'The practice’s own vocabulary: rename, reorder, archive or add. Archiving never deletes — answers already recorded stay in the history.',\n tabsLabel: 'Configuration vocabularies',\n tabQuestionnaire: 'Questionnaire',\n tabParameters: 'Parameters',\n tabPathologies: 'Pathologies',\n tabTargets: 'Targets',\n targetsIntro:\n 'Choose the parameters the practice tracks as goals. They ride the goal tiles above the record, where each patient’s target value is set and current-vs-target status is read.',\n panelTracked_one: '{{count}} tracked as a goal',\n panelTracked_other: '{{count}} tracked as goals',\n panelLive_one: '{{count}} active',\n panelLive_other: '{{count}} active',\n panelArchived_one: '{{count}} archived',\n panelArchived_other: '{{count}} archived',\n panelNotCaptured_one: '{{count}} not offered at capture',\n panelNotCaptured_other: '{{count}} not offered at capture',\n locked: 'Locked',\n lockedHint:\n 'Feeds the BMI derivation — rename or reorder it, never remove it',\n archived: 'Archived',\n rowActions: 'Actions for {{name}}',\n reorderHandle: 'Reorder {{name}}. Press Alt + Up or Alt + Down to move.',\n reorderAnnounce: '{{name}} moved to position {{to}} of {{total}}',\n edit: 'Edit {{name}}',\n archive: 'Archive {{name}}',\n restore: 'Restore {{name}}',\n addQuestion: 'Add question',\n addSection: 'Add section',\n addParameter: 'Add parameter',\n addCode: 'Add code',\n sectionEmptyCapture:\n 'No live questions — this section is not offered at capture.',\n familyHeading: 'Family with sub-codes — a heading, not assignable itself',\n subCodeOf: 'Sub-code of {{code}}',\n direction: {\n down: 'Lower is better',\n up: 'Higher is better',\n toRange: 'In range is better',\n },\n // Answer types — aligned with the platform vocabulary (boolean /\n // boolean_with_text / text / dropdown / dropdown_with_text / multiple)\n // plus the numeric types the platform does not have yet.\n type: {\n text: 'Short answer',\n textarea: 'Long answer',\n numberInteger: 'Number (integer)',\n numberDecimal: 'Number (decimal)',\n yesNoDetail: 'Yes / no',\n choice: 'Single choice',\n choiceWithText: 'Single choice with text',\n multiChoice: 'Multiple choice',\n frequency: 'Weekly frequency',\n meal: 'Meal',\n },\n typeLine: 'Answer type: {{type}}.',\n requiredBadge: 'Required',\n requiredField: 'Answer required',\n optionsCurrent: 'Choices: {{list}}.',\n editTitle: 'Edit {{name}}',\n keyLine: 'Identifier: {{key}} — set at creation, never changes.',\n codeLine: 'Code: {{code}} — set at creation, never changes.',\n labelField: 'Label',\n labelFieldHelp: 'Leave empty to use the standard wording.',\n helpField: 'Help text',\n addNote:\n 'A free-form entry is local to this practice — it joins no shared vocabulary.',\n addParameterTitle: 'Add a parameter',\n addQuestionTitle: 'Add a question to {{section}}',\n addSectionTitle: 'Add a section',\n addCodeTitle: 'Add a pathology code',\n codeField: 'Code',\n groupField: 'Group',\n directionField: 'What counts as better',\n unitField: 'Unit',\n precisionField: 'Decimals',\n rangeMinField: 'Reference minimum',\n rangeMaxField: 'Reference maximum',\n typeField: 'Answer type',\n optionsField: 'Choices',\n optionsFieldHelp: 'Comma-separated — at least one.',\n parentField: 'Parent family',\n parentFieldHelp:\n 'Adding a sub-code turns its family into a heading that can no longer be assigned itself.',\n sectionNeedsQuestion:\n 'A new section appears in the questionnaire once it holds at least one live question.',\n selectPlaceholder: 'Choose…',\n save: 'Save',\n cancel: 'Cancel',\n add: 'Add',\n },\n // The Diagnosis summary strip. Tile labels deliberately match the care\n // plan's \"Nutrition targets\" wording — the same four goals, said the same\n // way on both surfaces.\n targets: {\n title: 'Nutrition targets',\n /* One template for every tile — the seeded four and any practice-chosen\n * goal alike each read as a target. */\n tileLabel: '{{name}} target',\n now: 'Now {{value}}',\n /* BMI only: the WHO band belongs to the CURRENT figure, so it rides the\n \"Now\" line rather than adding a second chip beside the status. */\n nowBanded: 'Now {{value}} · {{band}}',\n nowUnset: 'Not measured yet',\n unset: 'No target',\n status: {\n onTarget: 'On target',\n approaching: 'Approaching',\n offTarget: 'Off target',\n },\n edit: 'Edit target — {{parameter}}',\n editTitle: 'Target — {{parameter}}',\n editField: 'New target',\n bounds: 'Between {{range}}',\n outOfBounds: 'Enter a target between {{range}}.',\n unsaved: 'Not saved yet',\n save: 'Save target',\n clear: 'Clear target',\n },\n summary: {\n fullQuestionnaire: 'The full questionnaire',\n noAnswers: 'No answers have been recorded yet.',\n jump: 'Answer {{field}} on the Compile tab',\n },\n compare: {\n visitsLabel: 'Visits compared',\n visitOption: '{{index}}. {{visitType}} · {{date}}',\n visitOptionSource: '{{label}} · {{source}}',\n // `total`, not `count` — a plural-suffixed key would need six forms in\n // Arabic to say a number the sentence already carries.\n selected: '{{total}} visits compared · {{from}} – {{to}}',\n minimum: 'At least two visits stay compared',\n stop: 'Stop comparing',\n panelTitle: 'Compare visits',\n sameVisit: 'Pick two or more different visits to see what changed.',\n summaryTitle: 'Changes from {{from}} to {{to}}',\n tableLabel: 'What changed across the compared visits',\n noChanges: 'No changes between these visits.',\n noChangesDescription:\n 'The same measurements, codes, therapy and notes were recorded at every one of them.',\n present: 'Present',\n added: 'Added',\n removed: 'Removed',\n changed: 'Changed',\n notMeasured: 'Not measured',\n category: {\n measurement: 'Measurements',\n pathology: 'Pathologies',\n therapy: 'Therapy',\n note: 'Notes',\n },\n column: {\n item: 'What',\n change: 'Change',\n },\n },\n event: {\n barLabel: 'Events',\n chip: '{{label}} · {{date}}',\n separator: ', ',\n shown: 'Event lines shown: {{list}}',\n noneShown: 'No event lines shown.',\n external: '{{category}} · recorded by {{source}}',\n // Only when a host panel is wired: showing the line also opens it.\n category: {\n therapy: 'Therapy',\n diet: 'Diet',\n fmd: 'Fasting-mimicking programme',\n surgery: 'Surgery',\n lifestyle: 'Daily life',\n },\n label: {\n dietStart: 'Mediterranean plan started',\n fmdCycle: 'Fasting-mimicking cycle',\n gymStart: 'Started the gym',\n chemoStart: 'Chemotherapy started',\n surgery: 'Gallbladder surgery',\n },\n source: {\n oncology: 'an oncologist outside this practice',\n },\n },\n grid: {\n parameter: 'Parameter',\n caption: 'Parameter values across visits, oldest first.',\n captionInModule:\n 'Parameter values across visits of {{module}}, oldest first.',\n target: 'Target {{value}} {{unit}}',\n trendLabel: '{{parameter}} trend',\n trend: 'Trend',\n editable: 'Editable',\n editCell: '{{parameter}} — latest visit',\n // `total`, not `count`: no plural suffix needed to say a number.\n baselineMerged: 'Merged from {{total}} first visits',\n // One table per anamnesis type: the module heads the table, and a\n // visit recorded under no module still needs a table to sit in.\n unlabelledSource: 'Other',\n blockVisits_one: '{{count}} visit',\n blockVisits_other: '{{count}} visits',\n },\n readOnly: {\n subtitle: 'Care plan record — read only.',\n summary: 'Patient summary',\n none: 'None recorded.',\n perWeek: '{{times}} times per week',\n },\n pathology: {\n E66: 'Obesity',\n E66_0: 'Obesity due to excess calories',\n E66_9: 'Obesity, unspecified',\n E11: 'Type 2 diabetes mellitus',\n E11_9: 'Type 2 diabetes without complications',\n E11_6: 'Type 2 diabetes with other specified complications',\n E78: 'Disorders of lipoprotein metabolism',\n I10: 'Essential hypertension',\n E03: 'Hypothyroidism',\n K58: 'Irritable bowel syndrome',\n D50: 'Iron-deficiency anaemia',\n E55: 'Vitamin D deficiency',\n groupGeneral: 'General',\n },\n param: {\n weight: 'Weight',\n height: 'Height',\n bmi: 'BMI',\n waist: 'Waist',\n hips: 'Hips',\n arm: 'Arm',\n phaseAngle: 'Phase angle',\n energy: 'Daily energy',\n protein: 'Protein',\n fastingGlucose: 'Fasting glucose',\n hba1c: 'HbA1c',\n totalCholesterol: 'Total cholesterol',\n ldl: 'LDL cholesterol',\n hdl: 'HDL cholesterol',\n triglycerides: 'Triglycerides',\n haemoglobin: 'Haemoglobin',\n vitaminD: 'Vitamin D (25-OH)',\n tsh: 'TSH',\n ferritin: 'Ferritin',\n crp: 'C-reactive protein',\n creatinine: 'Creatinine',\n },\n field: {\n highlighted: 'Highlighted',\n reasonForVisit: { label: 'Reason for visit and goals' },\n knownConditions: { label: 'Known conditions' },\n dailyMedications: { label: 'Daily medications' },\n currentSupplements: { label: 'Current supplements' },\n familyParents: { label: 'Parents' },\n familySiblings: { label: 'Siblings' },\n familyGrandparents: { label: 'Grandparents' },\n bloating: { label: 'Abdominal bloating' },\n refluxGastritis: { label: 'Reflux or gastritis' },\n tiredness: { label: 'Tiredness' },\n sleepQuality: {\n label: 'Sleep quality',\n option: { good: 'Good', fair: 'Fair', poor: 'Poor' },\n },\n sleepDifficulty: { label: 'Difficulty falling asleep or night waking' },\n bowelHabits: {\n label: 'Bowel habits',\n option: {\n regular: 'Regular',\n constipated: 'Constipated',\n diarrhoeal: 'Diarrhoeal',\n alternating: 'Alternating',\n },\n },\n stoolCharacteristics: { label: 'Stool characteristics' },\n haemorrhoids: { label: 'Haemorrhoids' },\n diverticula: { label: 'Diverticula' },\n regularUrination: { label: 'Regular urination' },\n menstrualCycle: {\n label: 'Menstrual cycle',\n option: {\n regular: 'Regular',\n irregular: 'Irregular',\n absent: 'Absent',\n },\n },\n foodAllergies: { label: 'Food allergies' },\n drugAllergies: { label: 'Drug allergies' },\n otherAllergies: { label: 'Other allergies' },\n foodIntolerances: { label: 'Food intolerances' },\n smoking: {\n label: 'Smoking',\n option: { never: 'Never', former: 'Former', current: 'Current' },\n },\n pastSurgery: { label: 'Past surgery' },\n pregnancies: { label: 'Pregnancies' },\n weightSelf: { label: 'Weight (kg)' },\n heightSelf: { label: 'Height (cm)' },\n physicalActivity: { label: 'Current physical activity' },\n lifestyle: { label: 'Current lifestyle' },\n waterPerDay: { label: 'Water (litres per day)' },\n fizzyDrinks: {\n label: 'Fizzy drinks',\n option: {\n never: 'Never',\n occasionally: 'Occasionally',\n daily: 'Daily',\n },\n },\n alcohol: {\n label: 'Alcohol',\n option: {\n never: 'Never',\n occasionally: 'Occasionally',\n daily: 'Daily',\n },\n },\n coffeePerDay: { label: 'Coffee (cups per day)' },\n coffeeSugar: {\n label: 'Coffee with sugar?',\n option: { yes: 'Yes', no: 'No' },\n },\n breakfast: { label: 'Breakfast' },\n morningSnack: { label: 'Morning snack' },\n lunch: { label: 'Lunch' },\n afternoonSnack: { label: 'Afternoon snack' },\n dinner: { label: 'Dinner' },\n afterDinner: { label: 'After dinner' },\n pulses: { label: 'Pulses (times per week)' },\n fish: {\n label: 'Fish (times per week)',\n detailLabel: 'Which fish do you prefer?',\n },\n eggs: { label: 'Eggs (times per week)' },\n meatCuredMeat: {\n label: 'Meat and cured meat (times per week)',\n detailLabel: 'Red or white?',\n },\n dairy: {\n label: 'Dairy (times per week)',\n detailLabel: 'Which dairy do you prefer?',\n },\n visitType: { label: 'Visit type' },\n practitioner: { label: 'Practitioner' },\n tumourType: { label: 'Tumour type' },\n stage: { label: 'Stage' },\n metastases: { label: 'Metastases' },\n treatmentStatus: { label: 'Treatment status' },\n medName: { label: 'Name' },\n medDose: { label: 'Dose' },\n nutritionalProposal: { label: 'Nutritional proposal' },\n clinicalNotes: { label: 'Clinical notes' },\n annualProposed: { label: 'Proposed' },\n annualAccepted: { label: 'Accepted' },\n annualDeclineReason: { label: 'Reason for declining' },\n },\n questionnaire: {\n noNumeric: {\n title: 'Nothing to compare yet',\n description:\n 'The trend compares numeric answers across questionnaires. Give a question the number type and a unit in the form settings, then compile it at least twice.',\n },\n overviewTab: 'Overview',\n },\n empty: {\n noVisits: {\n title: 'No visits yet',\n description:\n 'Once the first visit is recorded, the values and trends appear here.',\n },\n noRecord: {\n title: 'Nothing recorded yet',\n description:\n 'This record has no visits. Add the first visit to start compiling it.',\n create: 'Start the first questionnaire',\n createSigned: 'Start with signature',\n },\n noQuestions: {\n title: 'No questions to answer',\n description:\n 'This questionnaire has no active questions. Ask the practice to enable some.',\n },\n noParameters: {\n title: 'No measurements set up',\n description:\n 'This practice has no measurements configured, so there is nothing to plot yet.',\n },\n },\n visitNote: {\n title: 'Visit notes',\n trigger: 'Visit notes — {{visitType}}, {{date}}',\n // Location-NEUTRAL on purpose: the host decides where routed notes\n // arrive (a side rail, a dialog) and the focus choreography lands the\n // reader on the note either way — so the copy claims only \"the notes\n // view\", never a side.\n openInPanel:\n 'Open the visit notes — {{visitType}}, {{date}} — in the notes view',\n },\n // The host's side panel. Story-local: a real host names its own rail tool.\n rail: {\n notes: 'Notes & events',\n empty: 'This record has no notes and no events.',\n // Accessible name for an EVENT row in the notes timeline. Without it the\n // card announces itself as \"Clinical note\", which an event is not.\n eventLabel: 'Event',\n },\n window: {\n label: 'Visits shown',\n pickerTrigger: 'Visits · {{shown}} of {{total}}',\n selectAll: 'Select all',\n showing: 'Showing {{shown}} of {{total}} visits · {{from}} – {{to}}',\n showingAll: 'All {{total}} visits · {{from}} – {{to}}',\n minimum: 'At least one visit stays shown',\n // `label`, never `count`: a plural-suffixed key would need six forms in\n // Arabic to say a number the sentence already carries.\n optionHasNote: '{{label}} · note',\n },\n digest: {\n group: {\n reason: 'Why they came',\n history: 'Conditions and medication',\n flags: 'Reported symptoms',\n habits: 'Daily habits',\n },\n nothing: {\n title: 'Nothing to summarise yet',\n description:\n 'The answers recorded so far are not part of the summary. Open the full questionnaire below to read them.',\n },\n missing: {\n title_one: '{{count}} required question still unanswered',\n title_other: '{{count}} required questions still unanswered',\n list: 'Still missing: {{list}}',\n separator: ', ',\n jump: 'Go to {{field}}',\n },\n },\n // Export — the tabular serialisation of one tab, shared by every writer.\n // The tab names are stated here rather than reused from `compile.tab*` so\n // a locale that carries only the evolution slice still names the document\n // it produces.\n export: {\n tab: { summary: 'Summary', compile: 'Compile', evolution: 'Evolution' },\n // The same three views AS DOCUMENTS. \"Compile\" is a fine label on a tab\n // and a poor title for a clinical record.\n docTab: {\n summary: 'Questionnaire summary',\n compile: 'Visit record',\n evolution: 'Evolution',\n },\n docTitle: '{{tab}} — {{patient}}',\n info: 'Document details',\n generated: 'Generated',\n audienceLabel: 'Copy for',\n audience: {\n clinician: 'The practice',\n patient: 'The patient',\n external: 'An external professional',\n },\n visitsLabel: 'Visits included',\n visitsSelected: '{{shown}} of {{total}}',\n visitsAll: 'All {{total}}',\n withheld: 'Some clinical detail is not included in this copy.',\n none: 'Nothing recorded.',\n listSeparator: ', ',\n flagged: '{{date}} ({{flag}})',\n source: { patient: 'Patient', clinician: 'Clinician' },\n column: {\n question: 'Question',\n answer: 'Answer',\n source: 'Source',\n field: 'Field',\n value: 'Value',\n unit: 'Unit',\n referenceRange: 'Reference range',\n flag: 'Flag',\n target: 'Target',\n change: 'Change {{from}} → {{to}}',\n outOfRange: 'Out of range',\n code: 'Code',\n description: 'Description',\n name: 'Name',\n dose: 'Dose',\n kind: 'Type',\n cycle: 'Cycle',\n startDate: 'Start date',\n status: 'Status',\n notes: 'Notes',\n note: 'Note',\n text: 'Text',\n },\n // The one control on the Diagnosis surface. Order is deliberate:\n // Share → PDF → Print → Excel → CSV.\n control: {\n trigger: 'Export & share',\n // WCAG 2.5.3: both names OPEN with the visible label above.\n triggerLabel: 'Export & share the {{tab}} view',\n triggerLabelAudience: 'Export & share the {{tab}} view, {{audience}}',\n audienceBadge: 'Patient copy',\n menuLabel: '{{tab}} view',\n everyVisit: 'Include every visit, not only the columns shown',\n excludes: 'A patient copy leaves out: {{list}}',\n excludesNone: 'A patient copy of this view leaves nothing out.',\n holds: 'The practice copy holds the full record, including {{list}}.',\n holdsNone: 'This view holds nothing a patient copy would leave out.',\n share: 'Share…',\n pdf: 'Download PDF',\n print: 'Print',\n xlsx: 'Download Excel (.xlsx)',\n csv: 'Download CSV (.csv)',\n printFrame: 'Print document (no visible content)',\n printing: 'The print dialog is opening for the document.',\n ready: '{{file}} is ready.',\n failed: 'This browser could not prepare the file.',\n },\n // A MOCK. Nothing here transmits, and no string may say it did.\n share: {\n title: 'Share the {{tab}} view',\n mockBadge: 'Preview only',\n subtitle: 'Choose who a copy would be for, and see what it would hold.',\n noticeTitle: 'Nothing is sent from this screen',\n notice:\n 'This preview shows the shape of a share, not a share. A real one needs a signed expiring link, the patient’s consent, and a record of who received what over which channel — all of which live outside this record.',\n audienceLabel: 'Who would this copy be for?',\n includes: 'This copy would hold',\n includesNone: 'This view produces no document for this recipient.',\n excludes: 'This copy would leave out',\n excludesNone: 'Nothing is left out of this copy.',\n cancel: 'Cancel',\n confirm: 'Confirm recipient',\n confirmed: 'Recipient set to {{audience}}. Nothing has been sent.',\n },\n // Withheld concepts, named for a human. Ids carry dots; i18next reads a\n // dot as a level, so the keys flatten them.\n concept: {\n patient_identity: 'Patient identity',\n intake_answers: 'Questionnaire answers',\n visit_date: 'Visit dates',\n visit_type: 'Visit type',\n visit_practitioner: 'Practitioner',\n visit_reasonCode: 'Coded reason for the visit',\n anthropometrics_values: 'Anthropometric measurements',\n dietary_intake: 'Dietary intake',\n derived_bmi: 'BMI',\n lab_values: 'Blood-test values',\n pathology_codes: 'Diagnostic codes',\n oncological_history: 'Oncological history',\n therapy_entries: 'Therapy and supplements',\n fmd_cycles: 'Fasting-mimicking cycles',\n annual_programme: 'Annual programme',\n notes_clinicalNotes: 'Clinical notes',\n notes_nutritionalProposal: 'Nutritional proposal',\n symptom_observations: 'Clinician observations',\n compare_diff: 'Visit comparison',\n visit_note: 'Visit notes',\n event_timeline: 'Clinical event timeline',\n export_tabDocument: 'The document itself',\n export_workbook: 'The whole-record workbook',\n },\n },\n },\n};\n\n/* ------------------------------- Italian -------------------------------- */\n\n/* THE WHOLE BUNDLE needs native review before the demo — the per-block markers\n * below are older and cover only what follows them. */\nconst IT = {\n anamnesis: {\n mainLabel: 'Cartella anamnestica — {{mode}}',\n mode: {\n intake: 'Anamnesi',\n compile: 'Diagnostica',\n questionnaire: 'Questionario',\n readOnly: 'Sola lettura',\n },\n common: {\n yes: 'Sì',\n no: 'No',\n unknown: 'Non noto',\n notSure: 'Non so',\n choose: 'Seleziona…',\n details: 'Dettagli',\n detailsPending: 'Appare rispondendo “Sì”',\n time: 'Ora',\n whatEaten: 'Cosa hai mangiato?',\n },\n header: {\n name: 'Nome',\n age: 'Età',\n dob: 'Data di nascita',\n visitDate: 'Data della visita',\n years: '{{age}} anni',\n },\n origin: { fromPatient: 'Dal paziente' },\n delta: {\n improved: 'Migliorato',\n worsened: 'Peggiorato',\n unchanged: 'Invariato',\n aria: '{{valence}}: {{change}}',\n },\n range: {\n aboveRange: 'Sopra il range',\n belowRange: 'Sotto il range',\n atMost: '≤ {{value}}',\n atLeast: '≥ {{value}}',\n },\n group: {\n anthropometric: 'Antropometria',\n dietary: 'Apporto alimentare',\n lab: 'Esami del sangue',\n },\n visitType: { first: 'Prima visita', followUp: 'Controllo' },\n medKind: { medication: 'Farmaco', supplement: 'Integratore' },\n section: {\n reason: 'Motivo della visita',\n pharmacological: 'Anamnesi farmacologica',\n familyHistory: 'Anamnesi familiare',\n symptoms: 'Sintomi',\n otherHistory: 'Altra anamnesi',\n dietaryHistory: 'Anamnesi alimentare',\n recall24h: 'Recall delle 24 ore',\n foodFrequency: 'Frequenza alimentare settimanale',\n visitMeta: 'Dettagli della visita',\n patientIntake: 'Questionario del paziente',\n intakeGaps: 'Domande senza risposta',\n anthropometrics: 'Antropometria',\n dietary: 'Apporto alimentare',\n pathologies: 'Patologie',\n oncological: 'Anamnesi oncologica',\n therapy: 'Terapia e integratori',\n labs: 'Esami del sangue',\n fmd: 'Programma di digiuno mima-digiuno',\n proposal: 'Proposta nutrizionale e note',\n annual: 'Programma annuale',\n evolution: 'Andamento',\n },\n intake: {\n title: 'Questionario pre-visita',\n subtitle: 'Compila questo questionario prima della prima visita.',\n sectionsLabel: 'Sezioni del questionario',\n answered: '{{answered}} di {{total}} domande completate',\n sectionProgress: '{{answered}} di {{total}} completate',\n submit: 'Salva',\n unsentNotice:\n 'Le tue risposte vengono registrate quando invii il questionario.',\n submittedNotice: 'Risposte salvate.',\n },\n // Italian below needs native review before the demo.\n compile: {\n tabSummary: 'Riepilogo',\n tabCompile: 'Compila',\n tabEvolution: 'Andamento',\n viewsLabel: 'Viste della cartella',\n visitCount: '{{visits}} visite',\n bmiInStrip:\n 'Il BMI è calcolato da peso e altezza — si legge nel riepilogo in cima alla cartella.',\n gapsIntro:\n 'Queste domande obbligatorie sono tornate senza risposta. Registrale insieme al paziente.',\n noIntake: 'Il paziente non ha inviato alcun questionario.',\n pathologiesLabel: 'Patologie assegnate',\n pathologiesHelp:\n 'Seleziona ogni codice pertinente — un paziente può averne più di uno.',\n pathologiesPlaceholder: 'Cerca codici…',\n noTherapy: 'Nessuna terapia o integratore registrato.',\n addTherapy: 'Aggiungi farmaco',\n removeTherapy: 'Rimuovi {{name}}',\n noFmd: 'Nessun ciclo di mima-digiuno registrato.',\n cycleNumber: 'Ciclo {{number}}',\n cycleCompleted: 'Completato',\n cycleInProgress: 'In corso',\n // \"voci\" carries the noun, so the badge agrees under a feminine block\n // title too — \"{{count}} registrati\" only agreed by luck.\n blockEmpty: 'Nulla registrato',\n blockFilled_one: '{{count}} voce',\n blockFilled_other: '{{count}} voci',\n blockFlagged_one: '{{count}} fuori range',\n blockFlagged_other: '{{count}} fuori range',\n blockOutstanding_one: '{{count}} da completare',\n blockOutstanding_other: '{{count}} da completare',\n blockSettled: 'Tutte completate',\n addFollowUpVisit: 'Aggiungi controllo',\n },\n // Editor di configurazione (provvisorio — l’editor di produzione attende\n // la specifica reale del cliente; vedi anamnesis.mdx).\n configEditor: {\n title: 'Configurazione dell’anamnesi',\n intro:\n 'Il vocabolario dello studio: rinomina, riordina, archivia o aggiungi. Archiviare non cancella — le risposte già registrate restano nello storico.',\n tabsLabel: 'Vocabolari configurabili',\n tabQuestionnaire: 'Questionario',\n tabParameters: 'Parametri',\n tabPathologies: 'Patologie',\n tabTargets: 'Obiettivi',\n targetsIntro:\n 'Scegli i parametri che lo studio traccia come obiettivi. Compaiono nei riquadri sopra la cartella, dove si imposta il valore obiettivo di ogni paziente e si legge l’andamento rispetto all’obiettivo.',\n panelTracked_one: '{{count}} tracciato come obiettivo',\n panelTracked_other: '{{count}} tracciati come obiettivi',\n panelLive_one: '{{count}} attivo',\n panelLive_other: '{{count}} attivi',\n panelArchived_one: '{{count}} archiviato',\n panelArchived_other: '{{count}} archiviati',\n panelNotCaptured_one: '{{count}} non proposta in compilazione',\n panelNotCaptured_other: '{{count}} non proposte in compilazione',\n locked: 'Bloccato',\n lockedHint:\n 'Alimenta il calcolo del BMI — rinominalo o riordinalo, mai rimuoverlo',\n archived: 'Archiviato',\n rowActions: 'Azioni per {{name}}',\n reorderHandle:\n 'Riordina {{name}}. Premi Alt + Freccia su o Alt + Freccia giù per spostare.',\n reorderAnnounce: '{{name}} spostato in posizione {{to}} di {{total}}',\n edit: 'Modifica {{name}}',\n archive: 'Archivia {{name}}',\n restore: 'Ripristina {{name}}',\n addQuestion: 'Aggiungi domanda',\n addSection: 'Aggiungi sezione',\n addParameter: 'Aggiungi parametro',\n addCode: 'Aggiungi codice',\n sectionEmptyCapture:\n 'Nessuna domanda attiva — questa sezione non è proposta in compilazione.',\n familyHeading:\n 'Famiglia con sotto-codici — è un’intestazione, non assegnabile',\n subCodeOf: 'Sotto-codice di {{code}}',\n direction: {\n down: 'Meglio più basso',\n up: 'Meglio più alto',\n toRange: 'Meglio nel range',\n },\n type: {\n text: 'Risposta breve',\n textarea: 'Risposta lunga',\n numberInteger: 'Numero (intero)',\n numberDecimal: 'Numero (decimale)',\n yesNoDetail: 'Sì / No',\n choice: 'Scelta singola',\n choiceWithText: 'Scelta singola con testo',\n multiChoice: 'Scelta multipla (più risposte)',\n frequency: 'Frequenza settimanale',\n meal: 'Pasto',\n },\n typeLine: 'Tipo di risposta: {{type}}.',\n requiredBadge: 'Obbligatoria',\n requiredField: 'Risposta obbligatoria',\n optionsCurrent: 'Opzioni: {{list}}.',\n editTitle: 'Modifica {{name}}',\n keyLine:\n 'Identificatore: {{key}} — assegnato alla creazione, non cambia mai.',\n codeLine: 'Codice: {{code}} — assegnato alla creazione, non cambia mai.',\n labelField: 'Etichetta',\n labelFieldHelp: 'Lascia vuoto per usare la dicitura standard.',\n helpField: 'Testo di aiuto',\n addNote:\n 'Una voce libera resta locale a questo studio — non entra in alcun vocabolario condiviso.',\n addParameterTitle: 'Aggiungi un parametro',\n addQuestionTitle: 'Aggiungi una domanda a {{section}}',\n addSectionTitle: 'Aggiungi una sezione',\n addCodeTitle: 'Aggiungi un codice patologia',\n codeField: 'Codice',\n groupField: 'Gruppo',\n directionField: 'Cosa conta come miglioramento',\n unitField: 'Unità',\n precisionField: 'Decimali',\n rangeMinField: 'Minimo di riferimento',\n rangeMaxField: 'Massimo di riferimento',\n typeField: 'Tipo di risposta',\n optionsField: 'Opzioni',\n optionsFieldHelp: 'Separate da virgola — almeno una.',\n parentField: 'Famiglia di appartenenza',\n parentFieldHelp:\n 'Aggiungendo un sotto-codice, la famiglia diventa un’intestazione non più assegnabile direttamente.',\n sectionNeedsQuestion:\n 'Una nuova sezione compare nel questionario quando contiene almeno una domanda attiva.',\n selectPlaceholder: 'Scegli…',\n save: 'Salva',\n cancel: 'Annulla',\n add: 'Aggiungi',\n },\n targets: {\n title: 'Obiettivi nutrizionali',\n tileLabel: 'Obiettivo {{name}}',\n now: 'Ora {{value}}',\n nowBanded: 'Ora {{value}} · {{band}}',\n nowUnset: 'Non ancora misurato',\n unset: 'Nessun obiettivo',\n status: {\n onTarget: 'In linea',\n approaching: 'In avvicinamento',\n offTarget: 'Fuori obiettivo',\n },\n edit: 'Modifica obiettivo — {{parameter}}',\n editTitle: 'Obiettivo — {{parameter}}',\n editField: 'Nuovo obiettivo',\n bounds: 'Tra {{range}}',\n outOfBounds: 'Inserisci un obiettivo tra {{range}}.',\n unsaved: 'Non ancora salvato',\n save: 'Salva obiettivo',\n clear: 'Rimuovi obiettivo',\n },\n // Italian below needs native review before the demo.\n summary: {\n fullQuestionnaire: 'Il questionario completo',\n noAnswers: 'Nessuna risposta registrata finora.',\n jump: 'Rispondi a {{field}} nella scheda Compila',\n },\n // Italian below needs native review before the demo.\n compare: {\n visitsLabel: 'Visite confrontate',\n visitOption: '{{index}}. {{visitType}} · {{date}}',\n visitOptionSource: '{{label}} · {{source}}',\n selected: '{{total}} visite confrontate · {{from}} – {{to}}',\n minimum: 'Restano confrontate almeno due visite',\n stop: 'Interrompi confronto',\n panelTitle: 'Confronta le visite',\n sameVisit: 'Seleziona due o più visite diverse per vedere le differenze.',\n summaryTitle: 'Modifiche dal {{from}} al {{to}}',\n tableLabel: 'Che cosa è cambiato tra le visite confrontate',\n noChanges: 'Nessuna modifica tra queste visite.',\n noChangesDescription:\n 'In tutte sono stati registrati gli stessi valori, codici, terapie e note.',\n present: 'Presente',\n added: 'Aggiunto',\n removed: 'Rimosso',\n changed: 'Modificato',\n notMeasured: 'Non misurato',\n category: {\n measurement: 'Misurazioni',\n pathology: 'Patologie',\n therapy: 'Terapia',\n note: 'Note',\n },\n column: {\n item: 'Voce',\n change: 'Variazione',\n },\n },\n event: {\n barLabel: 'Eventi',\n chip: '{{label}} · {{date}}',\n separator: ', ',\n shown: 'Linee evento mostrate: {{list}}',\n noneShown: 'Nessuna linea evento mostrata.',\n // Gender-free frame: the interpolated category is feminine in four of\n // five cases, so an invariant participle mis-agrees.\n external: '{{category}} · fonte: {{source}}',\n category: {\n therapy: 'Terapia',\n diet: 'Dieta',\n fmd: 'Programma mima-digiuno',\n surgery: 'Intervento',\n lifestyle: 'Vita quotidiana',\n },\n label: {\n dietStart: 'Avvio del piano mediterraneo',\n fmdCycle: 'Ciclo mima-digiuno',\n gymStart: 'Inizio dell’attività in palestra',\n chemoStart: 'Avvio della chemioterapia',\n surgery: 'Intervento alla colecisti',\n },\n source: {\n oncology: 'un oncologo esterno allo studio',\n },\n },\n grid: {\n parameter: 'Parametro',\n caption: 'Valori dei parametri nelle visite, dalla più vecchia.',\n captionInModule:\n 'Valori dei parametri nelle visite di {{module}}, dalla più vecchia.',\n target: 'Obiettivo {{value}} {{unit}}',\n trendLabel: 'Andamento {{parameter}}',\n trend: 'Andamento',\n editable: 'Modificabile',\n editCell: '{{parameter}} — ultima visita',\n baselineMerged: 'Unione di {{total}} prime visite',\n unlabelledSource: 'Altro',\n blockVisits_one: '{{count}} visita',\n blockVisits_other: '{{count}} visite',\n },\n readOnly: {\n subtitle: 'Cartella del piano di cura — sola lettura.',\n summary: 'Riepilogo paziente',\n none: 'Nessuno registrato.',\n perWeek: '{{times}} volte a settimana',\n },\n pathology: {\n E66: 'Obesità',\n E66_0: 'Obesità da eccesso calorico',\n E66_9: 'Obesità non specificata',\n E11: 'Diabete mellito di tipo 2',\n E11_9: 'Diabete di tipo 2 senza complicanze',\n E11_6: 'Diabete di tipo 2 con altre complicanze specificate',\n E78: 'Disturbi del metabolismo delle lipoproteine',\n I10: 'Ipertensione essenziale',\n E03: 'Ipotiroidismo',\n K58: 'Sindrome dell’intestino irritabile',\n D50: 'Anemia sideropenica',\n E55: 'Carenza di vitamina D',\n groupGeneral: 'Generale',\n },\n param: {\n weight: 'Peso',\n height: 'Altezza',\n // Italian clinicians read and say \"BMI\" as often as \"IMC\", so the\n // acronym is kept alongside the translated form.\n bmi: 'IMC (BMI)',\n waist: 'Girovita',\n hips: 'Fianchi',\n arm: 'Braccio',\n phaseAngle: 'Angolo di fase',\n energy: 'Energia giornaliera',\n protein: 'Proteine',\n fastingGlucose: 'Glicemia a digiuno',\n hba1c: 'Emoglobina glicata',\n totalCholesterol: 'Colesterolo totale',\n ldl: 'Colesterolo LDL',\n hdl: 'Colesterolo HDL',\n triglycerides: 'Trigliceridi',\n haemoglobin: 'Emoglobina',\n vitaminD: 'Vitamina D (25-OH)',\n tsh: 'TSH',\n ferritin: 'Ferritina',\n crp: 'Proteina C reattiva',\n creatinine: 'Creatinina',\n },\n field: {\n highlighted: 'In risalto',\n reasonForVisit: { label: 'Motivo della visita e obiettivi' },\n knownConditions: { label: 'Patologie note' },\n dailyMedications: { label: 'Farmaci quotidiani' },\n currentSupplements: { label: 'Integratori attuali' },\n familyParents: { label: 'Genitori' },\n familySiblings: { label: 'Fratelli e sorelle' },\n familyGrandparents: { label: 'Nonni' },\n bloating: { label: 'Gonfiore addominale' },\n refluxGastritis: { label: 'Reflusso o gastrite' },\n tiredness: { label: 'Stanchezza' },\n sleepQuality: {\n label: 'Qualità del sonno',\n option: { good: 'Buona', fair: 'Discreta', poor: 'Scarsa' },\n },\n sleepDifficulty: {\n label: 'Difficoltà ad addormentarsi o risvegli notturni',\n },\n bowelHabits: {\n label: 'Abitudini intestinali',\n option: {\n regular: 'Regolari',\n constipated: 'Stitichezza',\n diarrhoeal: 'Diarroiche',\n alternating: 'Alternanti',\n },\n },\n stoolCharacteristics: { label: 'Caratteristiche delle feci' },\n haemorrhoids: { label: 'Emorroidi' },\n diverticula: { label: 'Diverticoli' },\n regularUrination: { label: 'Minzione regolare' },\n menstrualCycle: {\n label: 'Ciclo mestruale',\n option: {\n regular: 'Regolare',\n irregular: 'Irregolare',\n absent: 'Assente',\n },\n },\n foodAllergies: { label: 'Allergie alimentari' },\n drugAllergies: { label: 'Allergie ai farmaci' },\n otherAllergies: { label: 'Altre allergie' },\n foodIntolerances: { label: 'Intolleranze alimentari' },\n smoking: {\n label: 'Fumo',\n option: { never: 'Mai', former: 'Ex fumatore', current: 'Attuale' },\n },\n pastSurgery: { label: 'Interventi chirurgici pregressi' },\n pregnancies: { label: 'Gravidanze' },\n weightSelf: { label: 'Peso (kg)' },\n heightSelf: { label: 'Altezza (cm)' },\n physicalActivity: { label: 'Attività fisica attuale' },\n lifestyle: { label: 'Stile di vita attuale' },\n waterPerDay: { label: 'Acqua (litri al giorno)' },\n fizzyDrinks: {\n label: 'Bevande gassate',\n option: {\n never: 'Mai',\n occasionally: 'Occasionalmente',\n daily: 'Ogni giorno',\n },\n },\n alcohol: {\n label: 'Alcol',\n option: {\n never: 'Mai',\n occasionally: 'Occasionalmente',\n daily: 'Ogni giorno',\n },\n },\n coffeePerDay: { label: 'Caffè (tazzine al giorno)' },\n coffeeSugar: {\n label: 'Caffè con zucchero?',\n option: { yes: 'Sì', no: 'No' },\n },\n breakfast: { label: 'Colazione' },\n morningSnack: { label: 'Spuntino del mattino' },\n lunch: { label: 'Pranzo' },\n afternoonSnack: { label: 'Spuntino del pomeriggio' },\n dinner: { label: 'Cena' },\n afterDinner: { label: 'Dopo cena' },\n pulses: { label: 'Legumi (volte a settimana)' },\n fish: {\n label: 'Pesce (volte a settimana)',\n detailLabel: 'Quale pesce preferisci?',\n },\n eggs: { label: 'Uova (volte a settimana)' },\n meatCuredMeat: {\n label: 'Carne e salumi (volte a settimana)',\n detailLabel: 'Rossa o bianca?',\n },\n dairy: {\n label: 'Latticini (volte a settimana)',\n detailLabel: 'Quali latticini preferisci?',\n },\n visitType: { label: 'Tipo di visita' },\n practitioner: { label: 'Professionista' },\n tumourType: { label: 'Tipo di tumore' },\n stage: { label: 'Stadio' },\n metastases: { label: 'Metastasi' },\n treatmentStatus: { label: 'Stato del trattamento' },\n medName: { label: 'Nome' },\n medDose: { label: 'Dose' },\n nutritionalProposal: { label: 'Proposta nutrizionale' },\n clinicalNotes: { label: 'Note cliniche' },\n annualProposed: { label: 'Proposto' },\n annualAccepted: { label: 'Accettato' },\n annualDeclineReason: { label: 'Motivo del rifiuto' },\n },\n // Italian below needs native review before the demo.\n questionnaire: {\n noNumeric: {\n title: 'Ancora nulla da confrontare',\n description:\n 'L’andamento confronta le risposte numeriche fra i questionari. Imposta una domanda come numerica con un’unità di misura nelle impostazioni del modulo, poi compilala almeno due volte.',\n },\n overviewTab: 'Panoramica',\n },\n empty: {\n noVisits: {\n title: 'Nessuna visita',\n description:\n 'Dopo la prima visita registrata, qui compaiono i valori e l’andamento.',\n },\n noRecord: {\n title: 'Nessun dato registrato',\n description:\n 'Questa cartella non ha visite. Aggiungi la prima visita per iniziare a compilarla.',\n create: 'Compila il primo questionario',\n createSigned: 'Compila con firma',\n },\n noQuestions: {\n title: 'Nessuna domanda da compilare',\n description:\n 'Questo questionario non ha domande attive. Chiedi allo studio di attivarne.',\n },\n // Italian below needs native review before the demo.\n noParameters: {\n title: 'Nessun parametro configurato',\n description:\n 'Questo studio non ha parametri configurati, quindi non c’è ancora nulla da mostrare.',\n },\n },\n // Italian below needs native review before the demo.\n visitNote: {\n title: 'Note della visita',\n trigger: 'Note della visita — {{visitType}}, {{date}}',\n openInPanel:\n 'Apri le note della visita — {{visitType}}, {{date}} — nella vista note',\n },\n rail: {\n notes: 'Note ed eventi',\n empty: 'Questa cartella non ha né note né eventi.',\n eventLabel: 'Evento',\n },\n // Italian below needs native review before the demo.\n window: {\n label: 'Visite mostrate',\n pickerTrigger: 'Visite · {{shown}} di {{total}}',\n selectAll: 'Seleziona tutto',\n // Count-free frame: \"Mostrate 1 visite su 13\" is ungrammatical, and the\n // one-visit state is reachable (it is the state that appends `minimum`).\n showing: 'Visite mostrate: {{shown}} su {{total}} · {{from}} – {{to}}',\n showingAll: 'Tutte le {{total}} visite · {{from}} – {{to}}',\n minimum: 'Resta mostrata almeno una visita',\n optionHasNote: '{{label}} · nota',\n },\n digest: {\n group: {\n reason: 'Motivo della visita',\n history: 'Patologie e farmaci',\n flags: 'Sintomi riferiti',\n habits: 'Abitudini quotidiane',\n },\n nothing: {\n title: 'Non c’è ancora nulla da riassumere',\n description:\n 'Le risposte registrate finora non rientrano nella sintesi. Apri il questionario completo qui sotto per leggerle.',\n },\n missing: {\n title_one: '{{count}} domanda obbligatoria senza risposta',\n title_other: '{{count}} domande obbligatorie senza risposta',\n list: 'Mancano ancora: {{list}}',\n separator: ', ',\n jump: 'Vai a {{field}}',\n },\n },\n export: {\n tab: {\n summary: 'Riepilogo',\n compile: 'Compila',\n evolution: 'Andamento',\n },\n docTab: {\n summary: 'Riepilogo del questionario',\n compile: 'Scheda visita',\n evolution: 'Andamento',\n },\n docTitle: '{{tab}} — {{patient}}',\n info: 'Dettagli del documento',\n generated: 'Generato',\n audienceLabel: 'Copia per',\n audience: {\n clinician: 'Lo studio',\n patient: 'Il paziente',\n external: 'Un professionista esterno',\n },\n visitsLabel: 'Visite incluse',\n visitsSelected: '{{shown}} su {{total}}',\n visitsAll: 'Tutte le {{total}}',\n withheld: 'Alcuni dettagli clinici non sono inclusi in questa copia.',\n none: 'Nulla di registrato.',\n listSeparator: ', ',\n flagged: '{{date}} ({{flag}})',\n source: { patient: 'Paziente', clinician: 'Clinico' },\n column: {\n question: 'Domanda',\n answer: 'Risposta',\n source: 'Origine',\n field: 'Campo',\n value: 'Valore',\n unit: 'Unità',\n referenceRange: 'Range di riferimento',\n flag: 'Segnalazione',\n target: 'Obiettivo',\n change: 'Variazione {{from}} → {{to}}',\n outOfRange: 'Fuori range',\n code: 'Codice',\n description: 'Descrizione',\n name: 'Nome',\n dose: 'Dose',\n kind: 'Tipo',\n cycle: 'Ciclo',\n startDate: 'Data di inizio',\n status: 'Stato',\n notes: 'Note',\n note: 'Nota',\n text: 'Testo',\n },\n control: {\n trigger: 'Esporta e condividi',\n triggerLabel: 'Esporta e condividi la vista {{tab}}',\n triggerLabelAudience:\n 'Esporta e condividi la vista {{tab}}, {{audience}}',\n audienceBadge: 'Copia per il paziente',\n menuLabel: 'Vista {{tab}}',\n everyVisit: 'Includi tutte le visite, non solo le colonne mostrate',\n excludes: 'Una copia per il paziente esclude: {{list}}',\n excludesNone:\n 'Una copia per il paziente non esclude nulla di questa vista.',\n holds:\n 'La copia per lo studio contiene la cartella completa, inclusi: {{list}}.',\n holdsNone:\n 'In questa vista non c’\\u00e8 nulla che una copia per il paziente escluderebbe.',\n share: 'Condividi…',\n pdf: 'Scarica PDF',\n print: 'Stampa',\n xlsx: 'Scarica Excel (.xlsx)',\n csv: 'Scarica CSV (.csv)',\n printFrame: 'Documento di stampa (nessun contenuto visibile)',\n printing: 'Si sta aprendo la finestra di stampa del documento.',\n ready: '{{file}} è pronto.',\n failed: 'Questo browser non è riuscito a preparare il file.',\n },\n share: {\n title: 'Condividi la vista {{tab}}',\n mockBadge: 'Solo anteprima',\n subtitle:\n 'Scegli a chi sarebbe destinata una copia e guarda che cosa conterrebbe.',\n noticeTitle: 'Da questa schermata non viene inviato nulla',\n notice:\n 'Questa anteprima mostra la forma di una condivisione, non una condivisione. Quella vera richiede un link firmato con scadenza, il consenso del paziente e la registrazione di chi ha ricevuto che cosa e su quale canale: tutto al di fuori di questa cartella.',\n audienceLabel: 'A chi sarebbe destinata questa copia?',\n includes: 'Questa copia conterrebbe',\n includesNone:\n 'Per questo destinatario questa vista non produce alcun documento.',\n excludes: 'Questa copia escluderebbe',\n excludesNone: 'Questa copia non esclude nulla.',\n cancel: 'Annulla',\n confirm: 'Conferma destinatario',\n confirmed:\n 'Destinatario impostato su {{audience}}. Non è stato inviato nulla.',\n },\n concept: {\n patient_identity: 'Dati anagrafici del paziente',\n intake_answers: 'Risposte al questionario',\n visit_date: 'Date delle visite',\n visit_type: 'Tipo di visita',\n visit_practitioner: 'Professionista',\n visit_reasonCode: 'Motivo della visita codificato',\n anthropometrics_values: 'Misure antropometriche',\n dietary_intake: 'Apporto alimentare',\n derived_bmi: 'BMI',\n lab_values: 'Valori degli esami del sangue',\n pathology_codes: 'Codici diagnostici',\n oncological_history: 'Anamnesi oncologica',\n therapy_entries: 'Terapia e integratori',\n fmd_cycles: 'Cicli di digiuno simulato',\n annual_programme: 'Programma annuale',\n notes_clinicalNotes: 'Note cliniche',\n notes_nutritionalProposal: 'Proposta nutrizionale',\n symptom_observations: 'Osservazioni del clinico',\n compare_diff: 'Confronto tra visite',\n visit_note: 'Note della visita',\n event_timeline: 'Cronologia degli eventi clinici',\n export_tabDocument: 'Il documento stesso',\n export_workbook: 'La cartella di lavoro completa',\n },\n },\n },\n};\n\n/* ---------------- Arabic (RTL) — evolution slice only ------------------- */\n\nconst AR = {\n anamnesis: {\n mainLabel: 'السجل الطبي — {{mode}}',\n mode: {\n intake: 'الاستجواب',\n compile: 'التجميع',\n questionnaire: 'الاستبيان',\n readOnly: 'للقراءة فقط',\n },\n common: { yes: 'نعم', no: 'لا' },\n header: {\n name: 'الاسم',\n age: 'العمر',\n dob: 'تاريخ الميلاد',\n visitDate: 'تاريخ الزيارة',\n years: '{{age}} سنة',\n },\n origin: { fromPatient: 'من المريض' },\n delta: {\n improved: 'تحسّن',\n worsened: 'تدهور',\n unchanged: 'دون تغيير',\n aria: '{{valence}}: {{change}}',\n },\n range: {\n aboveRange: 'أعلى من النطاق',\n belowRange: 'أدنى من النطاق',\n atMost: '≤ {{value}}',\n atLeast: '≥ {{value}}',\n },\n group: {\n anthropometric: 'القياسات الجسمية',\n dietary: 'المدخول الغذائي',\n lab: 'تحاليل الدم',\n },\n visitType: { first: 'الزيارة الأولى', followUp: 'متابعة' },\n section: { evolution: 'التطوّر' },\n compare: {\n visitsLabel: 'الزيارات المقارَنة',\n visitOption: '{{index}}. {{visitType}} · {{date}}',\n visitOptionSource: '{{label}} · {{source}}',\n selected: 'مقارنة {{total}} زيارة · {{from}} – {{to}}',\n minimum: 'تبقى زيارتان على الأقل قيد المقارنة',\n stop: 'إيقاف المقارنة',\n panelTitle: 'مقارنة الزيارات',\n sameVisit: 'اختر زيارتين مختلفتين أو أكثر لعرض التغيّرات.',\n summaryTitle: 'التغيّرات من {{from}} إلى {{to}}',\n tableLabel: 'ما الذي تغيّر بين الزيارات المقارَنة',\n noChanges: 'لا توجد تغيّرات بين هذه الزيارات.',\n noChangesDescription:\n 'سُجِّلت في كل الزيارات القيم والرموز والعلاجات والملاحظات نفسها.',\n present: 'موجود',\n added: 'أُضيف',\n removed: 'أُزيل',\n changed: 'تغيّر',\n notMeasured: 'لم يُقَس',\n category: {\n measurement: 'القياسات',\n pathology: 'الأمراض',\n therapy: 'العلاج',\n note: 'الملاحظات',\n },\n column: {\n item: 'البند',\n change: 'التغيير',\n },\n },\n event: {\n barLabel: 'الأحداث',\n chip: '{{label}} · {{date}}',\n separator: '، ',\n shown: 'خطوط الأحداث المعروضة: {{list}}',\n noneShown: 'لا توجد خطوط أحداث معروضة.',\n external: '{{category}} · سجّله {{source}}',\n category: {\n therapy: 'العلاج',\n diet: 'الحمية',\n fmd: 'برنامج محاكاة الصيام',\n surgery: 'جراحة',\n lifestyle: 'الحياة اليومية',\n },\n label: {\n dietStart: 'بدء خطة البحر المتوسط',\n fmdCycle: 'دورة محاكاة الصيام',\n gymStart: 'بدء التمارين الرياضية',\n chemoStart: 'بدء العلاج الكيميائي',\n surgery: 'جراحة المرارة',\n },\n source: {\n oncology: 'طبيب أورام من خارج العيادة',\n },\n },\n grid: {\n parameter: 'المؤشر',\n caption: 'قيم المؤشرات عبر الزيارات، من الأقدم.',\n captionInModule: 'قيم المؤشرات عبر زيارات {{module}}، من الأقدم.',\n target: 'الهدف {{value}} {{unit}}',\n trendLabel: 'اتجاه {{parameter}}',\n trend: 'الاتجاه',\n editable: 'قابل للتعديل',\n editCell: '{{parameter}} — آخر زيارة',\n baselineMerged: 'مدمجة من {{total}} زيارات أولى',\n unlabelledSource: 'أخرى',\n blockVisits_zero: 'لا زيارات',\n blockVisits_one: 'زيارة واحدة',\n blockVisits_two: 'زيارتان',\n blockVisits_few: '{{count}} زيارات',\n blockVisits_many: '{{count}} زيارة',\n blockVisits_other: '{{count}} زيارة',\n },\n param: {\n weight: 'الوزن',\n height: 'الطول',\n bmi: 'مؤشر كتلة الجسم',\n waist: 'محيط الخصر',\n hips: 'محيط الورك',\n arm: 'الذراع',\n phaseAngle: 'زاوية الطور',\n energy: 'الطاقة اليومية',\n protein: 'البروتين',\n fastingGlucose: 'سكر الدم الصائم',\n hba1c: 'الهيموغلوبين السكري',\n totalCholesterol: 'الكوليسترول الكلي',\n ldl: 'الكوليسترول الضار',\n hdl: 'الكوليسترول النافع',\n triglycerides: 'الدهون الثلاثية',\n haemoglobin: 'الهيموغلوبين',\n vitaminD: 'فيتامين د',\n tsh: 'الهرمون المنبّه للغدة الدرقية',\n ferritin: 'الفيريتين',\n crp: 'البروتين التفاعلي',\n creatinine: 'الكرياتينين',\n },\n questionnaire: {\n overviewTab: 'نظرة عامة',\n },\n empty: {\n noVisits: {\n title: 'لا توجد زيارات بعد',\n description: 'بعد تسجيل الزيارة الأولى تظهر القيم والاتجاهات هنا.',\n },\n noRecord: {\n title: 'لا يوجد شيء مسجّل بعد',\n description:\n 'هذا السجل لا يحتوي على زيارات. أضف الزيارة الأولى لبدء تجميعه.',\n create: 'ابدأ الاستبيان الأول',\n createSigned: 'ابدأ مع التوقيع',\n },\n noParameters: {\n title: 'لا توجد قياسات مُعدّة',\n description:\n 'لم تُعدّ هذه العيادة أي قياسات، لذا لا يوجد ما يُعرض بعد.',\n },\n },\n // The two note labels are read by the evolution slice's note popover, so\n // they need ar/ja cover even though the rest of `field.*` does not.\n field: {\n highlighted: 'إجابة مميّزة',\n clinicalNotes: { label: 'ملاحظات سريرية' },\n nutritionalProposal: { label: 'الخطة الغذائية المقترحة' },\n },\n visitNote: {\n title: 'ملاحظات الزيارة',\n trigger: 'ملاحظات الزيارة — {{visitType}}، {{date}}',\n openInPanel:\n 'افتح ملاحظات الزيارة — {{visitType}}، {{date}} — في عرض الملاحظات',\n },\n rail: {\n notes: 'الملاحظات والأحداث',\n empty: 'لا توجد ملاحظات ولا أحداث في هذا السجل.',\n eventLabel: 'حدث',\n },\n window: {\n label: 'الزيارات المعروضة',\n pickerTrigger: 'الزيارات · {{shown}} من {{total}}',\n selectAll: 'تحديد الكل',\n showing: 'عرض {{shown}} من {{total}} زيارة · {{from}} – {{to}}',\n showingAll: 'كل الزيارات {{total}} · {{from}} – {{to}}',\n minimum: 'تبقى زيارة واحدة معروضة على الأقل',\n optionHasNote: '{{label}} · ملاحظة',\n },\n // The digest + missing-answer alert render on intake/compile, which the\n // folder's Arabic story mounts — so the chrome is covered here too.\n digest: {\n group: {\n reason: 'سبب الزيارة',\n history: 'الأمراض والأدوية',\n flags: 'الأعراض المذكورة',\n habits: 'العادات اليومية',\n },\n nothing: {\n title: 'لا يوجد ما يُلخَّص بعد',\n description:\n 'الإجابات المسجَّلة حتى الآن ليست جزءاً من الملخّص. افتح الاستبيان الكامل أدناه لقراءتها.',\n },\n missing: {\n title_zero: 'لا توجد أسئلة إلزامية بلا إجابة',\n title_one: 'سؤال إلزامي واحد بلا إجابة',\n title_two: 'سؤالان إلزاميان بلا إجابة',\n title_few: '{{count}} أسئلة إلزامية بلا إجابة',\n title_many: '{{count}} سؤالاً إلزامياً بلا إجابة',\n title_other: '{{count}} سؤال إلزامي بلا إجابة',\n list: 'ما زال ناقصاً: {{list}}',\n separator: '، ',\n jump: 'انتقل إلى {{field}}',\n },\n },\n // The Diagnosis view switch — on screen beside the export control, and\n // named by the menu's own header, so it cannot stay English there.\n compile: {\n tabSummary: 'الملخّص',\n tabCompile: 'التسجيل',\n tabEvolution: 'التطوّر',\n viewsLabel: 'عروض السجلّ',\n },\n // Evolution slice: the keys the evolution export document reads. The\n // summary/compile columns stay English by design, as everywhere else here.\n export: {\n tab: { evolution: 'التطوّر' },\n docTab: { evolution: 'التطوّر' },\n docTitle: '{{tab}} — {{patient}}',\n info: 'تفاصيل المستند',\n generated: 'تاريخ الإنشاء',\n audienceLabel: 'نسخة لـ',\n audience: {\n clinician: 'العيادة',\n patient: 'المريض',\n external: 'مختص خارجي',\n },\n visitsLabel: 'الزيارات المدرجة',\n visitsSelected: '{{shown}} من {{total}}',\n visitsAll: 'كل الـ {{total}}',\n withheld: 'بعض التفاصيل السريرية غير مدرجة في هذه النسخة.',\n none: 'لا يوجد شيء مسجَّل.',\n listSeparator: '، ',\n flagged: '{{date}} ({{flag}})',\n column: {\n unit: 'الوحدة',\n referenceRange: 'النطاق المرجعي',\n target: 'الهدف',\n change: 'التغيّر {{from}} → {{to}}',\n outOfRange: 'خارج النطاق',\n },\n control: {\n trigger: 'تصدير ومشاركة',\n triggerLabel: 'تصدير ومشاركة عرض {{tab}}',\n triggerLabelAudience: 'تصدير ومشاركة عرض {{tab}}، {{audience}}',\n audienceBadge: 'نسخة المريض',\n menuLabel: 'عرض {{tab}}',\n everyVisit: 'تضمين كل الزيارات، وليس الأعمدة المعروضة فقط',\n excludes: 'نسخة المريض تستبعد: {{list}}',\n excludesNone: 'نسخة المريض من هذا العرض لا تستبعد شيئاً.',\n holds: 'نسخة العيادة تحتوي على السجلّ الكامل، بما في ذلك: {{list}}.',\n holdsNone: 'لا شيء في هذا العرض تستبعده نسخة المريض.',\n share: 'مشاركة…',\n pdf: 'تنزيل PDF',\n print: 'طباعة',\n xlsx: 'تنزيل Excel (.xlsx)',\n csv: 'تنزيل CSV (.csv)',\n printFrame: 'مستند الطباعة (بلا محتوى مرئي)',\n printing: 'يجري فتح نافذة طباعة المستند.',\n ready: '{{file}} جاهز.',\n failed: 'تعذّر على هذا المتصفح تجهيز الملف.',\n },\n share: {\n title: 'مشاركة عرض {{tab}}',\n mockBadge: 'معاينة فقط',\n subtitle: 'اختر لمن ستكون النسخة، وشاهد ما الذي ستحتويه.',\n noticeTitle: 'لا يُرسَل أي شيء من هذه الشاشة',\n notice:\n 'هذه المعاينة تُظهر شكل المشاركة، لا مشاركةً فعلية. المشاركة الحقيقية تتطلّب رابطاً موقّعاً ينتهي صلاحيته، وموافقة المريض، وسجلاً لمن استلم ماذا وعبر أي قناة — وكلها خارج هذه السجلّة.',\n audienceLabel: 'لمن ستكون هذه النسخة؟',\n includes: 'ستحتوي هذه النسخة على',\n includesNone: 'هذا العرض لا يُنتج أي مستند لهذا المستلم.',\n excludes: 'ستستبعد هذه النسخة',\n excludesNone: 'هذه النسخة لا تستبعد شيئاً.',\n cancel: 'إلغاء',\n confirm: 'تأكيد المستلم',\n confirmed: 'تم ضبط المستلم على {{audience}}. لم يُرسَل أي شيء.',\n },\n concept: {\n lab_values: 'قيم تحاليل الدم',\n pathology_codes: 'الرموز التشخيصية',\n oncological_history: 'التاريخ الأورامي',\n notes_clinicalNotes: 'الملاحظات السريرية',\n export_tabDocument: 'المستند نفسه',\n },\n },\n // Rendered by the compare panel, inside AnamnesisEvolution.\n pathology: {\n E66: 'السمنة',\n E66_0: 'سمنة ناتجة عن فرط السعرات الحرارية',\n E66_9: 'سمنة غير محددة',\n E11: 'داء السكري من النوع الثاني',\n E11_9: 'داء السكري من النوع الثاني دون مضاعفات',\n E11_6: 'داء السكري من النوع الثاني مع مضاعفات أخرى محددة',\n E78: 'اضطرابات استقلاب البروتين الدهني',\n I10: 'ارتفاع ضغط الدم الأساسي',\n E03: 'قصور الغدة الدرقية',\n K58: 'متلازمة القولون العصبي',\n D50: 'فقر الدم بعوز الحديد',\n E55: 'نقص فيتامين د',\n groupGeneral: 'عام',\n },\n },\n};\n\n/* ---------------- Japanese (CJK) — evolution slice only ----------------- */\n\nconst JA = {\n anamnesis: {\n mainLabel: '問診記録 — {{mode}}',\n mode: {\n intake: '問診',\n compile: '記入',\n questionnaire: '問診票',\n readOnly: '閲覧のみ',\n },\n common: { yes: 'はい', no: 'いいえ' },\n header: {\n name: '氏名',\n age: '年齢',\n dob: '生年月日',\n visitDate: '受診日',\n years: '{{age}}歳',\n },\n origin: { fromPatient: '患者から' },\n delta: {\n improved: '改善',\n worsened: '悪化',\n unchanged: '変化なし',\n aria: '{{valence}}: {{change}}',\n },\n range: {\n aboveRange: '基準値超',\n belowRange: '基準値未満',\n atMost: '≤ {{value}}',\n atLeast: '≥ {{value}}',\n },\n group: {\n anthropometric: '身体計測',\n dietary: '食事摂取',\n lab: '血液検査',\n },\n visitType: { first: '初診', followUp: '再診' },\n section: { evolution: '推移' },\n compare: {\n visitsLabel: '比較する受診',\n visitOption: '{{index}}. {{visitType}} · {{date}}',\n visitOptionSource: '{{label}} · {{source}}',\n selected: '{{total}}回の受診を比較 · {{from}} – {{to}}',\n minimum: '受診は2件以上比較されます',\n stop: '比較を終了',\n panelTitle: '受診を比較',\n sameVisit: '異なる2回以上の受診を選択してください。',\n summaryTitle: '{{from}}から{{to}}への変化',\n tableLabel: '比較した受診の間に変わったこと',\n noChanges: 'これらの受診の間に変化はありません。',\n noChangesDescription:\n 'いずれの受診でも同じ測定値・コード・処方・メモが記録されています。',\n present: 'あり',\n added: '追加',\n removed: '削除',\n changed: '変更',\n notMeasured: '未測定',\n category: {\n measurement: '測定値',\n pathology: '疾患',\n therapy: '処方',\n note: 'メモ',\n },\n column: {\n item: '項目',\n change: '変化',\n },\n },\n event: {\n barLabel: 'イベント',\n chip: '{{label}} · {{date}}',\n separator: '、',\n shown: '表示中のイベント線: {{list}}',\n noneShown: '表示中のイベント線はありません。',\n external: '{{category}} · 記録者: {{source}}',\n category: {\n therapy: '治療',\n diet: '食事',\n fmd: '疑似断食プログラム',\n surgery: '手術',\n lifestyle: '日常生活',\n },\n label: {\n dietStart: '地中海食プランの開始',\n fmdCycle: '疑似断食サイクル',\n gymStart: 'ジム通いの開始',\n chemoStart: '化学療法の開始',\n surgery: '胆のう手術',\n },\n source: {\n oncology: '院外の腫瘍内科医',\n },\n },\n grid: {\n parameter: '項目',\n caption: '受診ごとの項目値(古い順)。',\n captionInModule: '{{module}} の受診ごとの項目値(古い順)。',\n target: '目標 {{value}} {{unit}}',\n trendLabel: '{{parameter}}の推移',\n trend: '推移',\n editable: '編集可能',\n editCell: '{{parameter}} — 最新の受診',\n baselineMerged: '{{total}}件の初診を統合',\n unlabelledSource: 'その他',\n blockVisits_other: '{{count}}回の受診',\n },\n param: {\n weight: '体重',\n height: '身長',\n bmi: 'BMI',\n waist: 'ウエスト',\n hips: 'ヒップ',\n arm: '上腕',\n phaseAngle: '位相角',\n energy: '1日のエネルギー',\n protein: 'タンパク質',\n fastingGlucose: '空腹時血糖',\n hba1c: 'ヘモグロビンA1c',\n totalCholesterol: '総コレステロール',\n ldl: 'LDLコレステロール',\n hdl: 'HDLコレステロール',\n triglycerides: '中性脂肪',\n haemoglobin: 'ヘモグロビン',\n vitaminD: 'ビタミンD',\n tsh: '甲状腺刺激ホルモン',\n ferritin: 'フェリチン',\n crp: 'C反応性タンパク',\n creatinine: 'クレアチニン',\n },\n questionnaire: {\n overviewTab: '概要',\n },\n empty: {\n noVisits: {\n title: '受診記録がありません',\n description: '初回の受診を記録すると、値と推移がここに表示されます。',\n },\n noRecord: {\n title: 'まだ記録がありません',\n description:\n 'この記録には受診がありません。最初の受診を追加して記入を始めてください。',\n create: '最初の問診票を始める',\n createSigned: '署名付きで始める',\n },\n noParameters: {\n title: '測定項目が未設定です',\n description:\n 'この診療所には測定項目が設定されていないため、表示できる内容がありません。',\n },\n },\n // The two note labels are read by the evolution slice's note popover, so\n // they need ar/ja cover even though the rest of `field.*` does not.\n field: {\n highlighted: '注目すべき回答',\n clinicalNotes: { label: '臨床メモ' },\n nutritionalProposal: { label: '栄養指導の提案' },\n },\n visitNote: {\n title: '受診時のメモ',\n trigger: '受診時のメモ — {{visitType}}、{{date}}',\n openInPanel:\n '受診時のメモ — {{visitType}}、{{date}} — をメモビューで開く',\n },\n rail: {\n notes: 'メモとイベント',\n empty: 'この記録にはメモもイベントもありません。',\n eventLabel: 'イベント',\n },\n window: {\n label: '表示する受診',\n pickerTrigger: '受診 · {{total}}回中{{shown}}回',\n selectAll: 'すべて選択',\n showing: '{{total}}回中{{shown}}回を表示 · {{from}} – {{to}}',\n showingAll: 'すべての受診{{total}}回 · {{from}} – {{to}}',\n minimum: '受診は1件以上表示されます',\n optionHasNote: '{{label}} · メモ',\n },\n // The digest + missing-answer alert render on intake/compile, which the\n // folder's Japanese story mounts — so the chrome is covered here too.\n digest: {\n group: {\n reason: '受診の理由',\n history: '既往症と服薬',\n flags: '訴えのある症状',\n habits: '日常の習慣',\n },\n nothing: {\n title: 'まだ要約するものがありません',\n description:\n 'これまでに記録された回答は要約の対象外です。下の質問票全体を開いて確認してください。',\n },\n missing: {\n title_other: '未回答の必須項目が{{count}}件あります',\n list: '未回答: {{list}}',\n separator: '、',\n jump: '{{field}} へ移動',\n },\n },\n // The Diagnosis view switch — on screen beside the export control, and\n // named by the menu's own header, so it cannot stay English there.\n compile: {\n tabSummary: '要約',\n tabCompile: '記録',\n tabEvolution: '推移',\n viewsLabel: 'カルテの表示',\n },\n // Evolution slice: the keys the evolution export document reads. The\n // summary/compile columns stay English by design, as everywhere else here.\n export: {\n tab: { evolution: '推移' },\n docTab: { evolution: '推移' },\n docTitle: '{{tab}} — {{patient}}',\n info: '文書の詳細',\n generated: '作成日時',\n audienceLabel: '交付先',\n audience: {\n clinician: '診療所',\n patient: '患者',\n external: '院外の専門職',\n },\n visitsLabel: '対象の受診',\n visitsSelected: '{{total}}回中{{shown}}回',\n visitsAll: 'すべての受診{{total}}回',\n withheld: '一部の臨床情報はこの控えには含まれていません。',\n none: '記録はありません。',\n listSeparator: '、',\n flagged: '{{date}}({{flag}})',\n column: {\n unit: '単位',\n referenceRange: '基準範囲',\n target: '目標',\n change: '変化 {{from}} → {{to}}',\n outOfRange: '基準範囲外',\n },\n control: {\n trigger: '書き出し・共有',\n triggerLabel: '書き出し・共有 — {{tab}}ビュー',\n triggerLabelAudience: '書き出し・共有 — {{tab}}ビュー、{{audience}}',\n audienceBadge: '患者向けの控え',\n menuLabel: '{{tab}}ビュー',\n everyVisit: '表示中の列だけでなく、すべての受診を含める',\n excludes: '患者向けの控えでは次を除きます: {{list}}',\n excludesNone: 'このビューの患者向けの控えで除かれるものはありません。',\n holds: '診療所向けの控えには次を含む記録全体が入ります: {{list}}。',\n holdsNone: 'このビューには、患者向けの控えで除かれるものはありません。',\n share: '共有…',\n pdf: 'PDFをダウンロード',\n print: '印刷',\n xlsx: 'Excel (.xlsx) をダウンロード',\n csv: 'CSV (.csv) をダウンロード',\n printFrame: '印刷用文書(表示内容なし)',\n printing: '文書の印刷ダイアログを開いています。',\n ready: '{{file}} の準備ができました。',\n failed: 'このブラウザーではファイルを準備できませんでした。',\n },\n share: {\n title: '{{tab}}ビューを共有',\n mockBadge: 'プレビューのみ',\n subtitle: '控えの交付先を選び、その控えに何が入るかを確認します。',\n noticeTitle: 'この画面からは何も送信されません',\n notice:\n 'これは共有の「かたち」を示すプレビューであり、共有そのものではありません。実際の共有には、期限付きの署名付きリンク、患者の同意、そして誰が何をどの経路で受け取ったかの記録が必要で、いずれもこの記録の外にあります。',\n audienceLabel: 'この控えの交付先は?',\n includes: 'この控えに入るもの',\n includesNone: 'この交付先に対して、このビューは文書を生成しません。',\n excludes: 'この控えから除かれるもの',\n excludesNone: 'この控えから除かれるものはありません。',\n cancel: 'キャンセル',\n confirm: '交付先を確定',\n confirmed:\n '交付先を{{audience}}に設定しました。何も送信されていません。',\n },\n concept: {\n lab_values: '血液検査の数値',\n pathology_codes: '診断コード',\n oncological_history: '腫瘍の既往',\n notes_clinicalNotes: '臨床メモ',\n export_tabDocument: '文書そのもの',\n },\n },\n // Rendered by the compare panel, inside AnamnesisEvolution.\n pathology: {\n E66: '肥満',\n E66_0: '過剰カロリーによる肥満',\n E66_9: '肥満、詳細不明',\n E11: '2型糖尿病',\n E11_9: '合併症のない2型糖尿病',\n E11_6: 'その他の明示された合併症を伴う2型糖尿病',\n E78: 'リポタンパク代謝障害',\n I10: '本態性高血圧',\n E03: '甲状腺機能低下症',\n K58: '過敏性腸症候群',\n D50: '鉄欠乏性貧血',\n E55: 'ビタミンD欠乏症',\n groupGeneral: '一般',\n },\n },\n};\n\n/* ----------------------------- Registration ----------------------------- */\n\nconst BUNDLES: Record<string, Record<string, unknown>> = {\n en: EN,\n it: IT,\n ar: AR,\n ja: JA,\n};\n\n/** Register the story-local bundles onto the shared singleton (deep-merge,\n * never overwrite; never init). Idempotent across HMR reloads. */\nexport function registerAnamnesisBundles(i18n: I18nInstance): void {\n for (const [locale, bundle] of Object.entries(BUNDLES)) {\n if (!i18n.hasResourceBundle(locale, PATTERN_NS)) {\n i18n.addResourceBundle(locale, PATTERN_NS, bundle);\n } else {\n i18n.addResourceBundle(locale, PATTERN_NS, bundle, true, false);\n }\n }\n}\n","/* -------------------------------------------------------------------- */\n/* Anamnesis pattern — AnamnesisSummaryCard rows */\n/* */\n/* Maps intake definitions + one or more responses to the label/value */\n/* rows `AnamnesisSummaryCard` renders. The card is data-agnostic (it */\n/* owns layout, icons, i18n, a11y); this is where the pattern's vocabu- */\n/* lary — highlight rules, sex relevance, answer formatting — becomes */\n/* rows. Two callers: the Overview tab (one card combining each module's */\n/* latest interview, so `sources` has one entry per module) and the */\n/* archive table (one card for a single interview, one source). */\n/* */\n/* Sits beside `anamnesis-summary.tsx` (the Summary TAB) under its own */\n/* name because a `.ts` twin of that file would shadow it on import. */\n/* -------------------------------------------------------------------- */\n\nimport type { TFunction } from 'i18next';\nimport type {\n AnamnesisSummaryAnswer,\n AnamnesisSummarySection,\n} from '../../components/anamnesis-summary-card';\nimport { hasClockTime } from './anamnesis-derive';\nimport {\n formatIntakeAnswer,\n intakeFieldLabel,\n isIntakeAnswered,\n parseCalendarDate,\n sectionLabel,\n} from './anamnesis-format';\nimport { isHighlightedAnswer } from './anamnesis-highlight';\nimport type {\n IntakeAnswer,\n IntakeFieldDef,\n IntakeResponse,\n IntakeSectionDef,\n PatientSex,\n} from './anamnesis-types';\n\nexport interface SummarySource {\n response: IntakeResponse;\n /** Module name shown as the answer's source (combined view). */\n sourceLabel?: string;\n /** Overrides `response.submittedAtIso` as the \"recorded\" stamp. */\n reportedAtIso?: string;\n}\n\nexport interface SummarySectionsResult {\n sections: AnamnesisSummarySection[];\n /** Fields nobody answered (after the relevance skip). */\n unansweredCount: number;\n}\n\n/** The instant a source's stamp denotes, for latest-wins ordering. A bare\n * `YYYY-MM-DD` is a LOCAL calendar day — `new Date(iso)` would read it as\n * UTC midnight and lose a day west of Greenwich; a `YYYY-MM-DDTHH:mm` string\n * is a local instant and a zoned ISO string carries its own offset, so both\n * go through `Date`. An unreadable stamp is no stamp. */\nfunction stampInstant(iso: string | undefined): number | undefined {\n if (!iso) return undefined;\n const time = hasClockTime(iso)\n ? new Date(iso).getTime()\n : parseCalendarDate(iso)?.getTime();\n return time == null || Number.isNaN(time) ? undefined : time;\n}\n\nfunction stampOf(source: SummarySource): string | undefined {\n return source.reportedAtIso ?? source.response.submittedAtIso;\n}\n\ninterface Chosen {\n answer: IntakeAnswer;\n source: SummarySource;\n}\n\n/** The source whose answer to `key` is the freshest: only answered sources\n * count; a stamped source beats an unstamped one; among stamped sources the\n * latest stamp wins; ties (and unstamped vs unstamped) go to the later entry\n * in `sources`. */\nfunction latestAnswered(\n key: string,\n sources: readonly SummarySource[],\n): Chosen | undefined {\n let best: Chosen | undefined;\n let bestInstant = Number.NEGATIVE_INFINITY;\n for (const source of sources) {\n const answer = source.response.answers[key]?.value;\n if (!answer || !isIntakeAnswered(answer)) continue;\n const instant = stampInstant(stampOf(source)) ?? Number.NEGATIVE_INFINITY;\n if (instant >= bestInstant) {\n best = { answer, source };\n bestInstant = instant;\n }\n }\n return best;\n}\n\nfunction relevantTo(def: IntakeFieldDef, sex: PatientSex | undefined): boolean {\n const relevance = def.relevance ?? 'any';\n return sex === undefined || relevance === 'any' || relevance === sex;\n}\n\nfunction rowFor(\n def: IntakeFieldDef,\n chosen: Chosen,\n t: TFunction,\n): AnamnesisSummaryAnswer {\n const row: AnamnesisSummaryAnswer = {\n id: def.key,\n label: intakeFieldLabel(def, t),\n value: formatIntakeAnswer(chosen.answer, def, t),\n highlighted: isHighlightedAnswer(def, chosen.answer),\n };\n if (def.unit) row.unit = def.unit;\n const stamp = stampOf(chosen.source);\n if (stamp) row.reportedAtIso = stamp;\n if (chosen.source.sourceLabel) row.sourceLabel = chosen.source.sourceLabel;\n return row;\n}\n\n/** Maps intake definitions + one or more responses to summary rows.\n *\n * For every field the answered sources compete and the one with the LATEST\n * stamp (`reportedAtIso ?? response.submittedAtIso`) supplies the row —\n * `latestAnswered` spells out the ordering. The row carries the chosen\n * source's stamp and label so the card's HeartPulse tooltip can say when,\n * and from which module, a highlighted answer was recorded.\n *\n * Fields irrelevant to `opts.sex` (a `relevance` that is set, not `any`, and\n * differs) are skipped entirely and not counted; with no sex given nothing\n * is skipped, so an answered question is never silently dropped. Fields\n * nobody answered increment `unansweredCount`. Sections with no rows are\n * dropped. */\nexport function summarySectionsFromRecord(\n sections: readonly IntakeSectionDef[],\n sources: readonly SummarySource[],\n t: TFunction,\n opts?: { sex?: PatientSex },\n): SummarySectionsResult {\n const out: AnamnesisSummarySection[] = [];\n let unansweredCount = 0;\n for (const section of sections) {\n const answers: AnamnesisSummaryAnswer[] = [];\n for (const def of section.fields) {\n if (!relevantTo(def, opts?.sex)) continue;\n const chosen = latestAnswered(def.key, sources);\n if (!chosen) {\n unansweredCount += 1;\n continue;\n }\n answers.push(rowFor(def, chosen, t));\n }\n if (answers.length === 0) continue;\n out.push({\n id: section.key,\n heading: sectionLabel(section, t),\n answers,\n });\n }\n return { sections: out, unansweredCount };\n}\n"],"names":["__iconNode","ArchiveRestore","createLucideIcon","Archive","SendHorizontal","ANTHRO_PARAMETERS","LAB_PARAMETERS","DIETARY_PARAMETERS","ALL_NUMERIC_PARAMETERS","p","PATHOLOGY_TAXONOMY","pathologyLabelKey","code","c","INTAKE_SECTIONS","s","f","LOCKED_PARAMETER_KEYS","isParameterLocked","key","TARGETABLE_PARAMETER_KEYS","isParameterTargetable","SEEDED_ANAMNESIS_CONFIG","resolveConfig","config","ordered","list","item","index","a","b","entry","isLive","descriptor","stampLock","def","locked","orderedParameters","groups","group","configuredParameters","live","scoped","allParametersIncludingArchived","all","orderedSection","section","configuredSections","allSectionsIncludingArchived","configuredPathologies","allPathologiesIncludingArchived","pathologyLookup","assignablePathologyCodes","child","ANTHRO_FIELD_BY_KEY","CALENDAR_DATE_FORMAT","CALENDAR_DATETIME_FORMAT","CLOCK_TIME_RE","CALENDAR_DAY_RE","hasClockTime","iso","calendarDayOf","calendarFormatFor","computeBmi","weightKg","heightCm","kitComputeBmi","isReadableDate","ageAt","dobIso","referenceIso","dob","ref","age","monthDiff","DIETARY_STORAGE_KEYS","parameterStorage","readNumber","value","parameterValueAt","visit","hit","_a","d","l","latestParameterValue","visits","upsertMeasurement","parameterKey","setNumericOnVisit","storage","setTargetOnRecord","record","target","usable","targets","outOfRange","range","rangeDistance","deltaInfo","current","previous","abs","direction","valence","before","after","buildParameterRows","defs","targetByKey","t","cells","series","roundTo","precision","factor","latestVisit","ABSENT_VALUE","numberFormatters","numberFormatter","locale","formatter","formatValue","formatCalendarDate","formatCalendarDateTime","formatDelta","rounded","fieldVisible","sex","relevance","localeOf","lng","visitDateLabel","parseCalendarDate","y","m","clockSuffix","toCalendarIso","date","pad","n","visitOptionLabel","hasNote","base","label","ageLabel","dateOfBirthIso","patientAgeLabel","reference","practiceLabel","trimmed","parameterLabel","parameterLabelWithUnit","intakeFieldLabel","intakeFieldLabelWithUnit","intakeFieldHelp","practice","sectionLabel","pathologyLabel","pathologyCodeWithLabel","isIntakeAnswered","answer","formatIntakeAnswer","yn","selectedLabel","opt","DIGEST_GROUPS","visibleFields","sections","field","itemFor","read","flagItems","fields","out","buildIntakeDigest","byKey","items","answered","missingMandatoryAnswers","FOCUSABLE_CONTROL","focusIntakeField","root","host","control","MAX_JUMP_FRAMES","useFieldJump","containerRef","useRef","pending","setPending","useState","useEffect","frames","raf","attempt","requestJump","useCallback","AnamnesisMissingAnswers","missing","onJump","announce","jumpKey","first","separator","jsxs","Alert","jsx","Button","DigestGroupBlock","DescriptionList","AnamnesisDigest","digest","EmptyState","deltaVariants","cva","DeltaIndicator","delta","Icon","ArrowUp","ArrowDown","Minus","changeText","valenceLabel","OriginMarker","Badge","User","OutOfRangeBadge","flag","compact","TREND_COLOUR","TrendSparkline","annotations","onSelectAnnotation","measured","overall","Sparkline","TRIGGER_FOCUS_RING","AnamnesisAnswerList","intake","blocks","sourced","AnamnesisSummary","Fragment","Collapsible","CollapsibleTrigger","ChevronDown","CollapsibleContent","EVERY_VISIT_BLOCKS","OCCASIONAL_BLOCKS","filledText","oncologicalFill","onc","filled","labValues","labDefs","lab","hits","annualFill","annual","compileBlockDensity","labs","firstVisit","fills","flags","density","id","BASELINE_VISIT_ID","visitSortKey","byDay","finite","ANTHRO_KEYS","mergeMeasurements","lists","merged","at","mergeText","texts","kept","text","firstDefined","values","isBaselineVisit","resolveBaseline","keepId","folds","firsts","same","sources","anthropometrics","source","intakeLists","pathologyCodes","therapy","baseline","rest","EVENT_SHAPE","EVENT_TONE","eventPosition","event","spans","instant","times","i","from","to","within","eventMarks","events","position","eventLabel","eventDetail","category","eventAnnotations","marks","activeIds","mark","AnamnesisEventBar","onToggle","labelId","useId","detailId","active","pressed","AnnotationMarker","NOTE_FIELDS","visitNotes","hasVisitNotes","AnamnesisVisitNoteList","note","NOTE_SCROLL_CLASS","AnamnesisVisitNote","defaultOpen","onOpenNote","visitTypeLabel","dateLabel","triggerLabel","IconButton","NotebookPen","Popover","Timestamp","MATRIX_IDENTITY_CLASS","MATRIX_VISIT_COLUMN_CLASS","MATRIX_TREND_COLUMN_CLASS","IDENTITY_HEADER_CLASS","COLUMN_HEADER_CLASS","TRAILING_HEADER_CLASS","MATRIX_CELL_CLASS","MatrixVisitHeader","column","emphasised","editable","defaultOpenNoteVisitId","withNote","mergedFrom","headerClass","AnamnesisMatrix","captionId","caption","identityLabel","trendLabel","trendTestId","visitHeaders","trailingLabel","trailingTestId","rows","framed","testId","columnCount","row","_b","defaultSelectedVisitIds","v","windowVisits","selectedIds","options","pinned","shown","columns","pinnedShown","pinnedTotal","shownCount","totalCount","allVisitColumns","visitPickerIsUseful","UNMEASURED_CELL","deltaIsLegible","formatBound","bound","decimals","formatRange","AnamnesisEvolutionGrid","editableVisitId","onCellChange","visitColumns","capturableKeys","baselineSources","groupBanners","editableId","renderedRows","lastGroup","rangeText","valueCells","columnIndex","cell","isEditableVisit","capturable","editableCell","deltaHidden","NumberInput","next","UNLABELLED_BLOCK_KEY","WHOLE_RECORD_BLOCK_KEY","wholeRecordBlock","partitionVisitsBySource","unlabelledLabel","block","sortKey","oldest","measuredParameters","keep","unionShownVisitIds","reports","seen","union","report","AnamnesisEvolution","partitionBySource","cardBlocks","onVisitSelectionChange","exportSlot","blockProps","allDefs","useMemo","unlabelled","views","compiling","shownByBlock","reportBlock","ids","reporters","blockRecord","EvolutionBlock","useShownVisitIds","setIds","track","prev","heading","carded","defaultVisitIds","defaultEventIds","toolbarEnd","merge","pickable","view","pinnedIds","headingId","readoutId","refusalNote","setRefusalNote","pickedVisitIds","setPickedVisitIds","pickerUseful","selectedVisitIds","visitWindow","shownVisitIds","visitItems","offset","allShown","triggerText","refuseFloor","setVisitShown","visitId","selectAllVisits","windowReadout","parts","pickedEventIds","setPickedEventIds","activeEventIds","drawable","toggleEvent","eventId","selectAnnotation","DropdownMenu","checked","Card","CLINICIAN_ONLY","CLINICIAN_AND_PATIENT","DISCLOSURE_RULES","RULE_BY_ID","rule","disclosedTo","audience","DOCUMENT_CONCEPT","allow","gate","conceptId","parameterConcept","sectionRow","textCell","referenceRangeText","flagText","slugify","calendarPart","day","buildFileStem","tab","namesDisclosed","name","audienceLabel","tabLabel","docTabLabel","baseMeta","generatedAtIso","meta","patientName","documentTitle","tabText","refusedDocument","finish","document","extraFootnotes","withheld","footnotes","buildSummaryExport","tables","measurementTable","title","withRange","anyAllowed","fieldValueTable","buildCompileExport","visitRows","anthro","dietary","lookup","present","site","cycle","yesNo","noteRows","outOfRangeText","flagged","windowChange","last","buildEvolutionExport","scope","passed","parameterRows","fromDate","toDate","tableColumns","buildAnamnesisExport","conceptLabel","documentDisclosure","table","CSV_MIME","XLSX_MIME","CSV_EOL","CSV_INJECTION","decimalSeparatorFor","part","csvDialectFor","formatCsvNumber","dialect","escapeCsvText","raw","guarded","csvCell","cellPrecision","toCsv","lines","push","toCsvBlob","body","loadExcelJs","module","interop","sheetName","used","cleaned","suffix","numberFormatFor","MIN_COLUMN_WIDTH","MAX_COLUMN_WIDTH","columnWidth","header","longest","max","toXlsxBlob","ExcelJS","workbook","info","titleRow","sheet","headerRow","banner","_","added","format","buffer","exportFileName","downloadBlob","blob","filename","url","anchor","downloadCsv","doc","downloadXlsx","PDF_FALLBACK","resolveTokenRgb","varName","fallback","probe","computed","match","pdfPalette","WINANSI_SUBSTITUTIONS","pdfSafeText","MARGIN","WIDE_TABLE_COLUMNS","TITLE_SIZE","META_SIZE","TABLE_TITLE_SIZE","BODY_SIZE","FOOTNOTE_SIZE","LINE","isWide","formatNumber","cellText","rowText","toPdfBlob","jsPDF","autoTable","palette","pageWidth","pageHeight","contentWidth","setFace","weight","size","colour","cursorY","line","sectionRows","capture","settings","data","stamp","pages","page","downloadPdf","printPdf","frame","OFFERED_AUDIENCES","AnamnesisExportMenu","defaultShareOpen","defaultAudience","setAudience","everyVisit","setEveryVisit","menuOpen","setMenuOpen","shareOpen","setShareOpen","shareAudience","setShareAudience","status","setStatus","rootRef","frameRef","printUrlRef","busyRef","describedById","build","forAudience","tabName","audienceBadge","patientExcluded","disclosureLine","sharePreview","say","run","write","ok","handlePdf","handleXlsx","handleCsv","handlePrint","openShare","confirmShare","option","Share2","FileText","Printer","FileSpreadsheet","Download","AnamnesisShareDialog","open","onOpenChange","onAudienceChange","preview","onConfirm","Dialog","RadioGroup","Radio","DisclosureList","emptyText","isHighlightedAnswer","timeToValue","time","h","valueToTime","isDetailVisible","HIGHLIGHT_WORDS_SR_ONLY","HIGHLIGHT_CHIP_COMPACT","HIGHLIGHT_CHIP_ALIGN","DECIMAL_NUMBER_FIELDS","CONTROL_MEASURE","numberInline","AnamnesisField","onChange","showOrigin","origin","readOnly","className","description","showMarker","highlighted","highlightLabel","labelStart","HeartPulse","labelEnd","FormField","TextInput","e","TextArea","perWeek","detail","selected","Select","toggle","Checkbox","desc","TimePicker","stripParameters","TARGET_BANDS","DEFAULT_TARGET_BAND","targetBandFor","tolerance","band","edge","targetStatus","now","gap","distance","TARGET_BOUNDS","targetBoundsFor","known","isTargetInBounds","draft","bounds","sameTarget","boundsLabel","TargetEditor","committed","nowLabel","onCommit","setOpen","setDraft","inBounds","dirty","parameter","handleOpenChange","commit","Pencil","TARGET_STATUS_VARIANT","TargetTile","variant","statusLabel","action","children","withUnit","StripTile","onTargetChange","tUi","useTranslation","banded","bmiCategory","gridColumnsClass","count","AnamnesisTargetStrip","NumericBlock","stripKeys","prevValue","labelWithUnit","settableTarget","Block","titleKey","fill","fillKind","AnamnesisCompile","initial","embedded","hideTargetStrip","statusSlot","onMissingAnswerJump","onRecordChange","practitioners","newVisitDateIso","defaultView","defaultExportMenuOpen","defaultExportAudience","setRecord","recordChangeSeenRef","nextId","patient","latest","x","anthroDefs","dietaryDefs","stripDefs","occasionalOpen","setOccasionalOpen","seed","state","setBlockOpen","historySections","liveSections","pathologies","setView","gapsOpen","setGapsOpen","trackShownVisits","readAnswer","missingAnswers","gapKeys","jumpToMissing","CompileShell","patchLatest","mut","r","onNumericChange","onGridCellChange","setTarget","setPathologies","codes","updateTherapy","patch","removeTherapy","addTherapy","addFollowUpVisit","updateIntakeAnswer","pathologyOptions","parent","latestOncological","latestAnnual","inner","Tabs","DatePicker","Plus","MultiSelect","Trash2","SHORT_FIELD_TYPES","isShortField","isLabGridSection","isLongFormText","spansRow","DETAILED_FIELD_TYPES","SECTION_FIELDS_GRID","SECTION_FIELDS_MIXED","FIELD_SPANS_ROW","seedAnswers","AnamnesisIntake","defaultOpenSection","onSubmit","jumpToField","referenceVisit","answers","setAnswers","submitted","setSubmitted","onFieldChange","visibleSections","sectionsToOpen","collapseIfComplete","setOpenSections","openSections","openSectionKey","seededFrom","setSeededFrom","seeded","holder","answeredCount","total","percentComplete","progressCaption","showMissing","Progress","Accordion","sectionAnswered","allShort","AccordionItem","AccordionTrigger","AccordionContent","ReadOnlyNumericList","AnamnesisReadOnly","ReadOnlyShell","oncological","NO_LEADING_TABS","AnamnesisEmptyCard","primaryAction","secondaryAction","AnamnesisQuestionnaire","leadingTabs","questionnaireSlot","questionnaireHeaderSlot","emptyState","tabProp","onTabChange","defaultTab","internalTab","setInternalTab","selectTab","working","setWorking","numericDefs","trendPanel","leading","Anamnesis","mode","dataComponent","onIntakeSubmit","intakeJumpToField","questionnaireTab","onQuestionnaireTabChange","defaultQuestionnaireTab","surface","reorderRowClasses","ReorderContext","createContext","AnamnesisReorderGroup","onReorder","dragSource","setDragSource","liveMessage","setLiveMessage","announceToggle","message","AnamnesisReorderRow","useContext","isDropTarget","setIsDropTarget","moveFromTo","clamped","onHandleKeyDown","isDragging","rowProps","handle","GripVertical","seededConfigDraft","keyFromLabel","taken","words","word","moveIndex","displayed","ADD_FIELD_TYPES","SEEDED_FIELD_KEYS","fieldTypeLabel","DIRECTIONS","GROUPS","AnamnesisConfigEditor","onConfigChange","editing","setEditing","adding","setAdding","patchParameters","map","patchSections","patchField","sectionKey","fieldKey","patchPathologies","reorderParameter","moved","orderByKey","reorderSection","reorderField","candidate","setEnabled","enabled","liveParameters","allParameters","liveFields","allFields","livePathologies","allPathologies","trackedGoals","sectionIndex","archived","liveInSection","sectionRowProps","sectionHandle","IconButtonGroup","List","fieldIndex","parameterRangeText","Lock","isHeading","Switch","EditDialog","AddDialog","onClose","EditDialogBody","editKeyOf","kitLabel","effectiveKitLabel","setLabel","helpText","setHelpText","required","setRequired","editableField","isChoiceField","optionsEditable","setOptions","editedOptions","optionsValid","save","nextLabel","nextHelp","isChoiceType","AddDialogBody","setGroup","setDirection","unit","setUnit","rangeMin","setRangeMin","rangeMax","setRangeMax","setPrecision","fieldType","setFieldType","setCode","parentCode","setParentCode","groupOptions","directionOptions","typeOptions","parentOptions","choiceOptions","valid","trimmedLabel","parseBound","min","resolvedType","sectionLabelForKey","anamnesisNoteId","anamnesisNotes","fromVisits","fromEvents","PATTERN_NS","EN","IT","AR","JA","BUNDLES","registerAnamnesisBundles","i18n","bundle","stampInstant","stampOf","latestAnswered","best","bestInstant","relevantTo","rowFor","chosen","summarySectionsFromRecord","opts","unansweredCount"],"mappings":"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","x_google_ignoreList":[0,1,2]}