@alfadocs/ui-kit-debug 1.3.12 → 1.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/{anamnesis-i18n-9OrXTNS3.js → anamnesis-i18n-CfC0qYzy.js} +2 -2
- package/dist/_chunks/{anamnesis-i18n-9OrXTNS3.js.map → anamnesis-i18n-CfC0qYzy.js.map} +1 -1
- package/dist/_chunks/{appointment-timeline-BB-c1LeR.js → appointment-timeline-B630OT_J.js} +2 -2
- package/dist/_chunks/{appointment-timeline-BB-c1LeR.js.map → appointment-timeline-B630OT_J.js.map} +1 -1
- package/dist/_chunks/{booking-BxFV0hT5.js → booking-DjNbd7C1.js} +2 -2
- package/dist/_chunks/{booking-BxFV0hT5.js.map → booking-DjNbd7C1.js.map} +1 -1
- package/dist/_chunks/{cycle-calculator-DrdC2hPj.js → cycle-calculator-BwqYVPB4.js} +2 -2
- package/dist/_chunks/{cycle-calculator-DrdC2hPj.js.map → cycle-calculator-BwqYVPB4.js.map} +1 -1
- package/dist/_chunks/{date-picker-BP_W6VtE.js → date-picker-ZHejTVAJ.js} +81 -77
- package/dist/_chunks/date-picker-ZHejTVAJ.js.map +1 -0
- package/dist/_chunks/{due-date-calculator-DzNMFyOU.js → due-date-calculator-CwfsFd3T.js} +2 -2
- package/dist/_chunks/{due-date-calculator-DzNMFyOU.js.map → due-date-calculator-CwfsFd3T.js.map} +1 -1
- package/dist/_chunks/{gestational-age-calculator-CuGkVqKp.js → gestational-age-calculator-DdgbH69Z.js} +2 -2
- package/dist/_chunks/{gestational-age-calculator-CuGkVqKp.js.map → gestational-age-calculator-DdgbH69Z.js.map} +1 -1
- package/dist/_chunks/{patient-details-D7D3f9dy.js → patient-details-DqjjwPmt.js} +2 -2
- package/dist/_chunks/{patient-details-D7D3f9dy.js.map → patient-details-DqjjwPmt.js.map} +1 -1
- package/dist/_chunks/{pregnancy-dating-C3WvXHee.js → pregnancy-dating-DzYTlBkT.js} +2 -2
- package/dist/_chunks/{pregnancy-dating-C3WvXHee.js.map → pregnancy-dating-DzYTlBkT.js.map} +1 -1
- package/dist/_chunks/{radiograph-panel.agent-AsXJBr1p.js → radiograph-panel.agent-BQZ64Riy.js} +2 -2
- package/dist/_chunks/{radiograph-panel.agent-AsXJBr1p.js.map → radiograph-panel.agent-BQZ64Riy.js.map} +1 -1
- package/dist/agent-catalog.json +1 -1
- package/dist/components/appointment-timeline/index.js +1 -1
- package/dist/components/booking/index.js +1 -1
- package/dist/components/cycle-calculator/index.js +1 -1
- package/dist/components/date-picker/date-picker.d.ts +8 -0
- package/dist/components/date-picker/date-picker.d.ts.map +1 -1
- package/dist/components/date-picker/index.js +1 -1
- package/dist/components/due-date-calculator/index.js +1 -1
- package/dist/components/gestational-age-calculator/index.js +1 -1
- package/dist/components/patient-details/index.js +1 -1
- package/dist/components/pregnancy-dating/index.js +1 -1
- package/dist/components/radiograph-panel/index.js +1 -1
- package/dist/index.js +10 -10
- package/dist/patterns/anamnesis/index.js +1 -1
- package/package.json +1 -1
- package/dist/_chunks/date-picker-BP_W6VtE.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anamnesis-i18n-9OrXTNS3.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","../../node_modules/lucide-react/dist/esm/icons/square-pen.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-visit-note.tsx","../../src/patterns/anamnesis/anamnesis-matrix.tsx","../../src/patterns/anamnesis/anamnesis-compare-panel.tsx","../../src/patterns/anamnesis/anamnesis-events.ts","../../src/patterns/anamnesis/anamnesis-event-bar.tsx","../../src/patterns/anamnesis/anamnesis-window.ts","../../src/patterns/anamnesis/anamnesis-evolution-grid.tsx","../../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-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"],"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 * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\", key: \"1m0v6g\" }],\n [\n \"path\",\n {\n d: \"M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z\",\n key: \"ohrbg2\"\n }\n ]\n];\nconst SquarePen = createLucideIcon(\"square-pen\", __iconNode);\n\nexport { __iconNode, SquarePen as default };\n//# sourceMappingURL=square-pen.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 { key: 'refluxGastritis', type: 'yesNoDetail', detail: true },\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/** 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 const dob = new Date(dobIso);\n const ref = new Date(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\n/** Format a numeric value to its parameter precision, or an em dash when\n * absent. `0` formats as a value; a non-finite number is absent, because\n * `NaN.toFixed(1)` is the string \"NaN\" and that must never reach a cell.\n * Callers append the unit separately. */\nexport function formatValue(value: number | null, precision = 1): string {\n if (value == null || !Number.isFinite(value)) return ABSENT_VALUE;\n return value.toFixed(precision);\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/** Signed, precision-formatted delta string (e.g. \"+2.4\", \"−1.0\"). Uses a\n * real minus sign for the negative case. */\nexport function formatDelta(abs: number, precision = 1): 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}${Math.abs(rounded).toFixed(precision)}`;\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 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>`. Pins UTC AND the\n * app locale, so one visit cannot render two ways on one screen. */\nexport function visitDateLabel(iso: string, t: TFunction): string {\n return formatCalendarDate(iso, localeOf(t));\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. */\nexport function parseCalendarDate(iso: string): Date | undefined {\n const [y, m, d] = iso.split('-').map(Number);\n if (!y || !m || !d) return undefined;\n return new Date(y, m - 1, d);\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 label = t('anamnesis.compare.visitOption', {\n index: index + 1,\n visitType: t(`anamnesis.visitType.${visit.visitType}`),\n date: visitDateLabel(visit.dateIso, t),\n });\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 return answer.value != null ? String(answer.value) : '—';\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 { 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)}${\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. */\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 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 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 { CALENDAR_DATE_FORMAT, 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={CALENDAR_DATE_FORMAT}\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 { CALENDAR_DATE_FORMAT } from './anamnesis-derive';\nimport type { OpenAnamnesisNote } 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}\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}: MatrixVisitHeaderProps) {\n const { visit } = column;\n return (\n <th\n scope=\"col\"\n className={[\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 <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 <Timestamp\n value={visit.dateIso}\n format=\"absolute\"\n shape=\"bare\"\n absoluteFormat={CALENDAR_DATE_FORMAT}\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 <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 — compare panel (slot 4 of the evolution surface) */\n/* */\n/* \"Confronta\" reworked into ONE reading: tick the visits to compare and */\n/* read every difference in a single table with one grammar — added / */\n/* removed / changed — across every category. It replaces four ragged */\n/* lists whose shapes disagreed with each other. */\n/* */\n/* THE PANEL WEARS THE GRID'S SHAPE. It renders through the same */\n/* `AnamnesisMatrix` shell the evolution grid does, so the columns read */\n/* identity → first compared visit → trend → the rest, the sparklines are */\n/* the same `TrendSparkline` over the same full-record series, and the */\n/* event annotations drawn on the grid are drawn here too. The two reads */\n/* sit one under the other on screen; a second presentation of the same */\n/* record would be a second thing to learn. */\n/* */\n/* COLUMNS: identity → visits… → Change. The Change column is the NET */\n/* first→last change: the direction-aware delta for a numeric row, the */\n/* added/removed/changed word for a row that has no number. The old */\n/* before/after pair generalised into the visit columns, and the old */\n/* change-word column is gone — it named what the arrow already says. */\n/* */\n/* The category is a group banner, not a column, for the same reason the */\n/* grid banners its parameter groups: a value repeated down every row is a */\n/* heading wearing a column's clothes. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport { useId, useMemo, useState } from 'react';\nimport type { TFunction } from 'i18next';\nimport { X } from 'lucide-react';\nimport { Badge } from '../../components/badge';\nimport { Button } from '../../components/button';\nimport { EmptyState } from '../../components/empty-state';\nimport { FormField } from '../../components/form-field';\nimport { MultiSelect } from '../../components/multi-select';\nimport type { SelectOption } from '../../components/select';\nimport { Separator } from '../../components/separator';\nimport type { SparklineAnnotation } from '../../components/sparkline';\nimport {\n ABSENT_VALUE as ABSENT,\n formatValue,\n type DeltaInfo,\n type SpanDiff,\n} from './anamnesis-derive';\nimport {\n parameterLabel,\n pathologyCodeWithLabel,\n visitDateLabel,\n visitOptionLabel,\n} from './anamnesis-format';\nimport { DeltaIndicator, TrendSparkline } from './anamnesis-indicators';\nimport {\n AnamnesisMatrix,\n MATRIX_CELL_CLASS,\n MATRIX_IDENTITY_CLASS,\n MATRIX_TRAILING_CELL_CLASS,\n MATRIX_TREND_COLUMN_CLASS,\n MATRIX_VISIT_COLUMN_CLASS,\n MatrixVisitHeader,\n type MatrixRowSpec,\n} from './anamnesis-matrix';\nimport type {\n MedicationEntry,\n NumericParameterDef,\n PathologyCode,\n Visit,\n} from './anamnesis-types';\nimport type { VisitColumn } from './anamnesis-window';\n\n/* ------------------------------ Row model ------------------------------- */\n\n/** A note is summarised, not reproduced: the full text is one click away in\n * the grid's visit-column note popover. */\nconst NOTE_EXCERPT_MAX = 160;\n\n/** The one grammar every category speaks. */\nexport type CompareChangeKind = 'added' | 'removed' | 'changed';\n\n/** Chip tone per change word. Matched by the sr-only text in every cell, so\n * the word is never carried by colour alone. */\nconst CHANGE_VARIANT: Record<CompareChangeKind, 'success' | 'error' | 'info'> =\n {\n added: 'success',\n removed: 'error',\n changed: 'info',\n };\n\n/** One line of the compare table. Every field is already display-ready, so\n * the renderer below never reaches back into the domain model. */\nexport interface CompareRow {\n /** Stable row id — `<category>:<subject>`. */\n id: string;\n /** Owning category's id (see `COMPARE_CATEGORIES`). */\n categoryId: string;\n /** What changed, in the clinician's words. */\n item: string;\n /** Second line under `item` — the unit and reference range, where there is\n * one. Numeric rows only; the grid puts the same thing in the same place. */\n meta?: string;\n change: CompareChangeKind;\n /** Translated change word — what the Change cell says when there is no\n * number to say it with. */\n changeLabel: string;\n /** One display string per compared visit, in the diff's (record) order. */\n values: string[];\n /** Numeric rows only: the FULL-RECORD series, so the sparkline here is the\n * same line as the grid's — not a shorter one drawn from the picked visits,\n * which would move every event annotation. */\n series?: (number | null)[];\n /** Numeric rows only: the net first→last change, direction-aware. */\n delta?: DeltaInfo | null;\n /** Numeric rows only: needed to colour the delta by valence. */\n def?: NumericParameterDef;\n}\n\nexport interface CompareRowContext {\n t: TFunction;\n pathologies: Record<string, PathologyCode>;\n /** Full-record sparkline series by parameter key. */\n seriesByKey: ReadonlyMap<string, (number | null)[]>;\n}\n\nexport interface CompareCategoryDef {\n /** Stable id; also the i18n leaf under `anamnesis.compare.category.*`. */\n id: string;\n /** Pull this category's rows out of one span diff. */\n rows: (diff: SpanDiff, ctx: CompareRowContext) => CompareRow[];\n}\n\n/* ---------------------------- Row builders ------------------------------ */\n\n/** The change word for a subject that is present at some compared visits and\n * absent at others. Read first→last, because that is the span the Change\n * column reports; a subject that came and went returns to `changed`, which is\n * true (it is not the same story across the span) and never a blank cell. */\nfunction spanKind(present: readonly boolean[]): CompareChangeKind {\n const first = present[0];\n const last = present[present.length - 1];\n if (!first && last) return 'added';\n if (first && !last) return 'removed';\n return 'changed';\n}\n\nfunction excerpt(text: string): string {\n const trimmed = text.trim();\n if (!trimmed) return ABSENT;\n return trimmed.length > NOTE_EXCERPT_MAX\n ? `${trimmed.slice(0, NOTE_EXCERPT_MAX).trimEnd()}…`\n : trimmed;\n}\n\n/** A therapy entry as one string. `withName` disambiguates an entry renamed\n * somewhere in the span, where the name is the thing that changed. */\nfunction describeTherapy(\n entry: MedicationEntry,\n withName: boolean,\n present: string,\n): string {\n const dose = entry.dose?.trim();\n if (withName) return dose ? `${entry.name} · ${dose}` : entry.name;\n return dose ? dose : present;\n}\n\nfunction measurementRows(\n diff: SpanDiff,\n { t, seriesByKey }: CompareRowContext,\n): CompareRow[] {\n return diff.numeric.map((change) => {\n // `== null` throughout: a measurement of 0 is a value, not an absence.\n const present = change.values.map((value) => value != null);\n const kind = spanKind(present);\n return {\n id: `measurement:${change.def.key}`,\n categoryId: 'measurement',\n item: parameterLabel(change.def, t),\n meta: change.def.unit ?? undefined,\n change: kind,\n changeLabel: t(`anamnesis.compare.${kind}`),\n // Bare numbers: the unit is stated once beside the parameter, exactly\n // as the grid states it, rather than repeated in every column.\n values: change.values.map((value) =>\n formatValue(value, change.def.precision),\n ),\n series: seriesByKey.get(change.def.key),\n delta: change.delta,\n def: change.def,\n };\n });\n}\n\nfunction pathologyRows(\n diff: SpanDiff,\n { t, pathologies }: CompareRowContext,\n): CompareRow[] {\n const present = t('anamnesis.compare.present');\n return diff.pathologies.map((change) => {\n const kind = spanKind(change.present);\n return {\n id: `pathology:${change.code}`,\n categoryId: 'pathology',\n item: pathologyCodeWithLabel(change.code, t, pathologies[change.code]),\n change: kind,\n changeLabel: t(`anamnesis.compare.${kind}`),\n values: change.present.map((at) => (at ? present : ABSENT)),\n };\n });\n}\n\nfunction therapyRows(diff: SpanDiff, { t }: CompareRowContext): CompareRow[] {\n const present = t('anamnesis.compare.present');\n return diff.medications.map((change) => {\n const carried = change.entries.filter(\n (entry): entry is MedicationEntry => entry != null,\n );\n // A rename is the change itself, so every cell has to carry the name for\n // the row to be readable at all.\n const renamed = new Set(carried.map((entry) => entry.name)).size > 1;\n const kind = spanKind(change.entries.map((entry) => entry != null));\n return {\n id: `therapy:${change.id}`,\n categoryId: 'therapy',\n // The most recent name the span holds — a renamed entry reads under\n // what it is called now, not under what it used to be called.\n item: carried[carried.length - 1]?.name ?? change.id,\n change: kind,\n changeLabel: t(`anamnesis.compare.${kind}`),\n values: change.entries.map((entry) =>\n entry ? describeTherapy(entry, renamed, present) : ABSENT,\n ),\n };\n });\n}\n\nfunction noteRows(diff: SpanDiff, { t }: CompareRowContext): CompareRow[] {\n return diff.texts.flatMap((change) => {\n const values = change.values.map(excerpt);\n // Two notes that differ only past the excerpt would render as one string\n // repeated across every column — a row that says nothing.\n if (values.every((value) => value === values[0])) return [];\n const kind = spanKind(values.map((value) => value !== ABSENT));\n return [\n {\n id: `note:${change.field}`,\n categoryId: 'note',\n item: t(`anamnesis.field.${change.field}.label`, {\n defaultValue: change.field,\n }),\n change: kind,\n changeLabel: t(`anamnesis.compare.${kind}`),\n values,\n },\n ];\n });\n}\n\n/* --------------------------- Category registry -------------------------- */\n\n/** One entry per `SpanDiff` array, in reading order. A future symptom or\n * event diff is ADDED here — the grammar, the columns and the renderer below\n * stay untouched. Adding a category is data, never a rewrite. */\nexport const COMPARE_CATEGORIES: readonly CompareCategoryDef[] = [\n { id: 'measurement', rows: measurementRows },\n { id: 'pathology', rows: pathologyRows },\n { id: 'therapy', rows: therapyRows },\n { id: 'note', rows: noteRows },\n];\n\n/** Every difference across the compared visits as one flat, ordered list.\n * Category order is the registry's order; within a category, the diff's own\n * order. Nothing is sorted here — the record's order is the reading order. */\nexport function buildCompareRows(\n diff: SpanDiff,\n ctx: CompareRowContext,\n): CompareRow[] {\n return COMPARE_CATEGORIES.flatMap((category) => category.rows(diff, ctx));\n}\n\n/* ------------------------------ Cell render ----------------------------- */\n\n/** The Change cell. A numeric row that has a number on both ends shows the\n * direction-aware delta; everything else — a pathology assigned, a therapy\n * stopped, a note written, a measurement that only exists at one end — shows\n * the change word, because there is no arithmetic to do. */\nfunction ChangeCell({ row, t }: { row: CompareRow; t: TFunction }) {\n if (row.def && row.delta) {\n return <DeltaIndicator delta={row.delta} def={row.def} t={t} />;\n }\n return (\n <Badge variant={CHANGE_VARIANT[row.change]} size=\"sm\">\n {row.changeLabel}\n </Badge>\n );\n}\n\n/* -------------------------------- Panel --------------------------------- */\n\nexport interface AnamnesisComparePanelProps {\n /** The record's visits, in record order — the picker's options. */\n visits: Visit[];\n /** The compared columns, resolved in RECORD order (never tick order). */\n columns: readonly VisitColumn[];\n /** Currently compared visit ids. */\n selectedIds: readonly string[];\n onSelectionChange: (ids: string[]) => void;\n /** The computed diff, or `null` when fewer than two visits are compared. */\n diff: SpanDiff | null;\n /** Full-record sparkline series by parameter key. */\n seriesByKey: ReadonlyMap<string, (number | null)[]>;\n pathologies: Record<string, PathologyCode>;\n /** The event lines drawn on the grid, so they are drawn here too. */\n annotations?: readonly SparklineAnnotation[];\n /** Make those lines pointer-selectable, exactly as they are on the grid.\n * The event bar above the grid stays the keyboard route for both. */\n onSelectAnnotation?: (eventId: string) => void;\n t: TFunction;\n /** Exit compare mode from inside the panel. The toggle that opened it is a\n * full grid above, so without this the only way out is off-screen. */\n onClose?: () => void;\n}\n\n/** Slot 4's contents: a header carrying the way out, the visit picker, then\n * one matrix of differences. The enclosing `Collapsible` lives in\n * `anamnesis-evolution.tsx`. */\nexport function AnamnesisComparePanel({\n visits,\n columns,\n selectedIds,\n onSelectionChange,\n diff,\n seriesByKey,\n pathologies,\n annotations,\n onSelectAnnotation,\n t,\n onClose,\n}: AnamnesisComparePanelProps) {\n const captionId = useId();\n const [refusalNote, setRefusalNote] = useState('');\n\n // Ordinals disambiguate two visits recorded on the same calendar day, which\n // would otherwise render two identical option labels.\n const options = useMemo<SelectOption[]>(\n () =>\n visits.map((visit, index) => ({\n value: visit.id,\n label: visitOptionLabel(visit, index, t),\n })),\n [visits, t],\n );\n\n const rows = useMemo(\n () => (diff ? buildCompareRows(diff, { t, pathologies, seriesByKey }) : []),\n [diff, t, pathologies, seriesByKey],\n );\n\n const readout = useMemo(() => {\n const first = columns[0]?.visit.dateIso;\n const last = columns[columns.length - 1]?.visit.dateIso;\n const shown = t('anamnesis.compare.selected', {\n total: columns.length,\n from: first ? visitDateLabel(first, t) : '',\n to: last ? visitDateLabel(last, t) : '',\n });\n // Said only where it applies: at two visits the next removal is the one\n // the picker refuses, and silence there reads as a broken control.\n return columns.length === 2\n ? `${shown} · ${t('anamnesis.compare.minimum')}`\n : shown;\n }, [columns, t]);\n\n const visitHeaders = useMemo(\n () =>\n columns.map((column) => (\n <MatrixVisitHeader\n key={column.key}\n column={column}\n t={t}\n emphasised\n // The same visit's note trigger is already in the grid column\n // directly above; a second one with the same accessible name is a\n // control the reader has to tell apart from itself.\n withNote={false}\n />\n )),\n [columns, t],\n );\n\n const matrixRows = useMemo<MatrixRowSpec[]>(() => {\n const built: MatrixRowSpec[] = [];\n let lastCategory: string | null = null;\n for (const row of rows) {\n if (row.categoryId !== lastCategory) {\n lastCategory = row.categoryId;\n built.push({\n key: `group-${row.categoryId}`,\n banner: t(`anamnesis.compare.category.${row.categoryId}`),\n });\n }\n built.push({\n key: row.id,\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:break-words ds:text-[color:var(--foreground)]\">\n {row.item}\n </span>\n {row.meta ? (\n <span className=\"type-meta ds:text-[color:var(--muted-foreground)]\">\n {row.meta}\n </span>\n ) : null}\n </div>\n </th>\n ),\n cells: row.values.map((value, index) => (\n <td\n key={columns[index]?.key ?? index}\n className={`${MATRIX_VISIT_COLUMN_CLASS} ${MATRIX_CELL_CLASS} ds:tabular-nums`}\n >\n <span className=\"type-body-sm ds:block ds:break-words ds:whitespace-normal ds:text-[color:var(--foreground)]\">\n {value}\n </span>\n </td>\n )),\n trend: (\n <td className={`${MATRIX_TREND_COLUMN_CLASS} ${MATRIX_CELL_CLASS}`}>\n {row.series && row.def ? (\n <TrendSparkline\n series={row.series}\n def={row.def}\n t={t}\n annotations={annotations}\n onSelectAnnotation={onSelectAnnotation}\n />\n ) : null}\n </td>\n ),\n trailing: (\n <td\n className={`${MATRIX_VISIT_COLUMN_CLASS} ${MATRIX_CELL_CLASS} ${MATRIX_TRAILING_CELL_CLASS}`}\n data-change={row.change}\n >\n <ChangeCell row={row} t={t} />\n </td>\n ),\n });\n }\n return built;\n }, [rows, columns, annotations, onSelectAnnotation, t]);\n\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n {/* The way out, at the top of what the toggle scrolled the reader to. A\n plain action, NOT a second state-owner: `aria-pressed` /\n `aria-expanded` stay on the toolbar toggle. */}\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-between ds:gap-[var(--spacing-md)]\">\n <h3 className=\"type-title-section ds:m-0 ds:text-[color:var(--foreground)]\">\n {t('anamnesis.compare.panelTitle')}\n </h3>\n {onClose ? (\n <Button\n intent=\"outline\"\n data-testid=\"anamnesis-compare-close\"\n startIcon={<X aria-hidden=\"true\" className=\"ds:size-5\" />}\n onClick={onClose}\n >\n {t('anamnesis.compare.stop')}\n </Button>\n ) : null}\n </div>\n\n <div\n data-testid=\"anamnesis-compare-picker\"\n className=\"ds:min-w-[18rem] ds:max-w-[32rem]\"\n >\n {/* No clear-all, and no floor of one: a comparison needs two visits,\n so an affordance whose effect is refused is worse than none. */}\n <FormField\n label={t('anamnesis.compare.visitsLabel')}\n description={readout}\n >\n <MultiSelect\n options={options}\n value={[...selectedIds]}\n allowSelectAll\n onChange={(next) => {\n if (next.length >= 2) {\n setRefusalNote('');\n onSelectionChange(next);\n return;\n }\n setRefusalNote(t('anamnesis.compare.minimum'));\n }}\n />\n </FormField>\n {/* The floor is enforced by REFUSING the change, and a description\n never re-read is no explanation at all for a screen reader. */}\n <span\n role=\"status\"\n data-testid=\"anamnesis-compare-floor\"\n className=\"ds:sr-only\"\n >\n {refusalNote}\n </span>\n </div>\n\n <Separator />\n\n <div\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n data-testid=\"anamnesis-compare-summary\"\n >\n {diff ? (\n <>\n {/* h4: the summary sits inside the panel whose header is the h3\n above, so the level increments rather than repeating. */}\n <h4 className=\"type-title-item ds:m-0 ds:text-[color:var(--foreground)]\">\n {t('anamnesis.compare.summaryTitle', {\n from: visitDateLabel(diff.visits[0].dateIso, t),\n to: visitDateLabel(\n diff.visits[diff.visits.length - 1].dateIso,\n t,\n ),\n })}\n </h4>\n {rows.length === 0 ? (\n <EmptyState\n variant=\"no-results\"\n size=\"sm\"\n title={t('anamnesis.compare.noChanges')}\n description={t('anamnesis.compare.noChangesDescription')}\n />\n ) : (\n <AnamnesisMatrix\n captionId={captionId}\n caption={t('anamnesis.compare.tableLabel')}\n identityLabel={t('anamnesis.compare.column.item')}\n trendLabel={t('anamnesis.grid.trend')}\n trailingLabel={t('anamnesis.compare.column.change')}\n trailingTestId=\"anamnesis-compare-change-column\"\n visitHeaders={visitHeaders}\n rows={matrixRows}\n testId=\"anamnesis-compare-table\"\n />\n )}\n </>\n ) : (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.compare.sameVisit')}\n </p>\n )}\n </div>\n </div>\n );\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 { 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 const times = visits.map((visit) => new Date(visit.dateIso).getTime());\n const at = new Date(event.dateIso).getTime();\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 — visit window (which visit columns are rendered) */\n/* */\n/* A multi-year history is a horizontal-scroll problem: thirteen visits */\n/* is thirteen columns nobody reads with a patient in the room. The */\n/* clinician therefore picks the columns EXPLICITLY, from a multi-select */\n/* listing every visit; the default picks the FIRST visit and the LATEST, */\n/* which answers the question actually asked with the patient present — */\n/* \"how far have we come\". */\n/* */\n/* Nothing stands in for an unpicked 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/* 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 /** Visit ids rendered on top of the selection — the compare anchors, so a\n * compared column is never one the picker left out. */\n alsoShowIds?: Iterable<string>;\n}\n\n/* --------------------------------- API ---------------------------------- */\n\n/** The selection the picker opens on: the first visit and the latest. On a\n * single-visit record the two collapse to one. */\nexport function defaultSelectedVisitIds(visits: readonly Visit[]): string[] {\n if (visits.length === 0) return [];\n const first = visits[0].id;\n const latest = visits[visits.length - 1].id;\n return first === latest ? [first] : [first, latest];\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 shown = new Set<string>(selectedIds);\n for (const id of options.alsoShowIds ?? []) 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 return {\n columns,\n shownCount: columns.length,\n totalCount: visits.length,\n hiddenCount: visits.length - columns.length,\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(\n visits,\n visits.map((v) => v.id),\n ).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 the */\n/* first visit and the LATEST. A delta is drawn only where the column before */\n/* it on screen IS the visit it was measured against. */\n/* -------------------------------------------------------------------- */\n\nimport { useId } from 'react';\nimport type { TFunction } from 'i18next';\nimport { NumberInput } from '../../components/number-input';\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 { 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\nfunction formatRange(\n range: NumericParameterDef['referenceRange'],\n t: TFunction,\n): string | null {\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/* -------------------------------- 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 onCellChange?: (\n visit: Visit,\n def: NumericParameterDef,\n value: number | null,\n ) => void;\n /** Compare mode: the visit ids under comparison (two or more) + the CELLS\n * that differ from the compared column before them, keyed\n * `<visitId>:<parameterKey>`. Per cell, never per parameter: at three or\n * more compared visits a column equal to its predecessor did not change. */\n compare?: {\n visitIds: ReadonlySet<string>;\n changedCells: ReadonlySet<string>;\n } | null;\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}\n\n/* ------------------------------- Component ------------------------------ */\n\nexport function AnamnesisEvolutionGrid({\n record,\n defs,\n t,\n editable = false,\n onCellChange,\n compare = null,\n framed = true,\n defaultOpenNoteVisitId,\n onOpenNote,\n visitColumns,\n capturableKeys,\n annotations,\n onSelectAnnotation,\n}: AnamnesisEvolutionGridProps) {\n const captionId = useId();\n const rows = buildParameterRows(record, defs);\n const visits = record.visits;\n const latestIndex = visits.length - 1;\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 const isComparedColumn = (visitId: string) =>\n compare?.visitIds.has(visitId) ?? false;\n\n rows.forEach((row: ParameterRow) => {\n if (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);\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 // Position, not id: a record carrying a duplicated visit id would\n // otherwise make two columns editable and write to the wrong one.\n const isLatest = index === latestIndex;\n const capturable =\n capturableKeys == null || capturableKeys.has(row.def.key);\n const editableCell =\n editable && isLatest && capturable && !row.def.computed;\n const deltaHidden = !deltaIsLegible(columns, columnIndex);\n const changed =\n compare != null &&\n compare.changedCells.has(`${visit.id}:${row.def.key}`);\n const emphasised = isComparedColumn(visit.id);\n return (\n <td\n key={column.key}\n data-changed={changed || undefined}\n className={[\n MATRIX_VISIT_COLUMN_CLASS,\n MATRIX_CELL_CLASS,\n 'ds:tabular-nums',\n emphasised ? 'ds:bg-[color:var(--muted)]/40' : '',\n // Changed cells carry a fill tint AND a non-colour inline-start\n // border bar so the change reads without relying on hue.\n changed\n ? 'ds:bg-[color:var(--info)]/10 ds:border-s-2 ds:border-[color:var(--info)]'\n : '',\n ]\n .filter(Boolean)\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)}\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 {changed ? (\n <span className=\"ds:sr-only\">\n {t('anamnesis.compare.changedCell')}\n </span>\n ) : null}\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),\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 emphasised={isComparedColumn(column.visit.id)}\n editable={editable && column.index === latestIndex}\n defaultOpenNoteVisitId={defaultOpenNoteVisitId}\n onOpenNote={onOpenNote}\n />\n ));\n\n return (\n <AnamnesisMatrix\n captionId={captionId}\n 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 — evolution section (grid + compare) */\n/* */\n/* The across-visits view, shared by compile mode (editable newest column) */\n/* and read-only mode (no edit affordances). */\n/* */\n/* FIXED VERTICAL ORDER — five slots, and nothing else may be inserted: */\n/* 0. Empty state — replaces slots 1–4 when the record has no visit */\n/* 1. Toolbar — one wrapping row: the visit multi-select and */\n/* its readout, then the Compare toggle */\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/* 4. Compare panel — closed by default, opened by the toolbar's */\n/* Compare toggle, closed by either that or its own */\n/* header exit (the toggle scrolls out of reach) */\n/* */\n/* The default state is therefore one table under one row of controls, */\n/* with every secondary surface folded away: a clinician with a patient in */\n/* front of them reads the grid without hunting. */\n/* -------------------------------------------------------------------- */\n\nimport { useEffect, useId, useMemo, useRef, useState } from 'react';\nimport type { TFunction } from 'i18next';\nimport { Button } from '../../components/button';\nimport { Collapsible, CollapsibleContent } from '../../components/collapsible';\nimport { EmptyState } from '../../components/empty-state';\nimport { FormField } from '../../components/form-field';\nimport { MultiSelect } from '../../components/multi-select';\nimport type { SelectOption } from '../../components/select';\nimport { AnamnesisComparePanel } from './anamnesis-compare-panel';\nimport {\n allParametersIncludingArchived,\n configuredParameters,\n pathologyLookup,\n type PracticeAnamnesisConfig,\n} from './anamnesis-config';\nimport { buildParameterRows, compareVisitSpan } from './anamnesis-derive';\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 defaultSelectedVisitIds,\n visitPickerIsUseful,\n windowVisits,\n} 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 /** Mount with the compare panel already open. Demo/story hook only —\n * Chromatic skips play functions, so a click-opened panel is never\n * snapshotted. */\n defaultCompareOpen?: boolean;\n /** Mount with this visit selection instead of first + latest. Demo/story\n * hook only, for the same Chromatic reason. */\n defaultVisitIds?: readonly string[];\n /** Mount the compare panel on this set of visits instead of first + latest.\n * Demo/story hook only, for the same Chromatic reason. */\n defaultCompareVisitIds?: 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 * The Diagnosis surface's one export control needs to know which visit\n * columns are on screen — the file must be the view that was asked for. */\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}\n\n/* ------------------------------- Component ------------------------------ */\n\nexport function AnamnesisEvolution({\n record,\n t,\n editable = false,\n onCellChange,\n framed = true,\n config,\n defaultCompareOpen = false,\n defaultVisitIds,\n defaultCompareVisitIds,\n defaultEventIds,\n onVisitSelectionChange,\n onOpenNote,\n}: AnamnesisEvolutionProps) {\n const { visits } = record;\n const canCompare = visits.length >= 2;\n const comparePanelId = useId();\n const compareToggleId = useId();\n\n // History surface: archived parameters stay, so a value recorded under a\n // since-archived parameter still renders.\n const defs = useMemo(() => allParametersIncludingArchived(config), [config]);\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 const pathologies = useMemo(() => pathologyLookup(config), [config]);\n\n const [compareOn, setCompareOn] = useState(defaultCompareOpen);\n const [refusalNote, setRefusalNote] = useState('');\n // The panel opens BELOW a full-height grid, so without this the toggle looks\n // like it did nothing. `start`, not `nearest`: the panel is taller than the\n // viewport, and `nearest` parks its header on the bottom edge.\n const comparePanelRef = useRef<HTMLDivElement>(null);\n const compareToggleRef = useRef<HTMLButtonElement>(null);\n // Skipped on mount so a `defaultCompareOpen` story never scrolls itself.\n const compareMounted = useRef(false);\n useEffect(() => {\n if (compareMounted.current && compareOn)\n comparePanelRef.current?.scrollIntoView({ block: 'start' });\n compareMounted.current = true;\n }, [compareOn]);\n // Leaving from inside the panel hands focus back to the toggle that owns the\n // state — which scrolls it into view, so the reader lands where they began.\n const closeCompare = () => {\n setCompareOn(false);\n compareToggleRef.current?.focus();\n };\n // First + latest by default — the same two visits the grid shows, so the\n // panel opens on the columns already on screen and every other visit is one\n // tick away. The same MultiSelect idiom as the grid's picker: two surfaces\n // reading the same record must not offer two different ways to choose it.\n const [pickedCompareIds, setPickedCompareIds] = useState<string[]>(() =>\n defaultCompareVisitIds\n ? [...defaultCompareVisitIds]\n : defaultSelectedVisitIds(visits),\n );\n\n // Falls back to the default whenever fewer than two picked visits are still\n // in the record — a host that swaps the record would otherwise leave dead\n // ids and a panel claiming there is nothing to compare. Same floor of two\n // the picker enforces on deselection.\n const compareSelectedIds = useMemo(() => {\n const live = pickedCompareIds.filter((id) =>\n visits.some((v) => v.id === id),\n );\n return live.length >= 2 ? live : defaultSelectedVisitIds(visits);\n }, [pickedCompareIds, visits]);\n\n // Compared columns are resolved in RECORD order, never tick order — a set\n // of ticked visits has no order of its own, and columns disagreeing with\n // the grid directly above them would be unreadable.\n const compareColumns = useMemo(\n () => windowVisits(visits, compareSelectedIds).columns,\n [visits, compareSelectedIds],\n );\n\n const diff = useMemo(() => {\n if (!compareOn) return null;\n return compareVisitSpan(\n compareColumns.map((column) => column.visit),\n defs,\n );\n }, [compareOn, compareColumns, defs]);\n\n // The grid's own series, by parameter key: the compare panel draws the SAME\n // full-record line the grid draws, so an event annotation lands on the same\n // x in both.\n const seriesByKey = useMemo(() => {\n const map = new Map<string, (number | null)[]>();\n for (const row of buildParameterRows(record, defs)) {\n map.set(row.def.key, row.series);\n }\n return map;\n }, [record, defs]);\n\n /* ---- Visit picker: which columns render (never which maths run) ---- */\n const [pickedVisitIds, setPickedVisitIds] = useState<string[]>(() =>\n defaultVisitIds ? [...defaultVisitIds] : defaultSelectedVisitIds(visits),\n );\n const pickable = visitPickerIsUseful(visits);\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 the default rather than to\n // nothing. Same floor the picker enforces on deselection.\n const selectedVisitIds = useMemo(() => {\n const live = pickedVisitIds.filter((id) => visits.some((v) => v.id === id));\n return live.length > 0 ? live : defaultSelectedVisitIds(visits);\n }, [pickedVisitIds, visits]);\n\n const visitWindow = useMemo(\n () =>\n windowVisits(visits, selectedVisitIds, {\n // A compared visit is always a column, so compare always marks its\n // columns in the grid — comparing a visit the picker left out brings\n // it back on screen rather than marking nothing.\n alsoShowIds: compareOn ? compareSelectedIds : [],\n }),\n [visits, selectedVisitIds, compareOn, compareSelectedIds],\n );\n\n // Reported, never owned: the host only mirrors what the grid draws. The\n // RENDERED window, not the picked set — compare adds its anchors as columns,\n // and an export that followed the picker alone would file two columns off a\n // screen showing four, with a change column spanning a different pair of\n // dates than the one being read.\n const shownVisitIds = useMemo(\n () => visitWindow.columns.map((column) => column.visit.id),\n [visitWindow],\n );\n useEffect(() => {\n onVisitSelectionChange?.(shownVisitIds);\n }, [shownVisitIds, onVisitSelectionChange]);\n\n const visitOptions = useMemo<SelectOption[]>(\n () =>\n visits.map((visit, index) => ({\n value: visit.id,\n label: visitOptionLabel(visit, index, t, hasVisitNotes(visit)),\n })),\n [visits, t],\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 const parts = [shown];\n // Compare force-adds its anchors as columns, so the count above can exceed\n // the picked set. Say where the extra columns came from rather than\n // leaving the picker's chip count contradicting the table.\n const added = visitWindow.shownCount - selectedVisitIds.length;\n if (added > 0) parts.push(t('anamnesis.window.addedByCompare', { added }));\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]);\n\n /* ---- Events: one shared x domain, one line per picked event ---- */\n // Positions come from the record's visit span, NOT from any row's point\n // count and NOT from the visit selection — the sparklines plot the whole\n // record, 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 // Marks CELLS, not parameters. A parameter that moved somewhere across the\n // span does not make every compared column of it a change: with three or\n // more visits a column identical to the one compared before it would\n // otherwise be tinted and announced \"Changed\" beside its own \"0\" delta.\n const compareForGrid = useMemo(() => {\n if (!diff) return null;\n const changedCells = new Set<string>();\n for (const change of diff.numeric) {\n change.values.forEach((value, at) => {\n const against = at === 0 ? change.values[1] : change.values[at - 1];\n if (value !== against)\n changedCells.add(`${diff.visits[at].id}:${change.def.key}`);\n });\n }\n return {\n visitIds: new Set(diff.visits.map((visit) => visit.id)),\n changedCells,\n };\n }, [diff]);\n\n /* ---- SLOT 0 — no visits: nothing to plot, nothing to compare ---- */\n if (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-md)]\">\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 {pickable || canCompare ? (\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 {pickable ? (\n <div\n data-testid=\"anamnesis-window-picker\"\n className=\"ds:min-w-[18rem] ds:max-w-[32rem] ds:grow\"\n >\n <FormField\n label={t('anamnesis.window.label')}\n description={windowReadout}\n >\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. */}\n <MultiSelect\n options={visitOptions}\n value={selectedVisitIds}\n allowSelectAll\n onChange={(next) => {\n if (next.length > 0) {\n setRefusalNote('');\n setPickedVisitIds(next);\n return;\n }\n setRefusalNote(t('anamnesis.window.minimum'));\n }}\n />\n </FormField>\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 {/* `pressed` = compare mode is on (the grid marks changed cells too);\n `expanded` = the panel below is open, and it also keeps the\n aria-controls target valid while the panel is unmounted. */}\n {canCompare ? (\n // The picker beside it is a FormField — label, control, then\n // description. A bare button in an `items-start` row top-aligns\n // with that LABEL and reads as floating above the control it acts\n // on, so reserve one label line above it. Sized from the same type\n // token as the real label, so it tracks the accessible theme's\n // larger type instead of a hardcoded offset.\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span aria-hidden=\"true\" className=\"type-label ds:invisible\">\n \n </span>\n <Button\n ref={compareToggleRef}\n id={compareToggleId}\n intent={compareOn ? 'primary' : 'outline'}\n data-testid=\"anamnesis-compare-toggle\"\n aria-pressed={compareOn}\n aria-expanded={compareOn}\n aria-controls={comparePanelId}\n onClick={() => setCompareOn((on) => !on)}\n >\n {compareOn\n ? t('anamnesis.compare.stop')\n : t('anamnesis.compare.start')}\n </Button>\n </div>\n ) : 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={record}\n defs={defs}\n t={t}\n editable={editable}\n onCellChange={onCellChange}\n compare={compareForGrid}\n framed={framed}\n visitColumns={visitWindow.columns}\n capturableKeys={capturableKeys}\n annotations={annotations}\n onSelectAnnotation={selectAnnotation}\n onOpenNote={onOpenNote}\n />\n\n {/* SLOT 4 — compare panel. Nothing else may be inserted at this position. */}\n {canCompare ? (\n <Collapsible open={compareOn} onOpenChange={setCompareOn}>\n <CollapsibleContent\n ref={comparePanelRef}\n id={comparePanelId}\n aria-labelledby={compareToggleId}\n data-testid=\"anamnesis-compare-panel\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n <AnamnesisComparePanel\n visits={visits}\n columns={compareColumns}\n selectedIds={compareSelectedIds}\n onSelectionChange={setPickedCompareIds}\n diff={diff}\n seriesByKey={seriesByKey}\n pathologies={pathologies}\n annotations={annotations}\n onSelectAnnotation={selectAnnotation}\n t={t}\n onClose={closeCompare}\n />\n </CollapsibleContent>\n </Collapsible>\n ) : (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.compare.needTwoVisits')}\n </p>\n )}\n </div>\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 — 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 (unit carried in the FormField 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 { 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 { intakeFieldHelp, intakeFieldLabelWithUnit } from './anamnesis-format';\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/** Number fields captured to one decimal place vs whole numbers. */\nconst DECIMAL_NUMBER_FIELDS = new Set(['weightSelf', 'waterPerDay']);\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 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 t,\n}: AnamnesisFieldProps) {\n const label = intakeFieldLabelWithUnit(def, t);\n const description = intakeFieldHelp(def, t);\n const showMarker = showOrigin && origin === 'patient';\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 label={label} description={description}>\n <TextInput\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 label={label} description={description}>\n <TextArea\n disabled={readOnly}\n value={value}\n autoResize\n minRows={2}\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 label={label} description={description}>\n <NumberInput\n disabled={readOnly}\n value={value}\n min={0}\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 label={label} description={description}>\n <NumberInput\n disabled={readOnly}\n value={perWeek}\n min={0}\n max={21}\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 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 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 {def.detail && present === 'yes' ? (\n <FormField label={t('anamnesis.common.details')}>\n <TextInput\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 ) : 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 label={label} description={description}>\n <Select\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 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:text-[color:var(--foreground)]\">\n {label}\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:text-[color:var(--foreground)]\">\n {label}\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 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 className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\"\n >\n {showMarker ? (\n <div className=\"ds:flex ds:justify-end\">\n <OriginMarker t={t} />\n </div>\n ) : null}\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 { 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. Unit symbols are\n * locale-invariant scientific notation, as everywhere else in this pattern. */\nfunction withUnit(value: number, def: NumericParameterDef): string {\n const text = formatValue(value, def.precision);\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 // 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),\n band: tUi(`bmiCalculator.category.${bmiCategory(now)}`),\n })\n : t('anamnesis.targets.now', { value: withUnit(now, def) });\n\n return (\n <TargetTile\n variant=\"elevated\"\n label={label}\n target={\n target == null ? t('anamnesis.targets.unset') : withUnit(target, def)\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 } 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 fieldVisible,\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 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),\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)} ${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 /** 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 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. Bails on an identical set — the child reports on every mount\n // and a fresh array each time would otherwise re-render this surface.\n const [shownVisitIds, setShownVisitIds] = useState<string[]>([]);\n const trackShownVisits = useCallback((ids: readonly string[]) => {\n setShownVisitIds((prev) =>\n prev.length === ids.length && prev.every((id, i) => id === ids[i])\n ? prev\n : [...ids],\n );\n }, []);\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. */}\n <DatePicker\n value={parseCalendarDate(latest.dateIso)}\n onChange={(next) =>\n next &&\n patchLatest((v) => ({\n ...v,\n dateIso: toCalendarIso(next),\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 />\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 { CALENDAR_DATE_FORMAT, latestVisit } 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 { AnamnesisRecord, IntakeAnswer } from './anamnesis-types';\n\n/* ------------------------------- Helpers -------------------------------- */\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 // Re-seed when the host swaps the record (see the same guard in\n // AnamnesisQuestionnaire). Without it, a host that refreshes in place rather\n // than reloading the page keeps showing the PREVIOUS questionnaire's\n // answers — a freshly created interview would arrive already full.\n const [seededFrom, setSeededFrom] = useState(record);\n if (record !== seededFrom) {\n setSeededFrom(record);\n setAnswers(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.\n const [openSection, setOpenSection] = useState<string>(\n () => defaultOpenSection ?? visibleSections[0]?.key ?? '',\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 setOpenSection(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 setOpenSection(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 absoluteFormat={CALENDAR_DATE_FORMAT}\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}>\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=\"single\"\n collapsible\n variant=\"default\"\n value={openSection}\n onValueChange={setOpenSection}\n >\n {visibleSections.map((section) => {\n const sectionAnswered = section.fields.filter((f) =>\n isIntakeAnswered(answers[f.key]),\n ).length;\n return (\n <AccordionItem key={section.key} value={section.key}>\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 <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]\">\n {section.fields.map((field) => (\n <AnamnesisField\n readOnly={readOnly}\n key={field.key}\n def={field}\n answer={answers[field.key]}\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 + comparison stay available. Not a screenshot */\n/* of compile mode with disabled inputs — a 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 CALENDAR_DATE_FORMAT,\n deltaInfo,\n formatValue,\n outOfRange,\n parameterValueAt,\n} from './anamnesis-derive';\nimport { AnamnesisEvolution } from './anamnesis-evolution';\nimport {\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 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)}\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),\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}\n\n/* ------------------------------- Component ------------------------------ */\n\nexport function AnamnesisReadOnly({\n record,\n t,\n embedded = false,\n config,\n onOpenNote,\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\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={CALENDAR_DATE_FORMAT}\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 + comparison */}\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 />\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 tabs, because those are the only two things this surface does: */\n/* answer/read the questionnaire, and compare its numbers over time. The */\n/* compile mode's eleven bespoke blocks are deliberately absent. */\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 { SquarePen } from 'lucide-react';\nimport { Tabs } from '../../components/tabs';\nimport { AnamnesisIntake, type IntakeAnswerMap } from './anamnesis-intake';\nimport { AnamnesisEvolution } from './anamnesis-evolution';\nimport { Badge } from '../../components/badge';\nimport { Button } from '../../components/button';\nimport { EmptyState } from '../../components/empty-state';\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 /** The reader may not change answers at all (no write grant). The Edit\n * affordance is then absent, not merely disabled — an action a user can\n * never complete should not be offered. */\n canEdit?: boolean;\n /** Mount on this tab instead of the questionnaire. Demo/story hook only —\n * Chromatic skips play functions, so a click-selected tab is never\n * snapshotted. */\n defaultTab?: AnamnesisQuestionnaireTab;\n}\n\nexport type AnamnesisQuestionnaireTab = 'questionnaire' | 'trend';\n\nexport function AnamnesisQuestionnaire({\n record,\n t,\n config,\n onSubmit,\n jumpToField,\n statusSlot,\n onTargetChange,\n hideTargetStrip = false,\n canEdit = true,\n defaultTab = 'questionnaire',\n}: AnamnesisQuestionnaireProps) {\n const [tab, setTab] = useState<AnamnesisQuestionnaireTab>(defaultTab);\n // An ALREADY-COMPILED questionnaire opens READ-ONLY, exactly as the legacy\n // pane did: the reader sees at a glance that it has been answered, and has\n // to ask before overwriting the patient's own words. A blank one opens\n // ready to answer, because there is nothing to protect.\n const alreadyCompiled = record.intake?.submittedAtIso != null;\n const [editing, setEditing] = useState(!alreadyCompiled);\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 and edit state. 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 // A record with answers arrives protected; a blank one arrives ready to\n // answer. Same rule as the first mount.\n setEditing(record.intake?.submittedAtIso == null);\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\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 || 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\n value={tab}\n onValueChange={(next) => setTab(next as AnamnesisQuestionnaireTab)}\n >\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 <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 <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]\">\n {statusSlot}\n {alreadyCompiled && !editing ? (\n <Badge variant=\"neutral\">\n {t('anamnesis.questionnaire.compiled')}\n </Badge>\n ) : null}\n {canEdit && !editing ? (\n <Button\n intent=\"outline\"\n size=\"sm\"\n startIcon={<SquarePen aria-hidden=\"true\" />}\n data-testid=\"anamnesis-questionnaire-edit\"\n onClick={() => {\n setEditing(true);\n setTab('questionnaire');\n }}\n >\n {t('anamnesis.questionnaire.edit')}\n </Button>\n ) : null}\n </div>\n </div>\n\n <Tabs.Content value=\"questionnaire\">\n {/* `embedded` unconditionally: the questionnaire sits inside this\n card's tab panel, so its own page chrome would double the\n heading the tab already provides. */}\n <AnamnesisIntake\n record={working}\n t={t}\n embedded\n config={config}\n readOnly={!editing}\n onSubmit={(answers) => {\n // Saving closes the edit session: back to the protected\n // read of what is now on record.\n setEditing(false);\n onSubmit?.(answers);\n }}\n jumpToField={jumpToField}\n />\n </Tabs.Content>\n\n <Tabs.Content value=\"trend\">\n {numericDefs.length === 0 ? (\n <EmptyState\n variant=\"no-results\"\n title={t('anamnesis.questionnaire.noNumeric.title')}\n description={t('anamnesis.questionnaire.noNumeric.description')}\n />\n ) : (\n /* Read-only: values are answered in the questionnaire, never\n typed into the grid — one place to answer a question. */\n <AnamnesisEvolution\n record={working}\n t={t}\n config={config}\n framed={false}\n />\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 { AnamnesisQuestionnaireTab } from './anamnesis-questionnaire';\nimport type {\n AnamnesisMode,\n AnamnesisRecord,\n OpenAnamnesisNote,\n PractitionerOption,\n} from './anamnesis-types';\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 /** 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: the reader may not change answers at all. The\n * Edit affordance is then absent rather than disabled. Default true. */\n canEdit?: boolean;\n /** Questionnaire mode only: mount on this tab instead of the questionnaire.\n * Demo/story hook only — 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 onMissingAnswerJump,\n onRecordChange,\n canEdit,\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 />\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 canEdit={canEdit}\n defaultTab={defaultQuestionnaireTab}\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 />\n ) : (\n <AnamnesisReadOnly\n record={record}\n t={t}\n embedded={embedded}\n config={config}\n onOpenNote={onOpenNote}\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: { intake: 'Intake', compile: 'Compile', readOnly: 'Read-only' },\n common: {\n yes: 'Yes',\n no: 'No',\n unknown: 'Unknown',\n notSure: 'Not sure',\n choose: 'Choose…',\n details: 'Details',\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 // `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 start: 'Compare',\n stop: 'Stop comparing',\n panelTitle: 'Compare visits',\n needTwoVisits: 'Two or more visits are needed to compare.',\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 changedCell: 'Changed',\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 target: 'Target {{value}} {{unit}}',\n trendLabel: '{{parameter}} trend',\n trend: 'Trend',\n editable: 'Editable',\n editCell: '{{parameter}} — latest visit',\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 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 compiled: 'Compiled',\n edit: 'Edit',\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 },\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 },\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 showing: 'Showing {{shown}} of {{total}} visits · {{from}} – {{to}}',\n showingAll: 'All {{total}} visits · {{from}} – {{to}}',\n minimum: 'At least one visit stays shown',\n // `added` / `label`, never `count`: a plural-suffixed key would need six\n // forms in Arabic to say a number the sentence already carries.\n addedByCompare: '{{added}} added by Compare',\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 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 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 selected: '{{total}} visite confrontate · {{from}} – {{to}}',\n minimum: 'Restano confrontate almeno due visite',\n start: 'Confronta',\n stop: 'Interrompi confronto',\n panelTitle: 'Confronta le visite',\n needTwoVisits: 'Servono due o più visite per confrontare.',\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 changedCell: 'Modificato',\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 target: 'Obiettivo {{value}} {{unit}}',\n trendLabel: 'Andamento {{parameter}}',\n trend: 'Andamento',\n editable: 'Modificabile',\n editCell: '{{parameter}} — ultima visita',\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 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 compiled: 'Compilata',\n edit: 'Modifica',\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 },\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 },\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 // 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 addedByCompare: '{{added}} aggiunte dal confronto',\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: { intake: 'الاستجواب', compile: 'التجميع', readOnly: 'للقراءة فقط' },\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 selected: 'مقارنة {{total}} زيارة · {{from}} – {{to}}',\n minimum: 'تبقى زيارتان على الأقل قيد المقارنة',\n start: 'قارن',\n stop: 'إيقاف المقارنة',\n panelTitle: 'مقارنة الزيارات',\n needTwoVisits: 'يلزم زيارتان أو أكثر للمقارنة.',\n sameVisit: 'اختر زيارتين مختلفتين أو أكثر لعرض التغيّرات.',\n summaryTitle: 'التغيّرات من {{from}} إلى {{to}}',\n tableLabel: 'ما الذي تغيّر بين الزيارات المقارَنة',\n noChanges: 'لا توجد تغيّرات بين هذه الزيارات.',\n noChangesDescription:\n 'سُجِّلت في كل الزيارات القيم والرموز والعلاجات والملاحظات نفسها.',\n present: 'موجود',\n added: 'أُضيف',\n removed: 'أُزيل',\n changed: 'تغيّر',\n changedCell: 'تغيّر',\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 target: 'الهدف {{value}} {{unit}}',\n trendLabel: 'اتجاه {{parameter}}',\n trend: 'الاتجاه',\n editable: 'قابل للتعديل',\n editCell: '{{parameter}} — آخر زيارة',\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 empty: {\n noVisits: {\n title: 'لا توجد زيارات بعد',\n description: 'بعد تسجيل الزيارة الأولى تظهر القيم والاتجاهات هنا.',\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 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 showing: 'عرض {{shown}} من {{total}} زيارة · {{from}} – {{to}}',\n showingAll: 'كل الزيارات {{total}} · {{from}} – {{to}}',\n minimum: 'تبقى زيارة واحدة معروضة على الأقل',\n addedByCompare: 'أضافت المقارنة {{added}}',\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: { intake: '問診', compile: '記入', readOnly: '閲覧のみ' },\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 selected: '{{total}}回の受診を比較 · {{from}} – {{to}}',\n minimum: '受診は2件以上比較されます',\n start: '比較',\n stop: '比較を終了',\n panelTitle: '受診を比較',\n needTwoVisits: '比較には2回以上の受診が必要です。',\n sameVisit: '異なる2回以上の受診を選択してください。',\n summaryTitle: '{{from}}から{{to}}への変化',\n tableLabel: '比較した受診の間に変わったこと',\n noChanges: 'これらの受診の間に変化はありません。',\n noChangesDescription:\n 'いずれの受診でも同じ測定値・コード・処方・メモが記録されています。',\n present: 'あり',\n added: '追加',\n removed: '削除',\n changed: '変更',\n changedCell: '変更',\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 target: '目標 {{value}} {{unit}}',\n trendLabel: '{{parameter}}の推移',\n trend: '推移',\n editable: '編集可能',\n editCell: '{{parameter}} — 最新の受診',\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 empty: {\n noVisits: {\n title: '受診記録がありません',\n description: '初回の受診を記録すると、値と推移がここに表示されます。',\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 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 showing: '{{total}}回中{{shown}}回を表示 · {{from}} – {{to}}',\n showingAll: 'すべての受診{{total}}回 · {{from}} – {{to}}',\n minimum: '受診は1件以上表示されます',\n addedByCompare: '比較により{{added}}回を追加',\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"],"names":["__iconNode","ArchiveRestore","createLucideIcon","Archive","SendHorizontal","SquarePen","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","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","computeBmi","weightKg","heightCm","kitComputeBmi","isReadableDate","iso","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","TEXT_FIELDS","roundTo","precision","factor","round","isConstant","values","same","a","sameMedication","compareVisitSpan","numeric","pathologies","unionInOrder","present","medications","id","entries","texts","field","read","seen","latestVisit","ABSENT_VALUE","formatValue","formatCalendarDate","locale","formatDelta","rounded","fieldVisible","sex","relevance","localeOf","lng","visitDateLabel","parseCalendarDate","y","m","toCalendarIso","date","pad","visitOptionLabel","hasNote","label","ageLabel","dateOfBirthIso","patientAgeLabel","reference","practiceLabel","trimmed","parameterLabel","parameterLabelWithUnit","intakeFieldLabel","intakeFieldLabelWithUnit","intakeFieldHelp","practice","sectionLabel","pathologyLabel","pathologyCodeWithLabel","isIntakeAnswered","answer","formatIntakeAnswer","yn","selectedLabel","opt","base","DIGEST_GROUPS","visibleFields","sections","itemFor","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","NOTE_FIELDS","visitNotes","text","hasVisitNotes","AnamnesisVisitNoteList","note","NOTE_SCROLL_CLASS","AnamnesisVisitNote","defaultOpen","onOpenNote","visitTypeLabel","dateLabel","triggerLabel","IconButton","NotebookPen","Popover","event","Timestamp","MATRIX_IDENTITY_CLASS","MATRIX_VISIT_COLUMN_CLASS","MATRIX_TREND_COLUMN_CLASS","IDENTITY_HEADER_CLASS","COLUMN_HEADER_CLASS","TRAILING_HEADER_CLASS","MATRIX_TRAILING_CELL_CLASS","MATRIX_CELL_CLASS","MatrixVisitHeader","column","emphasised","editable","defaultOpenNoteVisitId","withNote","AnamnesisMatrix","captionId","caption","identityLabel","trendLabel","trendTestId","visitHeaders","trailingLabel","trailingTestId","rows","framed","testId","columnCount","row","_b","NOTE_EXCERPT_MAX","CHANGE_VARIANT","spanKind","last","excerpt","ABSENT","describeTherapy","withName","dose","measurementRows","diff","seriesByKey","change","kind","pathologyRows","at","therapyRows","carried","renamed","noteRows","COMPARE_CATEGORIES","buildCompareRows","ctx","category","ChangeCell","AnamnesisComparePanel","columns","selectedIds","onSelectionChange","onClose","useId","refusalNote","setRefusalNote","options","useMemo","readout","shown","matrixRows","built","lastCategory","X","FormField","MultiSelect","next","Separator","EVENT_SHAPE","EVENT_TONE","eventPosition","spans","times","i","from","to","within","eventMarks","events","position","eventLabel","eventDetail","eventAnnotations","marks","activeIds","mark","AnamnesisEventBar","onToggle","labelId","detailId","active","pressed","AnnotationMarker","defaultSelectedVisitIds","latest","windowVisits","allVisitColumns","v","visitPickerIsUseful","UNMEASURED_CELL","deltaIsLegible","formatRange","AnamnesisEvolutionGrid","onCellChange","compare","visitColumns","capturableKeys","latestIndex","renderedRows","lastGroup","isComparedColumn","visitId","rangeText","valueCells","columnIndex","cell","isLatest","capturable","editableCell","deltaHidden","changed","NumberInput","AnamnesisEvolution","defaultCompareOpen","defaultVisitIds","defaultCompareVisitIds","defaultEventIds","onVisitSelectionChange","canCompare","comparePanelId","compareToggleId","compareOn","setCompareOn","comparePanelRef","compareToggleRef","compareMounted","closeCompare","pickedCompareIds","setPickedCompareIds","compareSelectedIds","compareColumns","map","pickedVisitIds","setPickedVisitIds","pickable","selectedVisitIds","visitWindow","shownVisitIds","visitOptions","windowReadout","parts","added","pickedEventIds","setPickedEventIds","activeEventIds","drawable","toggleEvent","eventId","selectAnnotation","compareForGrid","changedCells","against","on","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","site","cycle","yesNo","outOfRangeText","flagged","windowChange","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","_","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","n","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","prev","run","write","ok","handlePdf","handleXlsx","handleCsv","handlePrint","openShare","confirmShare","DropdownMenu","option","Share2","FileText","Printer","FileSpreadsheet","Download","AnamnesisShareDialog","open","onOpenChange","onAudienceChange","preview","onConfirm","Dialog","RadioGroup","Radio","DisclosureList","emptyText","timeToValue","time","h","valueToTime","DECIMAL_NUMBER_FIELDS","AnamnesisField","onChange","showOrigin","origin","readOnly","description","showMarker","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","x","anthroDefs","dietaryDefs","stripDefs","occasionalOpen","setOccasionalOpen","seed","state","setBlockOpen","historySections","liveSections","view","setView","gapsOpen","setGapsOpen","setShownVisitIds","trackShownVisits","ids","readAnswer","missingAnswers","gapKeys","jumpToMissing","CompileShell","Card","patchLatest","mut","r","onNumericChange","onGridCellChange","setTarget","setPathologies","codes","updateTherapy","patch","removeTherapy","addTherapy","addFollowUpVisit","updateIntakeAnswer","pathologyOptions","parent","latestOncological","latestAnnual","inner","Tabs","DatePicker","Plus","Trash2","seedAnswers","source","AnamnesisIntake","defaultOpenSection","onSubmit","jumpToField","referenceVisit","answers","setAnswers","seededFrom","setSeededFrom","submitted","setSubmitted","onFieldChange","visibleSections","openSection","setOpenSection","holder","answeredCount","totalCount","total","percentComplete","progressCaption","showMissing","Progress","Accordion","sectionAnswered","AccordionItem","AccordionTrigger","AccordionContent","ReadOnlyNumericList","AnamnesisReadOnly","ReadOnlyShell","oncological","AnamnesisQuestionnaire","canEdit","defaultTab","setTab","alreadyCompiled","editing","setEditing","working","setWorking","numericDefs","Anamnesis","mode","dataComponent","onIntakeSubmit","intakeJumpToField","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","adding","setAdding","patchParameters","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","checked","EditDialog","AddDialog","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"],"mappings":"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","x_google_ignoreList":[0,1,2,3]}
|
|
1
|
+
{"version":3,"file":"anamnesis-i18n-CfC0qYzy.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","../../node_modules/lucide-react/dist/esm/icons/square-pen.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-visit-note.tsx","../../src/patterns/anamnesis/anamnesis-matrix.tsx","../../src/patterns/anamnesis/anamnesis-compare-panel.tsx","../../src/patterns/anamnesis/anamnesis-events.ts","../../src/patterns/anamnesis/anamnesis-event-bar.tsx","../../src/patterns/anamnesis/anamnesis-window.ts","../../src/patterns/anamnesis/anamnesis-evolution-grid.tsx","../../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-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"],"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 * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\", key: \"1m0v6g\" }],\n [\n \"path\",\n {\n d: \"M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z\",\n key: \"ohrbg2\"\n }\n ]\n];\nconst SquarePen = createLucideIcon(\"square-pen\", __iconNode);\n\nexport { __iconNode, SquarePen as default };\n//# sourceMappingURL=square-pen.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 { key: 'refluxGastritis', type: 'yesNoDetail', detail: true },\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/** 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 const dob = new Date(dobIso);\n const ref = new Date(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\n/** Format a numeric value to its parameter precision, or an em dash when\n * absent. `0` formats as a value; a non-finite number is absent, because\n * `NaN.toFixed(1)` is the string \"NaN\" and that must never reach a cell.\n * Callers append the unit separately. */\nexport function formatValue(value: number | null, precision = 1): string {\n if (value == null || !Number.isFinite(value)) return ABSENT_VALUE;\n return value.toFixed(precision);\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/** Signed, precision-formatted delta string (e.g. \"+2.4\", \"−1.0\"). Uses a\n * real minus sign for the negative case. */\nexport function formatDelta(abs: number, precision = 1): 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}${Math.abs(rounded).toFixed(precision)}`;\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 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>`. Pins UTC AND the\n * app locale, so one visit cannot render two ways on one screen. */\nexport function visitDateLabel(iso: string, t: TFunction): string {\n return formatCalendarDate(iso, localeOf(t));\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. */\nexport function parseCalendarDate(iso: string): Date | undefined {\n const [y, m, d] = iso.split('-').map(Number);\n if (!y || !m || !d) return undefined;\n return new Date(y, m - 1, d);\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 label = t('anamnesis.compare.visitOption', {\n index: index + 1,\n visitType: t(`anamnesis.visitType.${visit.visitType}`),\n date: visitDateLabel(visit.dateIso, t),\n });\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 return answer.value != null ? String(answer.value) : '—';\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 { 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)}${\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. */\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 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 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 { CALENDAR_DATE_FORMAT, 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={CALENDAR_DATE_FORMAT}\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 { CALENDAR_DATE_FORMAT } from './anamnesis-derive';\nimport type { OpenAnamnesisNote } 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}\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}: MatrixVisitHeaderProps) {\n const { visit } = column;\n return (\n <th\n scope=\"col\"\n className={[\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 <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 <Timestamp\n value={visit.dateIso}\n format=\"absolute\"\n shape=\"bare\"\n absoluteFormat={CALENDAR_DATE_FORMAT}\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 <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 — compare panel (slot 4 of the evolution surface) */\n/* */\n/* \"Confronta\" reworked into ONE reading: tick the visits to compare and */\n/* read every difference in a single table with one grammar — added / */\n/* removed / changed — across every category. It replaces four ragged */\n/* lists whose shapes disagreed with each other. */\n/* */\n/* THE PANEL WEARS THE GRID'S SHAPE. It renders through the same */\n/* `AnamnesisMatrix` shell the evolution grid does, so the columns read */\n/* identity → first compared visit → trend → the rest, the sparklines are */\n/* the same `TrendSparkline` over the same full-record series, and the */\n/* event annotations drawn on the grid are drawn here too. The two reads */\n/* sit one under the other on screen; a second presentation of the same */\n/* record would be a second thing to learn. */\n/* */\n/* COLUMNS: identity → visits… → Change. The Change column is the NET */\n/* first→last change: the direction-aware delta for a numeric row, the */\n/* added/removed/changed word for a row that has no number. The old */\n/* before/after pair generalised into the visit columns, and the old */\n/* change-word column is gone — it named what the arrow already says. */\n/* */\n/* The category is a group banner, not a column, for the same reason the */\n/* grid banners its parameter groups: a value repeated down every row is a */\n/* heading wearing a column's clothes. */\n/* */\n/* story-only mock — do not promote */\n/* -------------------------------------------------------------------- */\n\nimport { useId, useMemo, useState } from 'react';\nimport type { TFunction } from 'i18next';\nimport { X } from 'lucide-react';\nimport { Badge } from '../../components/badge';\nimport { Button } from '../../components/button';\nimport { EmptyState } from '../../components/empty-state';\nimport { FormField } from '../../components/form-field';\nimport { MultiSelect } from '../../components/multi-select';\nimport type { SelectOption } from '../../components/select';\nimport { Separator } from '../../components/separator';\nimport type { SparklineAnnotation } from '../../components/sparkline';\nimport {\n ABSENT_VALUE as ABSENT,\n formatValue,\n type DeltaInfo,\n type SpanDiff,\n} from './anamnesis-derive';\nimport {\n parameterLabel,\n pathologyCodeWithLabel,\n visitDateLabel,\n visitOptionLabel,\n} from './anamnesis-format';\nimport { DeltaIndicator, TrendSparkline } from './anamnesis-indicators';\nimport {\n AnamnesisMatrix,\n MATRIX_CELL_CLASS,\n MATRIX_IDENTITY_CLASS,\n MATRIX_TRAILING_CELL_CLASS,\n MATRIX_TREND_COLUMN_CLASS,\n MATRIX_VISIT_COLUMN_CLASS,\n MatrixVisitHeader,\n type MatrixRowSpec,\n} from './anamnesis-matrix';\nimport type {\n MedicationEntry,\n NumericParameterDef,\n PathologyCode,\n Visit,\n} from './anamnesis-types';\nimport type { VisitColumn } from './anamnesis-window';\n\n/* ------------------------------ Row model ------------------------------- */\n\n/** A note is summarised, not reproduced: the full text is one click away in\n * the grid's visit-column note popover. */\nconst NOTE_EXCERPT_MAX = 160;\n\n/** The one grammar every category speaks. */\nexport type CompareChangeKind = 'added' | 'removed' | 'changed';\n\n/** Chip tone per change word. Matched by the sr-only text in every cell, so\n * the word is never carried by colour alone. */\nconst CHANGE_VARIANT: Record<CompareChangeKind, 'success' | 'error' | 'info'> =\n {\n added: 'success',\n removed: 'error',\n changed: 'info',\n };\n\n/** One line of the compare table. Every field is already display-ready, so\n * the renderer below never reaches back into the domain model. */\nexport interface CompareRow {\n /** Stable row id — `<category>:<subject>`. */\n id: string;\n /** Owning category's id (see `COMPARE_CATEGORIES`). */\n categoryId: string;\n /** What changed, in the clinician's words. */\n item: string;\n /** Second line under `item` — the unit and reference range, where there is\n * one. Numeric rows only; the grid puts the same thing in the same place. */\n meta?: string;\n change: CompareChangeKind;\n /** Translated change word — what the Change cell says when there is no\n * number to say it with. */\n changeLabel: string;\n /** One display string per compared visit, in the diff's (record) order. */\n values: string[];\n /** Numeric rows only: the FULL-RECORD series, so the sparkline here is the\n * same line as the grid's — not a shorter one drawn from the picked visits,\n * which would move every event annotation. */\n series?: (number | null)[];\n /** Numeric rows only: the net first→last change, direction-aware. */\n delta?: DeltaInfo | null;\n /** Numeric rows only: needed to colour the delta by valence. */\n def?: NumericParameterDef;\n}\n\nexport interface CompareRowContext {\n t: TFunction;\n pathologies: Record<string, PathologyCode>;\n /** Full-record sparkline series by parameter key. */\n seriesByKey: ReadonlyMap<string, (number | null)[]>;\n}\n\nexport interface CompareCategoryDef {\n /** Stable id; also the i18n leaf under `anamnesis.compare.category.*`. */\n id: string;\n /** Pull this category's rows out of one span diff. */\n rows: (diff: SpanDiff, ctx: CompareRowContext) => CompareRow[];\n}\n\n/* ---------------------------- Row builders ------------------------------ */\n\n/** The change word for a subject that is present at some compared visits and\n * absent at others. Read first→last, because that is the span the Change\n * column reports; a subject that came and went returns to `changed`, which is\n * true (it is not the same story across the span) and never a blank cell. */\nfunction spanKind(present: readonly boolean[]): CompareChangeKind {\n const first = present[0];\n const last = present[present.length - 1];\n if (!first && last) return 'added';\n if (first && !last) return 'removed';\n return 'changed';\n}\n\nfunction excerpt(text: string): string {\n const trimmed = text.trim();\n if (!trimmed) return ABSENT;\n return trimmed.length > NOTE_EXCERPT_MAX\n ? `${trimmed.slice(0, NOTE_EXCERPT_MAX).trimEnd()}…`\n : trimmed;\n}\n\n/** A therapy entry as one string. `withName` disambiguates an entry renamed\n * somewhere in the span, where the name is the thing that changed. */\nfunction describeTherapy(\n entry: MedicationEntry,\n withName: boolean,\n present: string,\n): string {\n const dose = entry.dose?.trim();\n if (withName) return dose ? `${entry.name} · ${dose}` : entry.name;\n return dose ? dose : present;\n}\n\nfunction measurementRows(\n diff: SpanDiff,\n { t, seriesByKey }: CompareRowContext,\n): CompareRow[] {\n return diff.numeric.map((change) => {\n // `== null` throughout: a measurement of 0 is a value, not an absence.\n const present = change.values.map((value) => value != null);\n const kind = spanKind(present);\n return {\n id: `measurement:${change.def.key}`,\n categoryId: 'measurement',\n item: parameterLabel(change.def, t),\n meta: change.def.unit ?? undefined,\n change: kind,\n changeLabel: t(`anamnesis.compare.${kind}`),\n // Bare numbers: the unit is stated once beside the parameter, exactly\n // as the grid states it, rather than repeated in every column.\n values: change.values.map((value) =>\n formatValue(value, change.def.precision),\n ),\n series: seriesByKey.get(change.def.key),\n delta: change.delta,\n def: change.def,\n };\n });\n}\n\nfunction pathologyRows(\n diff: SpanDiff,\n { t, pathologies }: CompareRowContext,\n): CompareRow[] {\n const present = t('anamnesis.compare.present');\n return diff.pathologies.map((change) => {\n const kind = spanKind(change.present);\n return {\n id: `pathology:${change.code}`,\n categoryId: 'pathology',\n item: pathologyCodeWithLabel(change.code, t, pathologies[change.code]),\n change: kind,\n changeLabel: t(`anamnesis.compare.${kind}`),\n values: change.present.map((at) => (at ? present : ABSENT)),\n };\n });\n}\n\nfunction therapyRows(diff: SpanDiff, { t }: CompareRowContext): CompareRow[] {\n const present = t('anamnesis.compare.present');\n return diff.medications.map((change) => {\n const carried = change.entries.filter(\n (entry): entry is MedicationEntry => entry != null,\n );\n // A rename is the change itself, so every cell has to carry the name for\n // the row to be readable at all.\n const renamed = new Set(carried.map((entry) => entry.name)).size > 1;\n const kind = spanKind(change.entries.map((entry) => entry != null));\n return {\n id: `therapy:${change.id}`,\n categoryId: 'therapy',\n // The most recent name the span holds — a renamed entry reads under\n // what it is called now, not under what it used to be called.\n item: carried[carried.length - 1]?.name ?? change.id,\n change: kind,\n changeLabel: t(`anamnesis.compare.${kind}`),\n values: change.entries.map((entry) =>\n entry ? describeTherapy(entry, renamed, present) : ABSENT,\n ),\n };\n });\n}\n\nfunction noteRows(diff: SpanDiff, { t }: CompareRowContext): CompareRow[] {\n return diff.texts.flatMap((change) => {\n const values = change.values.map(excerpt);\n // Two notes that differ only past the excerpt would render as one string\n // repeated across every column — a row that says nothing.\n if (values.every((value) => value === values[0])) return [];\n const kind = spanKind(values.map((value) => value !== ABSENT));\n return [\n {\n id: `note:${change.field}`,\n categoryId: 'note',\n item: t(`anamnesis.field.${change.field}.label`, {\n defaultValue: change.field,\n }),\n change: kind,\n changeLabel: t(`anamnesis.compare.${kind}`),\n values,\n },\n ];\n });\n}\n\n/* --------------------------- Category registry -------------------------- */\n\n/** One entry per `SpanDiff` array, in reading order. A future symptom or\n * event diff is ADDED here — the grammar, the columns and the renderer below\n * stay untouched. Adding a category is data, never a rewrite. */\nexport const COMPARE_CATEGORIES: readonly CompareCategoryDef[] = [\n { id: 'measurement', rows: measurementRows },\n { id: 'pathology', rows: pathologyRows },\n { id: 'therapy', rows: therapyRows },\n { id: 'note', rows: noteRows },\n];\n\n/** Every difference across the compared visits as one flat, ordered list.\n * Category order is the registry's order; within a category, the diff's own\n * order. Nothing is sorted here — the record's order is the reading order. */\nexport function buildCompareRows(\n diff: SpanDiff,\n ctx: CompareRowContext,\n): CompareRow[] {\n return COMPARE_CATEGORIES.flatMap((category) => category.rows(diff, ctx));\n}\n\n/* ------------------------------ Cell render ----------------------------- */\n\n/** The Change cell. A numeric row that has a number on both ends shows the\n * direction-aware delta; everything else — a pathology assigned, a therapy\n * stopped, a note written, a measurement that only exists at one end — shows\n * the change word, because there is no arithmetic to do. */\nfunction ChangeCell({ row, t }: { row: CompareRow; t: TFunction }) {\n if (row.def && row.delta) {\n return <DeltaIndicator delta={row.delta} def={row.def} t={t} />;\n }\n return (\n <Badge variant={CHANGE_VARIANT[row.change]} size=\"sm\">\n {row.changeLabel}\n </Badge>\n );\n}\n\n/* -------------------------------- Panel --------------------------------- */\n\nexport interface AnamnesisComparePanelProps {\n /** The record's visits, in record order — the picker's options. */\n visits: Visit[];\n /** The compared columns, resolved in RECORD order (never tick order). */\n columns: readonly VisitColumn[];\n /** Currently compared visit ids. */\n selectedIds: readonly string[];\n onSelectionChange: (ids: string[]) => void;\n /** The computed diff, or `null` when fewer than two visits are compared. */\n diff: SpanDiff | null;\n /** Full-record sparkline series by parameter key. */\n seriesByKey: ReadonlyMap<string, (number | null)[]>;\n pathologies: Record<string, PathologyCode>;\n /** The event lines drawn on the grid, so they are drawn here too. */\n annotations?: readonly SparklineAnnotation[];\n /** Make those lines pointer-selectable, exactly as they are on the grid.\n * The event bar above the grid stays the keyboard route for both. */\n onSelectAnnotation?: (eventId: string) => void;\n t: TFunction;\n /** Exit compare mode from inside the panel. The toggle that opened it is a\n * full grid above, so without this the only way out is off-screen. */\n onClose?: () => void;\n}\n\n/** Slot 4's contents: a header carrying the way out, the visit picker, then\n * one matrix of differences. The enclosing `Collapsible` lives in\n * `anamnesis-evolution.tsx`. */\nexport function AnamnesisComparePanel({\n visits,\n columns,\n selectedIds,\n onSelectionChange,\n diff,\n seriesByKey,\n pathologies,\n annotations,\n onSelectAnnotation,\n t,\n onClose,\n}: AnamnesisComparePanelProps) {\n const captionId = useId();\n const [refusalNote, setRefusalNote] = useState('');\n\n // Ordinals disambiguate two visits recorded on the same calendar day, which\n // would otherwise render two identical option labels.\n const options = useMemo<SelectOption[]>(\n () =>\n visits.map((visit, index) => ({\n value: visit.id,\n label: visitOptionLabel(visit, index, t),\n })),\n [visits, t],\n );\n\n const rows = useMemo(\n () => (diff ? buildCompareRows(diff, { t, pathologies, seriesByKey }) : []),\n [diff, t, pathologies, seriesByKey],\n );\n\n const readout = useMemo(() => {\n const first = columns[0]?.visit.dateIso;\n const last = columns[columns.length - 1]?.visit.dateIso;\n const shown = t('anamnesis.compare.selected', {\n total: columns.length,\n from: first ? visitDateLabel(first, t) : '',\n to: last ? visitDateLabel(last, t) : '',\n });\n // Said only where it applies: at two visits the next removal is the one\n // the picker refuses, and silence there reads as a broken control.\n return columns.length === 2\n ? `${shown} · ${t('anamnesis.compare.minimum')}`\n : shown;\n }, [columns, t]);\n\n const visitHeaders = useMemo(\n () =>\n columns.map((column) => (\n <MatrixVisitHeader\n key={column.key}\n column={column}\n t={t}\n emphasised\n // The same visit's note trigger is already in the grid column\n // directly above; a second one with the same accessible name is a\n // control the reader has to tell apart from itself.\n withNote={false}\n />\n )),\n [columns, t],\n );\n\n const matrixRows = useMemo<MatrixRowSpec[]>(() => {\n const built: MatrixRowSpec[] = [];\n let lastCategory: string | null = null;\n for (const row of rows) {\n if (row.categoryId !== lastCategory) {\n lastCategory = row.categoryId;\n built.push({\n key: `group-${row.categoryId}`,\n banner: t(`anamnesis.compare.category.${row.categoryId}`),\n });\n }\n built.push({\n key: row.id,\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:break-words ds:text-[color:var(--foreground)]\">\n {row.item}\n </span>\n {row.meta ? (\n <span className=\"type-meta ds:text-[color:var(--muted-foreground)]\">\n {row.meta}\n </span>\n ) : null}\n </div>\n </th>\n ),\n cells: row.values.map((value, index) => (\n <td\n key={columns[index]?.key ?? index}\n className={`${MATRIX_VISIT_COLUMN_CLASS} ${MATRIX_CELL_CLASS} ds:tabular-nums`}\n >\n <span className=\"type-body-sm ds:block ds:break-words ds:whitespace-normal ds:text-[color:var(--foreground)]\">\n {value}\n </span>\n </td>\n )),\n trend: (\n <td className={`${MATRIX_TREND_COLUMN_CLASS} ${MATRIX_CELL_CLASS}`}>\n {row.series && row.def ? (\n <TrendSparkline\n series={row.series}\n def={row.def}\n t={t}\n annotations={annotations}\n onSelectAnnotation={onSelectAnnotation}\n />\n ) : null}\n </td>\n ),\n trailing: (\n <td\n className={`${MATRIX_VISIT_COLUMN_CLASS} ${MATRIX_CELL_CLASS} ${MATRIX_TRAILING_CELL_CLASS}`}\n data-change={row.change}\n >\n <ChangeCell row={row} t={t} />\n </td>\n ),\n });\n }\n return built;\n }, [rows, columns, annotations, onSelectAnnotation, t]);\n\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n {/* The way out, at the top of what the toggle scrolled the reader to. A\n plain action, NOT a second state-owner: `aria-pressed` /\n `aria-expanded` stay on the toolbar toggle. */}\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-between ds:gap-[var(--spacing-md)]\">\n <h3 className=\"type-title-section ds:m-0 ds:text-[color:var(--foreground)]\">\n {t('anamnesis.compare.panelTitle')}\n </h3>\n {onClose ? (\n <Button\n intent=\"outline\"\n data-testid=\"anamnesis-compare-close\"\n startIcon={<X aria-hidden=\"true\" className=\"ds:size-5\" />}\n onClick={onClose}\n >\n {t('anamnesis.compare.stop')}\n </Button>\n ) : null}\n </div>\n\n <div\n data-testid=\"anamnesis-compare-picker\"\n className=\"ds:min-w-[18rem] ds:max-w-[32rem]\"\n >\n {/* No clear-all, and no floor of one: a comparison needs two visits,\n so an affordance whose effect is refused is worse than none. */}\n <FormField\n label={t('anamnesis.compare.visitsLabel')}\n description={readout}\n >\n <MultiSelect\n options={options}\n value={[...selectedIds]}\n allowSelectAll\n onChange={(next) => {\n if (next.length >= 2) {\n setRefusalNote('');\n onSelectionChange(next);\n return;\n }\n setRefusalNote(t('anamnesis.compare.minimum'));\n }}\n />\n </FormField>\n {/* The floor is enforced by REFUSING the change, and a description\n never re-read is no explanation at all for a screen reader. */}\n <span\n role=\"status\"\n data-testid=\"anamnesis-compare-floor\"\n className=\"ds:sr-only\"\n >\n {refusalNote}\n </span>\n </div>\n\n <Separator />\n\n <div\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n data-testid=\"anamnesis-compare-summary\"\n >\n {diff ? (\n <>\n {/* h4: the summary sits inside the panel whose header is the h3\n above, so the level increments rather than repeating. */}\n <h4 className=\"type-title-item ds:m-0 ds:text-[color:var(--foreground)]\">\n {t('anamnesis.compare.summaryTitle', {\n from: visitDateLabel(diff.visits[0].dateIso, t),\n to: visitDateLabel(\n diff.visits[diff.visits.length - 1].dateIso,\n t,\n ),\n })}\n </h4>\n {rows.length === 0 ? (\n <EmptyState\n variant=\"no-results\"\n size=\"sm\"\n title={t('anamnesis.compare.noChanges')}\n description={t('anamnesis.compare.noChangesDescription')}\n />\n ) : (\n <AnamnesisMatrix\n captionId={captionId}\n caption={t('anamnesis.compare.tableLabel')}\n identityLabel={t('anamnesis.compare.column.item')}\n trendLabel={t('anamnesis.grid.trend')}\n trailingLabel={t('anamnesis.compare.column.change')}\n trailingTestId=\"anamnesis-compare-change-column\"\n visitHeaders={visitHeaders}\n rows={matrixRows}\n testId=\"anamnesis-compare-table\"\n />\n )}\n </>\n ) : (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.compare.sameVisit')}\n </p>\n )}\n </div>\n </div>\n );\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 { 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 const times = visits.map((visit) => new Date(visit.dateIso).getTime());\n const at = new Date(event.dateIso).getTime();\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 — visit window (which visit columns are rendered) */\n/* */\n/* A multi-year history is a horizontal-scroll problem: thirteen visits */\n/* is thirteen columns nobody reads with a patient in the room. The */\n/* clinician therefore picks the columns EXPLICITLY, from a multi-select */\n/* listing every visit; the default picks the FIRST visit and the LATEST, */\n/* which answers the question actually asked with the patient present — */\n/* \"how far have we come\". */\n/* */\n/* Nothing stands in for an unpicked 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/* 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 /** Visit ids rendered on top of the selection — the compare anchors, so a\n * compared column is never one the picker left out. */\n alsoShowIds?: Iterable<string>;\n}\n\n/* --------------------------------- API ---------------------------------- */\n\n/** The selection the picker opens on: the first visit and the latest. On a\n * single-visit record the two collapse to one. */\nexport function defaultSelectedVisitIds(visits: readonly Visit[]): string[] {\n if (visits.length === 0) return [];\n const first = visits[0].id;\n const latest = visits[visits.length - 1].id;\n return first === latest ? [first] : [first, latest];\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 shown = new Set<string>(selectedIds);\n for (const id of options.alsoShowIds ?? []) 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 return {\n columns,\n shownCount: columns.length,\n totalCount: visits.length,\n hiddenCount: visits.length - columns.length,\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(\n visits,\n visits.map((v) => v.id),\n ).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 the */\n/* first visit and the LATEST. A delta is drawn only where the column before */\n/* it on screen IS the visit it was measured against. */\n/* -------------------------------------------------------------------- */\n\nimport { useId } from 'react';\nimport type { TFunction } from 'i18next';\nimport { NumberInput } from '../../components/number-input';\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 { 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\nfunction formatRange(\n range: NumericParameterDef['referenceRange'],\n t: TFunction,\n): string | null {\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/* -------------------------------- 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 onCellChange?: (\n visit: Visit,\n def: NumericParameterDef,\n value: number | null,\n ) => void;\n /** Compare mode: the visit ids under comparison (two or more) + the CELLS\n * that differ from the compared column before them, keyed\n * `<visitId>:<parameterKey>`. Per cell, never per parameter: at three or\n * more compared visits a column equal to its predecessor did not change. */\n compare?: {\n visitIds: ReadonlySet<string>;\n changedCells: ReadonlySet<string>;\n } | null;\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}\n\n/* ------------------------------- Component ------------------------------ */\n\nexport function AnamnesisEvolutionGrid({\n record,\n defs,\n t,\n editable = false,\n onCellChange,\n compare = null,\n framed = true,\n defaultOpenNoteVisitId,\n onOpenNote,\n visitColumns,\n capturableKeys,\n annotations,\n onSelectAnnotation,\n}: AnamnesisEvolutionGridProps) {\n const captionId = useId();\n const rows = buildParameterRows(record, defs);\n const visits = record.visits;\n const latestIndex = visits.length - 1;\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 const isComparedColumn = (visitId: string) =>\n compare?.visitIds.has(visitId) ?? false;\n\n rows.forEach((row: ParameterRow) => {\n if (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);\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 // Position, not id: a record carrying a duplicated visit id would\n // otherwise make two columns editable and write to the wrong one.\n const isLatest = index === latestIndex;\n const capturable =\n capturableKeys == null || capturableKeys.has(row.def.key);\n const editableCell =\n editable && isLatest && capturable && !row.def.computed;\n const deltaHidden = !deltaIsLegible(columns, columnIndex);\n const changed =\n compare != null &&\n compare.changedCells.has(`${visit.id}:${row.def.key}`);\n const emphasised = isComparedColumn(visit.id);\n return (\n <td\n key={column.key}\n data-changed={changed || undefined}\n className={[\n MATRIX_VISIT_COLUMN_CLASS,\n MATRIX_CELL_CLASS,\n 'ds:tabular-nums',\n emphasised ? 'ds:bg-[color:var(--muted)]/40' : '',\n // Changed cells carry a fill tint AND a non-colour inline-start\n // border bar so the change reads without relying on hue.\n changed\n ? 'ds:bg-[color:var(--info)]/10 ds:border-s-2 ds:border-[color:var(--info)]'\n : '',\n ]\n .filter(Boolean)\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)}\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 {changed ? (\n <span className=\"ds:sr-only\">\n {t('anamnesis.compare.changedCell')}\n </span>\n ) : null}\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),\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 emphasised={isComparedColumn(column.visit.id)}\n editable={editable && column.index === latestIndex}\n defaultOpenNoteVisitId={defaultOpenNoteVisitId}\n onOpenNote={onOpenNote}\n />\n ));\n\n return (\n <AnamnesisMatrix\n captionId={captionId}\n 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 — evolution section (grid + compare) */\n/* */\n/* The across-visits view, shared by compile mode (editable newest column) */\n/* and read-only mode (no edit affordances). */\n/* */\n/* FIXED VERTICAL ORDER — five slots, and nothing else may be inserted: */\n/* 0. Empty state — replaces slots 1–4 when the record has no visit */\n/* 1. Toolbar — one wrapping row: the visit multi-select and */\n/* its readout, then the Compare toggle */\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/* 4. Compare panel — closed by default, opened by the toolbar's */\n/* Compare toggle, closed by either that or its own */\n/* header exit (the toggle scrolls out of reach) */\n/* */\n/* The default state is therefore one table under one row of controls, */\n/* with every secondary surface folded away: a clinician with a patient in */\n/* front of them reads the grid without hunting. */\n/* -------------------------------------------------------------------- */\n\nimport { useEffect, useId, useMemo, useRef, useState } from 'react';\nimport type { TFunction } from 'i18next';\nimport { Button } from '../../components/button';\nimport { Collapsible, CollapsibleContent } from '../../components/collapsible';\nimport { EmptyState } from '../../components/empty-state';\nimport { FormField } from '../../components/form-field';\nimport { MultiSelect } from '../../components/multi-select';\nimport type { SelectOption } from '../../components/select';\nimport { AnamnesisComparePanel } from './anamnesis-compare-panel';\nimport {\n allParametersIncludingArchived,\n configuredParameters,\n pathologyLookup,\n type PracticeAnamnesisConfig,\n} from './anamnesis-config';\nimport { buildParameterRows, compareVisitSpan } from './anamnesis-derive';\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 defaultSelectedVisitIds,\n visitPickerIsUseful,\n windowVisits,\n} 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 /** Mount with the compare panel already open. Demo/story hook only —\n * Chromatic skips play functions, so a click-opened panel is never\n * snapshotted. */\n defaultCompareOpen?: boolean;\n /** Mount with this visit selection instead of first + latest. Demo/story\n * hook only, for the same Chromatic reason. */\n defaultVisitIds?: readonly string[];\n /** Mount the compare panel on this set of visits instead of first + latest.\n * Demo/story hook only, for the same Chromatic reason. */\n defaultCompareVisitIds?: 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 * The Diagnosis surface's one export control needs to know which visit\n * columns are on screen — the file must be the view that was asked for. */\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}\n\n/* ------------------------------- Component ------------------------------ */\n\nexport function AnamnesisEvolution({\n record,\n t,\n editable = false,\n onCellChange,\n framed = true,\n config,\n defaultCompareOpen = false,\n defaultVisitIds,\n defaultCompareVisitIds,\n defaultEventIds,\n onVisitSelectionChange,\n onOpenNote,\n}: AnamnesisEvolutionProps) {\n const { visits } = record;\n const canCompare = visits.length >= 2;\n const comparePanelId = useId();\n const compareToggleId = useId();\n\n // History surface: archived parameters stay, so a value recorded under a\n // since-archived parameter still renders.\n const defs = useMemo(() => allParametersIncludingArchived(config), [config]);\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 const pathologies = useMemo(() => pathologyLookup(config), [config]);\n\n const [compareOn, setCompareOn] = useState(defaultCompareOpen);\n const [refusalNote, setRefusalNote] = useState('');\n // The panel opens BELOW a full-height grid, so without this the toggle looks\n // like it did nothing. `start`, not `nearest`: the panel is taller than the\n // viewport, and `nearest` parks its header on the bottom edge.\n const comparePanelRef = useRef<HTMLDivElement>(null);\n const compareToggleRef = useRef<HTMLButtonElement>(null);\n // Skipped on mount so a `defaultCompareOpen` story never scrolls itself.\n const compareMounted = useRef(false);\n useEffect(() => {\n if (compareMounted.current && compareOn)\n comparePanelRef.current?.scrollIntoView({ block: 'start' });\n compareMounted.current = true;\n }, [compareOn]);\n // Leaving from inside the panel hands focus back to the toggle that owns the\n // state — which scrolls it into view, so the reader lands where they began.\n const closeCompare = () => {\n setCompareOn(false);\n compareToggleRef.current?.focus();\n };\n // First + latest by default — the same two visits the grid shows, so the\n // panel opens on the columns already on screen and every other visit is one\n // tick away. The same MultiSelect idiom as the grid's picker: two surfaces\n // reading the same record must not offer two different ways to choose it.\n const [pickedCompareIds, setPickedCompareIds] = useState<string[]>(() =>\n defaultCompareVisitIds\n ? [...defaultCompareVisitIds]\n : defaultSelectedVisitIds(visits),\n );\n\n // Falls back to the default whenever fewer than two picked visits are still\n // in the record — a host that swaps the record would otherwise leave dead\n // ids and a panel claiming there is nothing to compare. Same floor of two\n // the picker enforces on deselection.\n const compareSelectedIds = useMemo(() => {\n const live = pickedCompareIds.filter((id) =>\n visits.some((v) => v.id === id),\n );\n return live.length >= 2 ? live : defaultSelectedVisitIds(visits);\n }, [pickedCompareIds, visits]);\n\n // Compared columns are resolved in RECORD order, never tick order — a set\n // of ticked visits has no order of its own, and columns disagreeing with\n // the grid directly above them would be unreadable.\n const compareColumns = useMemo(\n () => windowVisits(visits, compareSelectedIds).columns,\n [visits, compareSelectedIds],\n );\n\n const diff = useMemo(() => {\n if (!compareOn) return null;\n return compareVisitSpan(\n compareColumns.map((column) => column.visit),\n defs,\n );\n }, [compareOn, compareColumns, defs]);\n\n // The grid's own series, by parameter key: the compare panel draws the SAME\n // full-record line the grid draws, so an event annotation lands on the same\n // x in both.\n const seriesByKey = useMemo(() => {\n const map = new Map<string, (number | null)[]>();\n for (const row of buildParameterRows(record, defs)) {\n map.set(row.def.key, row.series);\n }\n return map;\n }, [record, defs]);\n\n /* ---- Visit picker: which columns render (never which maths run) ---- */\n const [pickedVisitIds, setPickedVisitIds] = useState<string[]>(() =>\n defaultVisitIds ? [...defaultVisitIds] : defaultSelectedVisitIds(visits),\n );\n const pickable = visitPickerIsUseful(visits);\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 the default rather than to\n // nothing. Same floor the picker enforces on deselection.\n const selectedVisitIds = useMemo(() => {\n const live = pickedVisitIds.filter((id) => visits.some((v) => v.id === id));\n return live.length > 0 ? live : defaultSelectedVisitIds(visits);\n }, [pickedVisitIds, visits]);\n\n const visitWindow = useMemo(\n () =>\n windowVisits(visits, selectedVisitIds, {\n // A compared visit is always a column, so compare always marks its\n // columns in the grid — comparing a visit the picker left out brings\n // it back on screen rather than marking nothing.\n alsoShowIds: compareOn ? compareSelectedIds : [],\n }),\n [visits, selectedVisitIds, compareOn, compareSelectedIds],\n );\n\n // Reported, never owned: the host only mirrors what the grid draws. The\n // RENDERED window, not the picked set — compare adds its anchors as columns,\n // and an export that followed the picker alone would file two columns off a\n // screen showing four, with a change column spanning a different pair of\n // dates than the one being read.\n const shownVisitIds = useMemo(\n () => visitWindow.columns.map((column) => column.visit.id),\n [visitWindow],\n );\n useEffect(() => {\n onVisitSelectionChange?.(shownVisitIds);\n }, [shownVisitIds, onVisitSelectionChange]);\n\n const visitOptions = useMemo<SelectOption[]>(\n () =>\n visits.map((visit, index) => ({\n value: visit.id,\n label: visitOptionLabel(visit, index, t, hasVisitNotes(visit)),\n })),\n [visits, t],\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 const parts = [shown];\n // Compare force-adds its anchors as columns, so the count above can exceed\n // the picked set. Say where the extra columns came from rather than\n // leaving the picker's chip count contradicting the table.\n const added = visitWindow.shownCount - selectedVisitIds.length;\n if (added > 0) parts.push(t('anamnesis.window.addedByCompare', { added }));\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]);\n\n /* ---- Events: one shared x domain, one line per picked event ---- */\n // Positions come from the record's visit span, NOT from any row's point\n // count and NOT from the visit selection — the sparklines plot the whole\n // record, 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 // Marks CELLS, not parameters. A parameter that moved somewhere across the\n // span does not make every compared column of it a change: with three or\n // more visits a column identical to the one compared before it would\n // otherwise be tinted and announced \"Changed\" beside its own \"0\" delta.\n const compareForGrid = useMemo(() => {\n if (!diff) return null;\n const changedCells = new Set<string>();\n for (const change of diff.numeric) {\n change.values.forEach((value, at) => {\n const against = at === 0 ? change.values[1] : change.values[at - 1];\n if (value !== against)\n changedCells.add(`${diff.visits[at].id}:${change.def.key}`);\n });\n }\n return {\n visitIds: new Set(diff.visits.map((visit) => visit.id)),\n changedCells,\n };\n }, [diff]);\n\n /* ---- SLOT 0 — no visits: nothing to plot, nothing to compare ---- */\n if (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-md)]\">\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 {pickable || canCompare ? (\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 {pickable ? (\n <div\n data-testid=\"anamnesis-window-picker\"\n className=\"ds:min-w-[18rem] ds:max-w-[32rem] ds:grow\"\n >\n <FormField\n label={t('anamnesis.window.label')}\n description={windowReadout}\n >\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. */}\n <MultiSelect\n options={visitOptions}\n value={selectedVisitIds}\n allowSelectAll\n onChange={(next) => {\n if (next.length > 0) {\n setRefusalNote('');\n setPickedVisitIds(next);\n return;\n }\n setRefusalNote(t('anamnesis.window.minimum'));\n }}\n />\n </FormField>\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 {/* `pressed` = compare mode is on (the grid marks changed cells too);\n `expanded` = the panel below is open, and it also keeps the\n aria-controls target valid while the panel is unmounted. */}\n {canCompare ? (\n // The picker beside it is a FormField — label, control, then\n // description. A bare button in an `items-start` row top-aligns\n // with that LABEL and reads as floating above the control it acts\n // on, so reserve one label line above it. Sized from the same type\n // token as the real label, so it tracks the accessible theme's\n // larger type instead of a hardcoded offset.\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span aria-hidden=\"true\" className=\"type-label ds:invisible\">\n \n </span>\n <Button\n ref={compareToggleRef}\n id={compareToggleId}\n intent={compareOn ? 'primary' : 'outline'}\n data-testid=\"anamnesis-compare-toggle\"\n aria-pressed={compareOn}\n aria-expanded={compareOn}\n aria-controls={comparePanelId}\n onClick={() => setCompareOn((on) => !on)}\n >\n {compareOn\n ? t('anamnesis.compare.stop')\n : t('anamnesis.compare.start')}\n </Button>\n </div>\n ) : 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={record}\n defs={defs}\n t={t}\n editable={editable}\n onCellChange={onCellChange}\n compare={compareForGrid}\n framed={framed}\n visitColumns={visitWindow.columns}\n capturableKeys={capturableKeys}\n annotations={annotations}\n onSelectAnnotation={selectAnnotation}\n onOpenNote={onOpenNote}\n />\n\n {/* SLOT 4 — compare panel. Nothing else may be inserted at this position. */}\n {canCompare ? (\n <Collapsible open={compareOn} onOpenChange={setCompareOn}>\n <CollapsibleContent\n ref={comparePanelRef}\n id={comparePanelId}\n aria-labelledby={compareToggleId}\n data-testid=\"anamnesis-compare-panel\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n <AnamnesisComparePanel\n visits={visits}\n columns={compareColumns}\n selectedIds={compareSelectedIds}\n onSelectionChange={setPickedCompareIds}\n diff={diff}\n seriesByKey={seriesByKey}\n pathologies={pathologies}\n annotations={annotations}\n onSelectAnnotation={selectAnnotation}\n t={t}\n onClose={closeCompare}\n />\n </CollapsibleContent>\n </Collapsible>\n ) : (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('anamnesis.compare.needTwoVisits')}\n </p>\n )}\n </div>\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 — 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 (unit carried in the FormField 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 { 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 { intakeFieldHelp, intakeFieldLabelWithUnit } from './anamnesis-format';\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/** Number fields captured to one decimal place vs whole numbers. */\nconst DECIMAL_NUMBER_FIELDS = new Set(['weightSelf', 'waterPerDay']);\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 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 t,\n}: AnamnesisFieldProps) {\n const label = intakeFieldLabelWithUnit(def, t);\n const description = intakeFieldHelp(def, t);\n const showMarker = showOrigin && origin === 'patient';\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 label={label} description={description}>\n <TextInput\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 label={label} description={description}>\n <TextArea\n disabled={readOnly}\n value={value}\n autoResize\n minRows={2}\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 label={label} description={description}>\n <NumberInput\n disabled={readOnly}\n value={value}\n min={0}\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 label={label} description={description}>\n <NumberInput\n disabled={readOnly}\n value={perWeek}\n min={0}\n max={21}\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 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 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 {def.detail && present === 'yes' ? (\n <FormField label={t('anamnesis.common.details')}>\n <TextInput\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 ) : 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 label={label} description={description}>\n <Select\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 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:text-[color:var(--foreground)]\">\n {label}\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:text-[color:var(--foreground)]\">\n {label}\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 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 className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\"\n >\n {showMarker ? (\n <div className=\"ds:flex ds:justify-end\">\n <OriginMarker t={t} />\n </div>\n ) : null}\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 { 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. Unit symbols are\n * locale-invariant scientific notation, as everywhere else in this pattern. */\nfunction withUnit(value: number, def: NumericParameterDef): string {\n const text = formatValue(value, def.precision);\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 // 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),\n band: tUi(`bmiCalculator.category.${bmiCategory(now)}`),\n })\n : t('anamnesis.targets.now', { value: withUnit(now, def) });\n\n return (\n <TargetTile\n variant=\"elevated\"\n label={label}\n target={\n target == null ? t('anamnesis.targets.unset') : withUnit(target, def)\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 } 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 fieldVisible,\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 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),\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)} ${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 /** 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 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. Bails on an identical set — the child reports on every mount\n // and a fresh array each time would otherwise re-render this surface.\n const [shownVisitIds, setShownVisitIds] = useState<string[]>([]);\n const trackShownVisits = useCallback((ids: readonly string[]) => {\n setShownVisitIds((prev) =>\n prev.length === ids.length && prev.every((id, i) => id === ids[i])\n ? prev\n : [...ids],\n );\n }, []);\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. */}\n <DatePicker\n value={parseCalendarDate(latest.dateIso)}\n onChange={(next) =>\n next &&\n patchLatest((v) => ({\n ...v,\n dateIso: toCalendarIso(next),\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 />\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 { CALENDAR_DATE_FORMAT, latestVisit } 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 { AnamnesisRecord, IntakeAnswer } from './anamnesis-types';\n\n/* ------------------------------- Helpers -------------------------------- */\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 // Re-seed when the host swaps the record (see the same guard in\n // AnamnesisQuestionnaire). Without it, a host that refreshes in place rather\n // than reloading the page keeps showing the PREVIOUS questionnaire's\n // answers — a freshly created interview would arrive already full.\n const [seededFrom, setSeededFrom] = useState(record);\n if (record !== seededFrom) {\n setSeededFrom(record);\n setAnswers(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.\n const [openSection, setOpenSection] = useState<string>(\n () => defaultOpenSection ?? visibleSections[0]?.key ?? '',\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 setOpenSection(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 setOpenSection(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 absoluteFormat={CALENDAR_DATE_FORMAT}\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}>\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=\"single\"\n collapsible\n variant=\"default\"\n value={openSection}\n onValueChange={setOpenSection}\n >\n {visibleSections.map((section) => {\n const sectionAnswered = section.fields.filter((f) =>\n isIntakeAnswered(answers[f.key]),\n ).length;\n return (\n <AccordionItem key={section.key} value={section.key}>\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 <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]\">\n {section.fields.map((field) => (\n <AnamnesisField\n readOnly={readOnly}\n key={field.key}\n def={field}\n answer={answers[field.key]}\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 + comparison stay available. Not a screenshot */\n/* of compile mode with disabled inputs — a 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 CALENDAR_DATE_FORMAT,\n deltaInfo,\n formatValue,\n outOfRange,\n parameterValueAt,\n} from './anamnesis-derive';\nimport { AnamnesisEvolution } from './anamnesis-evolution';\nimport {\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 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)}\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),\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}\n\n/* ------------------------------- Component ------------------------------ */\n\nexport function AnamnesisReadOnly({\n record,\n t,\n embedded = false,\n config,\n onOpenNote,\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\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={CALENDAR_DATE_FORMAT}\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 + comparison */}\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 />\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 tabs, because those are the only two things this surface does: */\n/* answer/read the questionnaire, and compare its numbers over time. The */\n/* compile mode's eleven bespoke blocks are deliberately absent. */\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 { SquarePen } from 'lucide-react';\nimport { Tabs } from '../../components/tabs';\nimport { AnamnesisIntake, type IntakeAnswerMap } from './anamnesis-intake';\nimport { AnamnesisEvolution } from './anamnesis-evolution';\nimport { Badge } from '../../components/badge';\nimport { Button } from '../../components/button';\nimport { EmptyState } from '../../components/empty-state';\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 /** The reader may not change answers at all (no write grant). The Edit\n * affordance is then absent, not merely disabled — an action a user can\n * never complete should not be offered. */\n canEdit?: boolean;\n /** Mount on this tab instead of the questionnaire. Demo/story hook only —\n * Chromatic skips play functions, so a click-selected tab is never\n * snapshotted. */\n defaultTab?: AnamnesisQuestionnaireTab;\n}\n\nexport type AnamnesisQuestionnaireTab = 'questionnaire' | 'trend';\n\nexport function AnamnesisQuestionnaire({\n record,\n t,\n config,\n onSubmit,\n jumpToField,\n statusSlot,\n onTargetChange,\n hideTargetStrip = false,\n canEdit = true,\n defaultTab = 'questionnaire',\n}: AnamnesisQuestionnaireProps) {\n const [tab, setTab] = useState<AnamnesisQuestionnaireTab>(defaultTab);\n // An ALREADY-COMPILED questionnaire opens READ-ONLY, exactly as the legacy\n // pane did: the reader sees at a glance that it has been answered, and has\n // to ask before overwriting the patient's own words. A blank one opens\n // ready to answer, because there is nothing to protect.\n const alreadyCompiled = record.intake?.submittedAtIso != null;\n const [editing, setEditing] = useState(!alreadyCompiled);\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 and edit state. 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 // A record with answers arrives protected; a blank one arrives ready to\n // answer. Same rule as the first mount.\n setEditing(record.intake?.submittedAtIso == null);\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\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 || 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\n value={tab}\n onValueChange={(next) => setTab(next as AnamnesisQuestionnaireTab)}\n >\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 <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 <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]\">\n {statusSlot}\n {alreadyCompiled && !editing ? (\n <Badge variant=\"neutral\">\n {t('anamnesis.questionnaire.compiled')}\n </Badge>\n ) : null}\n {canEdit && !editing ? (\n <Button\n intent=\"outline\"\n size=\"sm\"\n startIcon={<SquarePen aria-hidden=\"true\" />}\n data-testid=\"anamnesis-questionnaire-edit\"\n onClick={() => {\n setEditing(true);\n setTab('questionnaire');\n }}\n >\n {t('anamnesis.questionnaire.edit')}\n </Button>\n ) : null}\n </div>\n </div>\n\n <Tabs.Content value=\"questionnaire\">\n {/* `embedded` unconditionally: the questionnaire sits inside this\n card's tab panel, so its own page chrome would double the\n heading the tab already provides. */}\n <AnamnesisIntake\n record={working}\n t={t}\n embedded\n config={config}\n readOnly={!editing}\n onSubmit={(answers) => {\n // Saving closes the edit session: back to the protected\n // read of what is now on record.\n setEditing(false);\n onSubmit?.(answers);\n }}\n jumpToField={jumpToField}\n />\n </Tabs.Content>\n\n <Tabs.Content value=\"trend\">\n {numericDefs.length === 0 ? (\n <EmptyState\n variant=\"no-results\"\n title={t('anamnesis.questionnaire.noNumeric.title')}\n description={t('anamnesis.questionnaire.noNumeric.description')}\n />\n ) : (\n /* Read-only: values are answered in the questionnaire, never\n typed into the grid — one place to answer a question. */\n <AnamnesisEvolution\n record={working}\n t={t}\n config={config}\n framed={false}\n />\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 { AnamnesisQuestionnaireTab } from './anamnesis-questionnaire';\nimport type {\n AnamnesisMode,\n AnamnesisRecord,\n OpenAnamnesisNote,\n PractitionerOption,\n} from './anamnesis-types';\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 /** 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: the reader may not change answers at all. The\n * Edit affordance is then absent rather than disabled. Default true. */\n canEdit?: boolean;\n /** Questionnaire mode only: mount on this tab instead of the questionnaire.\n * Demo/story hook only — 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 onMissingAnswerJump,\n onRecordChange,\n canEdit,\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 />\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 canEdit={canEdit}\n defaultTab={defaultQuestionnaireTab}\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 />\n ) : (\n <AnamnesisReadOnly\n record={record}\n t={t}\n embedded={embedded}\n config={config}\n onOpenNote={onOpenNote}\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: { intake: 'Intake', compile: 'Compile', readOnly: 'Read-only' },\n common: {\n yes: 'Yes',\n no: 'No',\n unknown: 'Unknown',\n notSure: 'Not sure',\n choose: 'Choose…',\n details: 'Details',\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 // `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 start: 'Compare',\n stop: 'Stop comparing',\n panelTitle: 'Compare visits',\n needTwoVisits: 'Two or more visits are needed to compare.',\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 changedCell: 'Changed',\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 target: 'Target {{value}} {{unit}}',\n trendLabel: '{{parameter}} trend',\n trend: 'Trend',\n editable: 'Editable',\n editCell: '{{parameter}} — latest visit',\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 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 compiled: 'Compiled',\n edit: 'Edit',\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 },\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 },\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 showing: 'Showing {{shown}} of {{total}} visits · {{from}} – {{to}}',\n showingAll: 'All {{total}} visits · {{from}} – {{to}}',\n minimum: 'At least one visit stays shown',\n // `added` / `label`, never `count`: a plural-suffixed key would need six\n // forms in Arabic to say a number the sentence already carries.\n addedByCompare: '{{added}} added by Compare',\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 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 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 selected: '{{total}} visite confrontate · {{from}} – {{to}}',\n minimum: 'Restano confrontate almeno due visite',\n start: 'Confronta',\n stop: 'Interrompi confronto',\n panelTitle: 'Confronta le visite',\n needTwoVisits: 'Servono due o più visite per confrontare.',\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 changedCell: 'Modificato',\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 target: 'Obiettivo {{value}} {{unit}}',\n trendLabel: 'Andamento {{parameter}}',\n trend: 'Andamento',\n editable: 'Modificabile',\n editCell: '{{parameter}} — ultima visita',\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 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 compiled: 'Compilata',\n edit: 'Modifica',\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 },\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 },\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 // 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 addedByCompare: '{{added}} aggiunte dal confronto',\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: { intake: 'الاستجواب', compile: 'التجميع', readOnly: 'للقراءة فقط' },\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 selected: 'مقارنة {{total}} زيارة · {{from}} – {{to}}',\n minimum: 'تبقى زيارتان على الأقل قيد المقارنة',\n start: 'قارن',\n stop: 'إيقاف المقارنة',\n panelTitle: 'مقارنة الزيارات',\n needTwoVisits: 'يلزم زيارتان أو أكثر للمقارنة.',\n sameVisit: 'اختر زيارتين مختلفتين أو أكثر لعرض التغيّرات.',\n summaryTitle: 'التغيّرات من {{from}} إلى {{to}}',\n tableLabel: 'ما الذي تغيّر بين الزيارات المقارَنة',\n noChanges: 'لا توجد تغيّرات بين هذه الزيارات.',\n noChangesDescription:\n 'سُجِّلت في كل الزيارات القيم والرموز والعلاجات والملاحظات نفسها.',\n present: 'موجود',\n added: 'أُضيف',\n removed: 'أُزيل',\n changed: 'تغيّر',\n changedCell: 'تغيّر',\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 target: 'الهدف {{value}} {{unit}}',\n trendLabel: 'اتجاه {{parameter}}',\n trend: 'الاتجاه',\n editable: 'قابل للتعديل',\n editCell: '{{parameter}} — آخر زيارة',\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 empty: {\n noVisits: {\n title: 'لا توجد زيارات بعد',\n description: 'بعد تسجيل الزيارة الأولى تظهر القيم والاتجاهات هنا.',\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 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 showing: 'عرض {{shown}} من {{total}} زيارة · {{from}} – {{to}}',\n showingAll: 'كل الزيارات {{total}} · {{from}} – {{to}}',\n minimum: 'تبقى زيارة واحدة معروضة على الأقل',\n addedByCompare: 'أضافت المقارنة {{added}}',\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: { intake: '問診', compile: '記入', readOnly: '閲覧のみ' },\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 selected: '{{total}}回の受診を比較 · {{from}} – {{to}}',\n minimum: '受診は2件以上比較されます',\n start: '比較',\n stop: '比較を終了',\n panelTitle: '受診を比較',\n needTwoVisits: '比較には2回以上の受診が必要です。',\n sameVisit: '異なる2回以上の受診を選択してください。',\n summaryTitle: '{{from}}から{{to}}への変化',\n tableLabel: '比較した受診の間に変わったこと',\n noChanges: 'これらの受診の間に変化はありません。',\n noChangesDescription:\n 'いずれの受診でも同じ測定値・コード・処方・メモが記録されています。',\n present: 'あり',\n added: '追加',\n removed: '削除',\n changed: '変更',\n changedCell: '変更',\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 target: '目標 {{value}} {{unit}}',\n trendLabel: '{{parameter}}の推移',\n trend: '推移',\n editable: '編集可能',\n editCell: '{{parameter}} — 最新の受診',\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 empty: {\n noVisits: {\n title: '受診記録がありません',\n description: '初回の受診を記録すると、値と推移がここに表示されます。',\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 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 showing: '{{total}}回中{{shown}}回を表示 · {{from}} – {{to}}',\n showingAll: 'すべての受診{{total}}回 · {{from}} – {{to}}',\n minimum: '受診は1件以上表示されます',\n addedByCompare: '比較により{{added}}回を追加',\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"],"names":["__iconNode","ArchiveRestore","createLucideIcon","Archive","SendHorizontal","SquarePen","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","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","computeBmi","weightKg","heightCm","kitComputeBmi","isReadableDate","iso","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","TEXT_FIELDS","roundTo","precision","factor","round","isConstant","values","same","a","sameMedication","compareVisitSpan","numeric","pathologies","unionInOrder","present","medications","id","entries","texts","field","read","seen","latestVisit","ABSENT_VALUE","formatValue","formatCalendarDate","locale","formatDelta","rounded","fieldVisible","sex","relevance","localeOf","lng","visitDateLabel","parseCalendarDate","y","m","toCalendarIso","date","pad","visitOptionLabel","hasNote","label","ageLabel","dateOfBirthIso","patientAgeLabel","reference","practiceLabel","trimmed","parameterLabel","parameterLabelWithUnit","intakeFieldLabel","intakeFieldLabelWithUnit","intakeFieldHelp","practice","sectionLabel","pathologyLabel","pathologyCodeWithLabel","isIntakeAnswered","answer","formatIntakeAnswer","yn","selectedLabel","opt","base","DIGEST_GROUPS","visibleFields","sections","itemFor","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","NOTE_FIELDS","visitNotes","text","hasVisitNotes","AnamnesisVisitNoteList","note","NOTE_SCROLL_CLASS","AnamnesisVisitNote","defaultOpen","onOpenNote","visitTypeLabel","dateLabel","triggerLabel","IconButton","NotebookPen","Popover","event","Timestamp","MATRIX_IDENTITY_CLASS","MATRIX_VISIT_COLUMN_CLASS","MATRIX_TREND_COLUMN_CLASS","IDENTITY_HEADER_CLASS","COLUMN_HEADER_CLASS","TRAILING_HEADER_CLASS","MATRIX_TRAILING_CELL_CLASS","MATRIX_CELL_CLASS","MatrixVisitHeader","column","emphasised","editable","defaultOpenNoteVisitId","withNote","AnamnesisMatrix","captionId","caption","identityLabel","trendLabel","trendTestId","visitHeaders","trailingLabel","trailingTestId","rows","framed","testId","columnCount","row","_b","NOTE_EXCERPT_MAX","CHANGE_VARIANT","spanKind","last","excerpt","ABSENT","describeTherapy","withName","dose","measurementRows","diff","seriesByKey","change","kind","pathologyRows","at","therapyRows","carried","renamed","noteRows","COMPARE_CATEGORIES","buildCompareRows","ctx","category","ChangeCell","AnamnesisComparePanel","columns","selectedIds","onSelectionChange","onClose","useId","refusalNote","setRefusalNote","options","useMemo","readout","shown","matrixRows","built","lastCategory","X","FormField","MultiSelect","next","Separator","EVENT_SHAPE","EVENT_TONE","eventPosition","spans","times","i","from","to","within","eventMarks","events","position","eventLabel","eventDetail","eventAnnotations","marks","activeIds","mark","AnamnesisEventBar","onToggle","labelId","detailId","active","pressed","AnnotationMarker","defaultSelectedVisitIds","latest","windowVisits","allVisitColumns","v","visitPickerIsUseful","UNMEASURED_CELL","deltaIsLegible","formatRange","AnamnesisEvolutionGrid","onCellChange","compare","visitColumns","capturableKeys","latestIndex","renderedRows","lastGroup","isComparedColumn","visitId","rangeText","valueCells","columnIndex","cell","isLatest","capturable","editableCell","deltaHidden","changed","NumberInput","AnamnesisEvolution","defaultCompareOpen","defaultVisitIds","defaultCompareVisitIds","defaultEventIds","onVisitSelectionChange","canCompare","comparePanelId","compareToggleId","compareOn","setCompareOn","comparePanelRef","compareToggleRef","compareMounted","closeCompare","pickedCompareIds","setPickedCompareIds","compareSelectedIds","compareColumns","map","pickedVisitIds","setPickedVisitIds","pickable","selectedVisitIds","visitWindow","shownVisitIds","visitOptions","windowReadout","parts","added","pickedEventIds","setPickedEventIds","activeEventIds","drawable","toggleEvent","eventId","selectAnnotation","compareForGrid","changedCells","against","on","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","site","cycle","yesNo","outOfRangeText","flagged","windowChange","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","_","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","n","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","prev","run","write","ok","handlePdf","handleXlsx","handleCsv","handlePrint","openShare","confirmShare","DropdownMenu","option","Share2","FileText","Printer","FileSpreadsheet","Download","AnamnesisShareDialog","open","onOpenChange","onAudienceChange","preview","onConfirm","Dialog","RadioGroup","Radio","DisclosureList","emptyText","timeToValue","time","h","valueToTime","DECIMAL_NUMBER_FIELDS","AnamnesisField","onChange","showOrigin","origin","readOnly","description","showMarker","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","x","anthroDefs","dietaryDefs","stripDefs","occasionalOpen","setOccasionalOpen","seed","state","setBlockOpen","historySections","liveSections","view","setView","gapsOpen","setGapsOpen","setShownVisitIds","trackShownVisits","ids","readAnswer","missingAnswers","gapKeys","jumpToMissing","CompileShell","Card","patchLatest","mut","r","onNumericChange","onGridCellChange","setTarget","setPathologies","codes","updateTherapy","patch","removeTherapy","addTherapy","addFollowUpVisit","updateIntakeAnswer","pathologyOptions","parent","latestOncological","latestAnnual","inner","Tabs","DatePicker","Plus","Trash2","seedAnswers","source","AnamnesisIntake","defaultOpenSection","onSubmit","jumpToField","referenceVisit","answers","setAnswers","seededFrom","setSeededFrom","submitted","setSubmitted","onFieldChange","visibleSections","openSection","setOpenSection","holder","answeredCount","totalCount","total","percentComplete","progressCaption","showMissing","Progress","Accordion","sectionAnswered","AccordionItem","AccordionTrigger","AccordionContent","ReadOnlyNumericList","AnamnesisReadOnly","ReadOnlyShell","oncological","AnamnesisQuestionnaire","canEdit","defaultTab","setTab","alreadyCompiled","editing","setEditing","working","setWorking","numericDefs","Anamnesis","mode","dataComponent","onIntakeSubmit","intakeJumpToField","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","adding","setAdding","patchParameters","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","checked","EditDialog","AddDialog","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"],"mappings":"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","x_google_ignoreList":[0,1,2,3]}
|