@alfadocs/ui-kit-debug 1.12.5 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/{actions-cell-renderer-DnSLrgQD.js → actions-cell-renderer-ReurEy5i.js} +2 -2
- package/dist/_chunks/{actions-cell-renderer-DnSLrgQD.js.map → actions-cell-renderer-ReurEy5i.js.map} +1 -1
- package/dist/_chunks/{address-fields-CZP4Wncx.js → address-fields-CZ0pEdEI.js} +4 -4
- package/dist/_chunks/{address-fields-CZP4Wncx.js.map → address-fields-CZ0pEdEI.js.map} +1 -1
- package/dist/_chunks/{ai-prompt-input-DnbfEJnr.js → ai-prompt-input-CrHr-5H8.js} +2 -2
- package/dist/_chunks/{ai-prompt-input-DnbfEJnr.js.map → ai-prompt-input-CrHr-5H8.js.map} +1 -1
- package/dist/_chunks/{anamnesis-summary-rows-BfhxWPO3.js → anamnesis-summary-rows-CRWO8x8g.js} +4 -4
- package/dist/_chunks/{anamnesis-summary-rows-BfhxWPO3.js.map → anamnesis-summary-rows-CRWO8x8g.js.map} +1 -1
- package/dist/_chunks/{audio-recorder-EWBCNIsd.js → audio-recorder-DXG6LTtO.js} +2 -2
- package/dist/_chunks/{audio-recorder-EWBCNIsd.js.map → audio-recorder-DXG6LTtO.js.map} +1 -1
- package/dist/_chunks/{autocomplete-BrONKN8l.js → autocomplete-MpBhz-fG.js} +86 -74
- package/dist/_chunks/{autocomplete-BrONKN8l.js.map → autocomplete-MpBhz-fG.js.map} +1 -1
- package/dist/_chunks/{balance-badge-cell-7L6nzB29.js → balance-badge-cell--iQ_gtmi.js} +4 -4
- package/dist/_chunks/{balance-badge-cell-7L6nzB29.js.map → balance-badge-cell--iQ_gtmi.js.map} +1 -1
- package/dist/_chunks/{bishop-score-Cnu0xs-z.js → bishop-score-CJUVBfAu.js} +2 -2
- package/dist/_chunks/{bishop-score-Cnu0xs-z.js.map → bishop-score-CJUVBfAu.js.map} +1 -1
- package/dist/_chunks/{booking-CBHKdsZl.js → booking-DQbo6mQF.js} +609 -591
- package/dist/_chunks/booking-DQbo6mQF.js.map +1 -0
- package/dist/_chunks/{care-plan-card-aDN4oem9.js → care-plan-card-D-FMfDKH.js} +2 -2
- package/dist/_chunks/{care-plan-card-aDN4oem9.js.map → care-plan-card-D-FMfDKH.js.map} +1 -1
- package/dist/_chunks/{care-plan-entry-card-BEhANdBE.js → care-plan-entry-card-Bvw_9T-d.js} +2 -2
- package/dist/_chunks/{care-plan-entry-card-BEhANdBE.js.map → care-plan-entry-card-Bvw_9T-d.js.map} +1 -1
- package/dist/_chunks/{care-plan-header-CkpPyQqG.js → care-plan-header-B5CBE0zu.js} +2 -2
- package/dist/_chunks/{care-plan-header-CkpPyQqG.js.map → care-plan-header-B5CBE0zu.js.map} +1 -1
- package/dist/_chunks/{city-input-towzBenY.js → city-input-DaQc-Hbj.js} +2 -2
- package/dist/_chunks/{city-input-towzBenY.js.map → city-input-DaQc-Hbj.js.map} +1 -1
- package/dist/_chunks/{combobox-DiMLItyu.js → combobox-D7_NLE2Z.js} +89 -81
- package/dist/_chunks/{combobox-DiMLItyu.js.map → combobox-D7_NLE2Z.js.map} +1 -1
- package/dist/_chunks/{contact-profile-card-BMIBr5s9.js → contact-profile-card-BZqi8Hck.js} +38 -36
- package/dist/_chunks/{contact-profile-card-BMIBr5s9.js.map → contact-profile-card-BZqi8Hck.js.map} +1 -1
- package/dist/_chunks/{country-select-UEF9BEeQ.js → country-select-DzbPFktV.js} +2 -2
- package/dist/_chunks/{country-select-UEF9BEeQ.js.map → country-select-DzbPFktV.js.map} +1 -1
- package/dist/_chunks/{document-preview-oyx9RhCo.js → document-preview-CDb-n_W7.js} +2 -2
- package/dist/_chunks/{document-preview-oyx9RhCo.js.map → document-preview-CDb-n_W7.js.map} +1 -1
- package/dist/_chunks/{face-scheme-CZaKm6fG.js → face-scheme-DA2vjqaM.js} +2 -2
- package/dist/_chunks/{face-scheme-CZaKm6fG.js.map → face-scheme-DA2vjqaM.js.map} +1 -1
- package/dist/_chunks/{file-manager-C0y7HBAN.js → file-manager-UsD8e_AB.js} +2 -2
- package/dist/_chunks/{file-manager-C0y7HBAN.js.map → file-manager-UsD8e_AB.js.map} +1 -1
- package/dist/_chunks/{gestational-age-calculator-CxZelpu2.js → gestational-age-calculator-CiOQjzgx.js} +2 -2
- package/dist/_chunks/{gestational-age-calculator-CxZelpu2.js.map → gestational-age-calculator-CiOQjzgx.js.map} +1 -1
- package/dist/_chunks/key-value-pair-BIBdZBLg.js +188 -0
- package/dist/_chunks/key-value-pair-BIBdZBLg.js.map +1 -0
- package/dist/_chunks/{link-cell-renderer-CenJx-_7.js → link-cell-renderer-CIASXsVM.js} +4 -4
- package/dist/_chunks/{link-cell-renderer-CenJx-_7.js.map → link-cell-renderer-CIASXsVM.js.map} +1 -1
- package/dist/_chunks/{multi-select-DqL4o0qV.js → multi-select-DYOvx2SJ.js} +56 -48
- package/dist/_chunks/{multi-select-DqL4o0qV.js.map → multi-select-DYOvx2SJ.js.map} +1 -1
- package/dist/_chunks/{muscle-scheme-yfzP_xoJ.js → muscle-scheme-BSJsI4-I.js} +2 -2
- package/dist/_chunks/{muscle-scheme-yfzP_xoJ.js.map → muscle-scheme-BSJsI4-I.js.map} +1 -1
- package/dist/_chunks/{optical-prescription-Dj3Eh5Ok.js → optical-prescription-BvwuqTpl.js} +2 -2
- package/dist/_chunks/{optical-prescription-Dj3Eh5Ok.js.map → optical-prescription-BvwuqTpl.js.map} +1 -1
- package/dist/_chunks/{patient-details-xrqe13az.js → patient-details-BQaUzPqp.js} +5 -5
- package/dist/_chunks/{patient-details-xrqe13az.js.map → patient-details-BQaUzPqp.js.map} +1 -1
- package/dist/_chunks/{patient-search-D5ufYoRc.js → patient-search-HeEUB-_X.js} +2 -2
- package/dist/_chunks/{patient-search-D5ufYoRc.js.map → patient-search-HeEUB-_X.js.map} +1 -1
- package/dist/_chunks/{patient-summary-card-CBfuDvJ5.js → patient-summary-card-CvDxhbBR.js} +2 -2
- package/dist/_chunks/{patient-summary-card-CBfuDvJ5.js.map → patient-summary-card-CvDxhbBR.js.map} +1 -1
- package/dist/_chunks/{payment-request-card-YVCcCZ25.js → payment-request-card-lmKLwsDs.js} +2 -2
- package/dist/_chunks/{payment-request-card-YVCcCZ25.js.map → payment-request-card-lmKLwsDs.js.map} +1 -1
- package/dist/_chunks/{periodontal-chart-BatZEFar.js → periodontal-chart-B9fphroR.js} +2 -2
- package/dist/_chunks/{periodontal-chart-BatZEFar.js.map → periodontal-chart-B9fphroR.js.map} +1 -1
- package/dist/_chunks/{periodontal-chart-card-BBpY_rBc.js → periodontal-chart-card-qEZPXj83.js} +2 -2
- package/dist/_chunks/{periodontal-chart-card-BBpY_rBc.js.map → periodontal-chart-card-qEZPXj83.js.map} +1 -1
- package/dist/_chunks/{pregnancy-dating-DtToyMyc.js → pregnancy-dating-D2wchD11.js} +2 -2
- package/dist/_chunks/{pregnancy-dating-DtToyMyc.js.map → pregnancy-dating-D2wchD11.js.map} +1 -1
- package/dist/_chunks/{province-select-BDywtmL-.js → province-select-BBc7s7vR.js} +2 -2
- package/dist/_chunks/{province-select-BDywtmL-.js.map → province-select-BBc7s7vR.js.map} +1 -1
- package/dist/_chunks/{select-BW5ecXlX.js → select-Bi8zril7.js} +165 -136
- package/dist/_chunks/select-Bi8zril7.js.map +1 -0
- package/dist/_chunks/{signature-request-DVDTKLjM.js → signature-request-CUe903hj.js} +2 -2
- package/dist/_chunks/{signature-request-DVDTKLjM.js.map → signature-request-CUe903hj.js.map} +1 -1
- package/dist/_chunks/{tabs-CBb2AidH.js → tabs-DqKtTIjZ.js} +2 -2
- package/dist/_chunks/{tabs-CBb2AidH.js.map → tabs-DqKtTIjZ.js.map} +1 -1
- package/dist/_chunks/{tasks-panel-Do5SFp-j.js → tasks-panel-DPCNaRko.js} +2 -2
- package/dist/_chunks/{tasks-panel-Do5SFp-j.js.map → tasks-panel-DPCNaRko.js.map} +1 -1
- package/dist/_chunks/{tooth-scheme-WdyVymQ1.js → tooth-scheme-2IsmbE6w.js} +2 -2
- package/dist/_chunks/{tooth-scheme-WdyVymQ1.js.map → tooth-scheme-2IsmbE6w.js.map} +1 -1
- package/dist/_chunks/{unit-converter-BPumXMA6.js → unit-converter-C6jMjqL9.js} +2 -2
- package/dist/_chunks/{unit-converter-BPumXMA6.js.map → unit-converter-C6jMjqL9.js.map} +1 -1
- package/dist/_chunks/{workflow-map-DE_ribRM.js → workflow-map-wcw3t6g4.js} +2 -2
- package/dist/_chunks/{workflow-map-DE_ribRM.js.map → workflow-map-wcw3t6g4.js.map} +1 -1
- package/dist/agent-catalog.json +1 -1
- package/dist/components/_shared/option.d.ts +1 -0
- package/dist/components/_shared/option.d.ts.map +1 -1
- package/dist/components/address-fields/index.js +1 -1
- package/dist/components/ai-prompt-input/index.js +1 -1
- package/dist/components/audio-recorder/index.js +1 -1
- package/dist/components/autocomplete/autocomplete.d.ts.map +1 -1
- package/dist/components/autocomplete/index.js +1 -1
- package/dist/components/bishop-score/index.js +1 -1
- package/dist/components/booking/booking.d.ts.map +1 -1
- package/dist/components/booking/index.js +1 -1
- package/dist/components/care-plan-card/index.js +1 -1
- package/dist/components/care-plan-entry-card/index.js +1 -1
- package/dist/components/care-plan-header/index.js +1 -1
- package/dist/components/city-input/index.js +1 -1
- package/dist/components/combobox/combobox.d.ts.map +1 -1
- package/dist/components/combobox/index.js +1 -1
- package/dist/components/contact-profile-card/contact-profile-card.d.ts.map +1 -1
- package/dist/components/contact-profile-card/index.js +1 -1
- package/dist/components/country-select/index.js +1 -1
- package/dist/components/data-table/index.js +2 -2
- package/dist/components/document-preview/index.js +1 -1
- package/dist/components/face-scheme/index.js +1 -1
- package/dist/components/file-manager/index.js +1 -1
- package/dist/components/gestational-age-calculator/index.js +1 -1
- package/dist/components/key-value-pair/index.js +1 -1
- package/dist/components/key-value-pair/key-value-pair.d.ts +16 -0
- package/dist/components/key-value-pair/key-value-pair.d.ts.map +1 -1
- package/dist/components/multi-select/index.js +1 -1
- package/dist/components/multi-select/multi-select.d.ts.map +1 -1
- package/dist/components/muscle-scheme/index.js +1 -1
- package/dist/components/optical-prescription/index.js +1 -1
- package/dist/components/patient-details/index.js +1 -1
- package/dist/components/patient-search/index.js +1 -1
- package/dist/components/patient-summary-card/index.js +1 -1
- package/dist/components/patient-table/index.js +1 -1
- package/dist/components/payment-card/index.js +1 -1
- package/dist/components/periodontal-chart/index.js +1 -1
- package/dist/components/periodontal-chart-card/index.js +1 -1
- package/dist/components/pregnancy-dating/index.js +1 -1
- package/dist/components/province-select/index.js +1 -1
- package/dist/components/select/index.js +1 -1
- package/dist/components/select/select.d.ts +24 -0
- package/dist/components/select/select.d.ts.map +1 -1
- package/dist/components/skeleton-scheme/index.js +1 -1
- package/dist/components/tabs/index.js +1 -1
- package/dist/components/tasks-panel/index.js +1 -1
- package/dist/components/tooth-scheme/index.js +1 -1
- package/dist/components/unit-converter/index.js +1 -1
- package/dist/components/workflow/index.js +1 -1
- package/dist/index.js +40 -40
- package/dist/patterns/anamnesis/index.js +1 -1
- package/dist/patterns/signature-request/index.js +1 -1
- package/package.json +1 -1
- package/dist/_chunks/booking-CBHKdsZl.js.map +0 -1
- package/dist/_chunks/key-value-pair-BubG4fUa.js +0 -144
- package/dist/_chunks/key-value-pair-BubG4fUa.js.map +0 -1
- package/dist/_chunks/select-BW5ecXlX.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tooth-scheme-WdyVymQ1.js","sources":["../../src/components/tooth-scheme/tooth-scheme.agent.ts","../../src/components/tooth-scheme/tooth-scheme.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — ToothScheme. */\n/* */\n/* Odontogram. The agent-relevant surface is the chart itself: the */\n/* findings on each tooth — now one entry per SYMBOL, each scoping its own */\n/* surfaces, roots, planned/executed status and per-practice colour — plus */\n/* structural references to each tooth's radiograph archive. The handle is */\n/* the curated `ToothSchemeHandle`, never React state. */\n/* */\n/* A9 (PRS §26 §3): the always-on state snapshot carries identifiers and */\n/* enums ONLY. The model has two free-text fields — a symbol's `note` and */\n/* a tooth's `notes` — and both are PHI, so both are projected out of */\n/* `state.chart` and fetched deliberately, per tooth, through an audited */\n/* `phi` action (`get_symbols` / `get_notes`). Radiograph notes, dates and */\n/* image urls behave the same way through `get_radiographs`. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { ToothSchemeHandle } from './tooth-scheme';\nimport type {\n ConditionId,\n Radiograph,\n RadiographKind,\n Root,\n Surface,\n SymbolPart,\n SymbolStatus,\n ToothCondition,\n ToothSymbol,\n} from './tooth-data';\n\ntype FdiId = Parameters<ToothSchemeHandle['focusTooth']>[0];\n\n/* -------------------------------------------------------------------- */\n/* Drift guard. */\n/* */\n/* The JSON-Schema enums below are inlined literals, not runtime reads of */\n/* the `tooth-data` unions — the adapter must stay a pure module the ESM */\n/* catalog build can import without TS path resolution. `enumOf` is what */\n/* stops the two copies drifting: it accepts ONLY a literal that covers */\n/* its union EXACTLY. */\n/* */\n/* - a typo or a retired id fails on the `T extends readonly U[]` */\n/* constraint — the compiler names the id that is not in the union; */\n/* - a MISSING id fails on the intersected `EnumIsMissing<…>` brand — */\n/* the error reads `EnumIsMissing<\"xray\">`, naming the ids to add. */\n/* */\n/* `ToothCondition` growing 11 → 21 is exactly the drift this catches, so */\n/* `npx tsc -b` is the gate: the build breaks here until the literal */\n/* catches up with the union. Same guard on Surface / Root / SymbolPart / */\n/* SymbolStatus / RadiographKind. */\n/* -------------------------------------------------------------------- */\n\n/** Error brand — surfaces the ids an enum literal is missing, by name. */\ntype EnumIsMissing<U extends string> = {\n readonly __addTheseIdsToTheLiteral: U;\n};\n\nconst enumOf =\n <U extends string>() =>\n <T extends readonly U[]>(\n ids: T &\n ([U] extends [T[number]]\n ? unknown\n : EnumIsMissing<Exclude<U, T[number]>>),\n ): T =>\n ids;\n\nconst CONDITION_IDS = enumOf<ToothCondition>()([\n 'caries',\n 'filled',\n 'crowned',\n 'temporaryCrown',\n 'bridge',\n 'missing',\n 'implant',\n 'implantExtraction',\n 'stub',\n 'destroyed',\n 'rootCanal',\n 'pin',\n 'rootAmputation',\n 'anchorage',\n 'hook',\n 'attachment',\n 'mucogingivalSurgery',\n 'periodontalSurgery',\n 'curettage',\n 'medication',\n 'xray',\n] as const);\n\nconst SURFACE_IDS = enumOf<Surface>()([\n 'mesial',\n 'distal',\n 'occlusal',\n 'buccal',\n 'lingual',\n] as const);\n\nconst ROOT_IDS = enumOf<Root>()([\n 'mesial',\n 'distal',\n 'palatal',\n 'buccal',\n 'single',\n] as const);\n\nconst PART_IDS = enumOf<SymbolPart>()(['element', 'surface', 'root'] as const);\n\nconst STATUS_IDS = enumOf<SymbolStatus>()(['planned', 'executed'] as const);\n\nconst RADIOGRAPH_KIND_IDS = enumOf<RadiographKind>()([\n 'periapical',\n 'bitewing',\n 'panoramic',\n 'other',\n] as const);\n\n/* -------------------------------------------------------------------- */\n/* JSON-Schema fragments. */\n/* -------------------------------------------------------------------- */\n\nconst FDI_SCHEMA = {\n type: 'string',\n description:\n \"FDI tooth id ('11'–'48' permanent, '51'–'85' primary) or a special-element id ('Q1'–'Q4' quadrants, 'S1'–'S6' sextants, 'AS'/'AI' arches, 'general'; primary mirrors with an 'm' prefix).\",\n} as const;\nconst CONDITION_SCHEMA = {\n enum: [...CONDITION_IDS],\n description:\n \"Built-in finding id. 'destroyed' is the retained root (*radice persistente*); 'xray' is the chartable radiograph SYMBOL, distinct from the image archive reached via get_radiographs.\",\n} as const;\n/**\n * Open finding id — the vocabulary is extensible per practice, so this stays a\n * plain string rather than the closed `CONDITION_SCHEMA` enum.\n */\nconst CONDITION_ID_SCHEMA = {\n type: 'string',\n description:\n \"Finding id — either a built-in (the enum on set_finding) or a practice-defined id from the host's `conditionRegistry`.\",\n} as const;\nconst SURFACE_SCHEMA = {\n enum: [...SURFACE_IDS],\n description: 'Tooth surface, named anatomically.',\n} as const;\nconst ROOT_SCHEMA = {\n enum: [...ROOT_IDS],\n description:\n \"Root, named ANATOMICALLY (not by screen side) — 'palatal' exists only on upper molars, 'single' covers every one-rooted tooth. On flank-mounted markers (anchorage, hook) 'mesial' / 'distal' select the side of the tooth instead.\",\n} as const;\nconst PART_SCHEMA = {\n enum: [...PART_IDS],\n description:\n \"Anatomical layer the finding marks. Omit to take the condition's natural part (caries and fillings are 'surface', root canals are 'root', crowns and implants are 'element').\",\n} as const;\nconst STATUS_SCHEMA = {\n enum: [...STATUS_IDS],\n description:\n \"Execution status — 'planned' (proposed treatment) vs 'executed' (already done). Omit when the finding carries no plan/executed distinction.\",\n} as const;\n/**\n * One charted finding. Used for BOTH the `get_symbols` result and the\n * `set_symbol` argument — the shape is symmetrical.\n */\nconst SYMBOL_SCHEMA = {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description:\n \"Provenance id — the host's care-plan / finding entry this symbol came from. Present on symbols the host seeded; supply it to update that exact entry.\",\n },\n condition: CONDITION_ID_SCHEMA,\n part: PART_SCHEMA,\n surfaces: { type: 'array', items: SURFACE_SCHEMA },\n roots: { type: 'array', items: ROOT_SCHEMA },\n status: STATUS_SCHEMA,\n color: {\n type: 'string',\n description:\n \"Per-practice colour override — a CSS colour or `var(--token)`. Omit to take the condition's own colour.\",\n },\n note: {\n type: 'string',\n description: 'Free-text clinical note. PHI — never in a state snapshot.',\n },\n },\n required: ['condition'],\n} as const;\nconst RADIOGRAPH_SCHEMA = {\n type: 'object',\n properties: {\n id: { type: 'string' },\n url: { type: 'string' },\n thumbnailUrl: { type: 'string' },\n date: { type: 'string', description: 'ISO acquisition date (YYYY-MM-DD).' },\n note: { type: 'string' },\n kind: { enum: [...RADIOGRAPH_KIND_IDS] },\n alt: { type: 'string' },\n },\n required: ['id', 'url'],\n} as const;\n\n/**\n * A9: the snapshot-safe projection of one symbol — identifiers and enums only.\n * Allow-listed field by field rather than deleting `note`, so a free-text field\n * added to `ToothSymbol` later cannot leak into the always-on snapshot by\n * default; it has to be opted in here.\n */\nfunction structuralSymbol(symbol: ToothSymbol) {\n return {\n id: symbol.id,\n condition: symbol.condition,\n part: symbol.part,\n surfaces: symbol.surfaces,\n roots: symbol.roots,\n status: symbol.status,\n color: symbol.color,\n };\n}\n\nexport const toothSchemeAgent: AgentAdapter<ToothSchemeHandle> = {\n id: 'tooth-scheme',\n // pick — focus/select a tooth (`focus_tooth`, transient, not persisted);\n // set_value / edit_inline — `set_finding` records a built-in finding and\n // marks the affected surfaces (set-surface), `set_symbol` records the full\n // per-symbol form (part / roots / status / colour / note), `remove_finding`\n // clears one; view_change — the side/plan projection + dentition are view\n // props.\n // `view_change` is deliberately NOT claimed: projection / dentition /\n // numbering are props, and the component's own view state only takes effect\n // when `controls` is on, so a `set_view` action would silently no-op for most\n // consumers. The view is readable below; changing it stays the host's job.\n capabilities: ['pick', 'set_value', 'edit_inline'],\n state: {\n chart: {\n // A9: the always-on snapshot carries FDI / element ids plus finding\n // ENUMS only — never the free-text clinical notes (`ToothState.notes`,\n // `ToothSymbol.note`), which are PHI. Those are fetched deliberately,\n // per tooth, via get_notes / get_symbols (both safety: 'phi').\n type: 'Record<FdiId, { conditions: ToothCondition[]; surfaces: Surface[]; symbols: { id?: string; condition: ConditionId; part?: SymbolPart; surfaces?: Surface[]; roots?: Root[]; status?: SymbolStatus; color?: string }[] }>',\n descriptionKey: 'ui.agent.toothScheme.state.chart',\n description:\n 'Current dental chart keyed by FDI id, or by a special-element id (quadrant / sextant / arch / general) for region-spanning findings. Each entry carries the flat `conditions` + `surfaces` pair AND the normalised per-symbol list, where every finding scopes its own surfaces, roots, planned/executed status and colour. Free-text clinical notes are PHI and omitted — read them per tooth via get_symbols / get_notes.',\n read: (handle) =>\n Object.fromEntries(\n Object.entries(handle.getChart()).map(([fdi, state]) => [\n fdi,\n {\n conditions: state.conditions,\n surfaces: state.surfaces,\n // Read back through the handle so a tooth charted the legacy\n // way (flat conditions + surfaces) reports the same symbol\n // shape as one charted per-symbol.\n symbols: handle.getSymbols(fdi).map(structuralSymbol),\n },\n ]),\n ),\n },\n chartedTeeth: {\n type: 'string[]',\n descriptionKey: 'ui.agent.toothScheme.state.chartedTeeth',\n description:\n 'Ids carrying at least one finding — FDI tooth ids and/or special-element ids (quadrant / sextant / arch / general).',\n read: (handle) => Object.keys(handle.getChart()),\n },\n radiographs: {\n // A9: the always-on state snapshot carries identifiers + enums only —\n // never PHI free-text (the radiograph `note`), service dates, or the\n // consumer-hosted image URLs. Those are fetched deliberately, per tooth,\n // via the audited `get_radiographs` action.\n type: 'Record<string, { id: string; kind?: string }[]>',\n descriptionKey: 'ui.agent.toothScheme.state.radiographs',\n description:\n 'Structural references (id + kind) to the radiographs on each tooth, keyed by FDI id. Notes, dates and image URLs are not exposed here — fetch them on demand via get_radiographs.',\n read: (handle) =>\n Object.fromEntries(\n handle\n .teethWithRadiographs()\n .map((fdi) => [\n fdi,\n handle\n .getRadiographs(fdi)\n .map((r) => ({ id: r.id, kind: r.kind ?? 'periapical' })),\n ]),\n ),\n },\n teethWithRadiographs: {\n type: 'string[]',\n descriptionKey: 'ui.agent.toothScheme.state.teethWithRadiographs',\n description: 'FDI ids of every tooth carrying at least one radiograph.',\n read: (handle) => handle.teethWithRadiographs(),\n },\n },\n actions: {\n focus_tooth: {\n safety: 'read',\n argsType: '{ id: FdiId }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA },\n required: ['id'],\n },\n idempotent: true,\n errors: [\n 'In the `both` view the registered instance renders no SVG of its own (the four sub-charts do, and deliberately do not register), so this action has no effect there.',\n ],\n descriptionKey: 'ui.agent.toothScheme.actions.focusTooth',\n description: 'Move focus to a specific tooth by FDI id.',\n invoke: (handle, args: { id: FdiId }) => {\n handle.focusTooth(args.id);\n },\n },\n get_tooth: {\n safety: 'read',\n argsType: '{ id: FdiId }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA },\n required: ['id'],\n },\n returns: 'ToothCondition[]',\n returnsSchema: { type: 'array', items: CONDITION_SCHEMA },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.getTooth',\n description:\n \"Read the BUILT-IN findings recorded on one tooth (FDI id), as a flat list of condition ids. Practice-defined findings, per-finding surfaces, roots and status are not included — use get_symbols for the tooth's full record.\",\n invoke: (handle, args: { id: FdiId }) => handle.getTooth(args.id),\n },\n get_symbols: {\n // phi (not read): a symbol carries a free-text clinical `note`, which is\n // PHI. PRS §26 §3 — phi outranks read so the host gates it behind\n // stricter confirm + audit. The always-on state.chart snapshot stays\n // note-free.\n safety: 'phi',\n argsType: '{ id: FdiId }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA },\n required: ['id'],\n },\n returns: 'ToothSymbol[]',\n returnsSchema: { type: 'array', items: SYMBOL_SCHEMA },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.getSymbols',\n description:\n \"Read one tooth's full finding record (incl. notes) — one entry per symbol, each with its own surfaces, roots, planned/executed status, colour override, provenance id and free-text note. Normalised, so a tooth charted with the flat conditions/surfaces pair reports the same shape.\",\n invoke: (handle, args: { id: FdiId }) => handle.getSymbols(args.id),\n },\n get_notes: {\n // phi (not read): resolves the tooth-level free-text clinical note.\n // Same posture as get_symbols — the note is out of state.chart and only\n // reachable through this audited action.\n safety: 'phi',\n argsType: '{ id: FdiId }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA },\n required: ['id'],\n },\n returns: 'string | null',\n returnsSchema: { type: ['string', 'null'] },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.getNotes',\n description:\n 'Read the tooth-level free-text clinical note, or null when there is none. Per-finding notes are separate — they come back from get_symbols.',\n invoke: (handle, args: { id: FdiId }) =>\n handle.getChart()[args.id]?.notes ?? null,\n },\n teeth_with: {\n safety: 'read',\n argsType: '{ condition: ToothCondition }',\n argsSchema: {\n type: 'object',\n properties: { condition: CONDITION_SCHEMA },\n required: ['condition'],\n },\n returns: 'FdiId[]',\n returnsSchema: { type: 'array', items: FDI_SCHEMA },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.teethWith',\n description:\n 'List the ids carrying a given built-in finding — FDI tooth ids and/or special-element ids (e.g. all teeth with caries). For a practice-defined finding use teeth_with_symbol.',\n invoke: (handle, args: { condition: ToothCondition }) =>\n handle.teethWith(args.condition),\n },\n teeth_with_symbol: {\n safety: 'read',\n argsType: '{ condition: ConditionId }',\n argsSchema: {\n type: 'object',\n properties: { condition: CONDITION_ID_SCHEMA },\n required: ['condition'],\n },\n returns: 'FdiId[]',\n returnsSchema: { type: 'array', items: FDI_SCHEMA },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.teethWithSymbol',\n description:\n \"As teeth_with, but open to the practice-defined ids in the host's `conditionRegistry` as well as the built-ins.\",\n invoke: (handle, args: { condition: ConditionId }) =>\n handle.teethWithSymbol(args.condition),\n },\n get_radiographs: {\n // phi (not read): resolves the radiograph `note` (free-text clinical\n // PHI) alongside the acquisition date and the consumer-hosted image\n // urls. PRS §26 §3 — phi outranks read so the host gates it behind\n // stricter confirm + audit; the always-on state.radiographs snapshot\n // stays structural (id + kind).\n safety: 'phi',\n argsType: '{ id: FdiId }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA },\n required: ['id'],\n },\n returns: 'Radiograph[]',\n returnsSchema: { type: 'array', items: RADIOGRAPH_SCHEMA },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.getRadiographs',\n description:\n 'Read the radiographs (x-rays) attached to one tooth, including their notes, dates and image urls.',\n invoke: (handle, args: { id: FdiId }) => handle.getRadiographs(args.id),\n },\n open_radiographs: {\n safety: 'read',\n argsType: '{ id: FdiId }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA },\n required: ['id'],\n },\n idempotent: true,\n errors: [\n 'In the `both` view the registered instance renders no SVG of its own (the four sub-charts do, and deliberately do not register), so this action has no effect there.',\n ],\n descriptionKey: 'ui.agent.toothScheme.actions.openRadiographs',\n description:\n \"Focus a tooth and open its radiograph archive (fires the host's onOpenRadiographs).\",\n invoke: (handle, args: { id: FdiId }) => {\n handle.openRadiographs(args.id);\n },\n },\n set_finding: {\n safety: 'write',\n argsType:\n '{ id: FdiId; condition: ToothCondition; surfaces?: Surface[] }',\n argsSchema: {\n type: 'object',\n properties: {\n id: FDI_SCHEMA,\n condition: CONDITION_SCHEMA,\n surfaces: { type: 'array', items: SURFACE_SCHEMA },\n },\n required: ['id', 'condition'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.setFinding',\n description:\n 'Record a built-in finding on a tooth or region element (crown, implant, root canal, caries, …). Optionally mark the affected surfaces for a surface finding. Structural only — to set a finding’s roots, planned/executed status, colour or note, or to chart a practice-defined finding, use set_symbol.',\n invoke: (\n handle,\n args: { id: FdiId; condition: ToothCondition; surfaces?: Surface[] },\n ) => {\n handle.setFinding(args.id, args.condition, args.surfaces);\n },\n },\n set_symbol: {\n // phi (not write): the symbol may carry a free-text clinical `note`,\n // which is PHI. PRS §26 §3 — a PHI write must never be auto-confirmed.\n // The structural-only path stays available as set_finding ('write').\n safety: 'phi',\n argsType: '{ id: FdiId; symbol: ToothSymbol }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA, symbol: SYMBOL_SCHEMA },\n required: ['id', 'symbol'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.setSymbol',\n description:\n 'Add or replace one finding on a tooth or region element, with its own part, surfaces, roots, planned/executed status, colour override and note. Matched by `symbol.id` when the symbol carries provenance, otherwise by its condition; appended when nothing matches. Accepts practice-defined `conditionRegistry` ids as well as the built-ins.',\n examples: [\n {\n args: {\n id: '16',\n symbol: {\n condition: 'filled',\n surfaces: ['mesial'],\n status: 'executed',\n },\n },\n note: 'Record an executed mesial filling on tooth 16, leaving any other finding on that tooth untouched.',\n },\n {\n args: {\n id: '26',\n symbol: {\n condition: 'rootCanal',\n roots: ['palatal'],\n status: 'planned',\n },\n },\n note: \"Plan a root canal on the palatal root of tooth 26 ('palatal' is the anatomical root, not a screen side).\",\n },\n ],\n invoke: (handle, args: { id: FdiId; symbol: ToothSymbol }) => {\n handle.setSymbol(args.id, args.symbol);\n },\n },\n remove_finding: {\n safety: 'write',\n argsType: '{ id: FdiId; condition: ToothCondition }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA, condition: CONDITION_SCHEMA },\n required: ['id', 'condition'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.removeFinding',\n description:\n 'Remove a finding from a tooth — every symbol carrying that condition goes, whatever its surfaces or roots. Built-in ids only.',\n invoke: (handle, args: { id: FdiId; condition: ToothCondition }) => {\n handle.removeFinding(args.id, args.condition);\n },\n },\n clear_tooth: {\n safety: 'destructive',\n argsType: '{ id: FdiId }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.clearTooth',\n description: 'Clear every finding from a tooth.',\n invoke: (handle, args: { id: FdiId }) => {\n handle.clearTooth(args.id);\n },\n },\n },\n domHooks: {\n root: { attr: 'data-component', value: 'tooth-scheme' },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n item: {\n attr: 'data-fdi',\n description:\n \"Each rendered tooth `<g>` carries its FDI id as `data-fdi`, its first finding as `data-condition`, the full space-separated list as `data-conditions`, the finding count as `data-symbol-count` and the first finding's status as `data-status`; selectable special-element slots carry their id in `data-fdi` too (plus `data-special` naming the kind). Per-surface pick targets carry `data-zone`, per-root pick targets `data-root` (the anatomical root name). The `data-projection` / `data-view-mode` attributes on the root expose the side/plan/both view.\",\n },\n },\n};\n\n// Re-exported for callers building typed args against the adapter.\nexport type {\n ConditionId,\n Radiograph,\n RadiographKind,\n Root,\n Surface,\n SymbolPart,\n SymbolStatus,\n ToothCondition,\n ToothSymbol,\n};\n","/* ------------------------------------------------------------------ */\n/* ToothScheme — the consolidated AlfaDocs odontogram. */\n/* */\n/* - Image-base + SVG overlay: each tooth is a photoreal CGI render */\n/* (`<image>`, served from `assetBaseUrl`); the SVG layer on top */\n/* carries findings, selection, keyboard nav and a11y. No third-party */\n/* engine — `src/docs/08-third-party.mdx §Dental chart` rejected the */\n/* candidates (jQuery, abandoned, poor a11y). */\n/* */\n/* - Colour-not-alone: whole-tooth findings render a DISTINCT symbol */\n/* glyph image (the shape is the channel) + the tooth's accessible */\n/* name + tooltip; surface findings (caries / filled) render a */\n/* per-surface fill in the plan view, or a distinguished ring (solid */\n/* = caries, dashed = filled) + legend + tooltip in the side view. */\n/* */\n/* - One finding model: every read goes through `symbolsForTooth()`, */\n/* so a symbol scopes its OWN surfaces and roots, whole-tooth */\n/* symbols draw in BOTH projections, and a registered finding with */\n/* no artwork still charts, as a glyph badge. */\n/* */\n/* - Two projections: `side` (facial — whole-tooth findings) and */\n/* `plan` (occlusal — per-surface caries / fillings, the \"Stato */\n/* dentale\" marking). `both` lays the two facial (side) rows on the */\n/* outside with the two occlusal (plan) rows between them — upper */\n/* side, upper occlusal, lower occlusal, lower side — and brackets */\n/* the chart with tooth numbers above and below (matching the */\n/* platform odontogram). */\n/* */\n/* - Special elements: selectable quadrant / sextant / arch / whole- */\n/* mouth slots appended to the inline-end of each arch row, so a */\n/* finding can span a region (e.g. a denture on the upper arch). See */\n/* `tooth-data.ts` § Special elements. */\n/* */\n/* - Chart orientation is FIXED to clinical convention: the patient's */\n/* right sits on the viewer's left in both arches regardless of */\n/* `dir`. A mirrored chart would invert every recorded diagnosis. */\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n type ReactElement,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport * as RadixTooltip from '@radix-ui/react-tooltip';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Settings } from 'lucide-react';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { IconButton } from '../button';\nimport { Popover } from '../popover';\nimport { Select } from '../select';\nimport { Switch } from '../switch';\nimport { toothSchemeAgent } from './tooth-scheme.agent';\n\nimport {\n CONDITION_COLORS,\n STATUS_COLORS,\n STATUS_OPACITY,\n TOOTH_CONDITIONS,\n conditionColor,\n conditionGlyph,\n conditionHasArtwork,\n conditionLabel,\n conditionPart,\n conditionPlanFolder,\n conditionPlanSymbol,\n conditionSideSymbol,\n conditionSymbolUrl,\n isBuiltInCondition,\n planOverlayScale,\n planSymbolUrl,\n rootScreenSide,\n rootsForTooth,\n statusLabelKey,\n surfaceSymbolUrl,\n symbolColor,\n symbolsForTooth,\n zonesForTooth,\n zoneSurface,\n zonePath,\n FDI_TO_META,\n PERMANENT_TEETH,\n PRIMARY_TEETH,\n SPECIAL_BY_ID,\n SPECIAL_SLOT_WIDTH,\n TOOTH_HIT_PAD,\n TOOTH_ROW_GAP,\n TOOTH_SLOT_WIDTH,\n TOOTH_SLOT_HEIGHT,\n PRIMARY_TOOTH_SCALE,\n chartFromConditions,\n isSpecialElement,\n labelFor,\n layoutSpecials,\n layoutTeeth,\n specialIconUrl,\n specialsForRow,\n toothImageUrl,\n type Arch,\n type ConditionDefinition,\n type ConditionId,\n type ConditionRegistry,\n type Projection,\n type PositionedSpecial,\n type Root,\n type SpecialElement,\n type SymbolStatus,\n type ToothMeta,\n type ToothSymbol,\n type ViewMode,\n type Dentition,\n type FdiId,\n type Numbering,\n type Radiograph,\n type Surface,\n type SurfaceZone,\n type ToothChart,\n type ToothCondition,\n type ToothMode,\n type ToothState,\n} from './tooth-data';\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport interface ToothSchemeProps {\n /** Opaque instance id — emitted as `data-component-id` for the agent registry. */\n id?: string;\n /** Which teeth to render. Default `'permanent'`. */\n dentition?: Dentition;\n /** Numbering system shown on each tooth label. Default `'fdi'`. */\n numbering?: Numbering;\n /** `'interactive'` enables selection + keyboard nav; `'display'` is read-only. Default `'interactive'`. */\n mode?: ToothMode;\n /**\n * `'side'` shows the facial view (whole-tooth findings); `'plan'` shows the\n * occlusal view (per-surface caries / fillings); `'both'` lays the two facial\n * rows on the outside with the two occlusal rows between them (upper side →\n * upper occlusal → lower occlusal → lower side), bracketed by tooth numbers\n * above and below. Default `'side'`.\n */\n projection?: ViewMode;\n /**\n * Show the selectable special-element slots (quadrants, sextants, arches,\n * whole-mouth) to the inline-end of each arch row. When unset, they show in\n * `both` view and hide in the single side / plan views; pass `true` / `false`\n * to force it. They share the chart data and emit `onSelect` like a tooth.\n */\n specialElements?: boolean;\n /** Controlled chart state — the full `Record<FdiId, ToothState>`. */\n value?: ToothChart;\n /** Uncontrolled initial chart state. */\n defaultValue?: ToothChart;\n /** Fired whenever the chart changes — always emits FDI ids. */\n onChange?: (next: ToothChart) => void;\n /**\n * Fired when a tooth OR special element is focused / clicked. Special\n * elements emit their id (`Q1`, `S3`, `AS`, `general`, …).\n */\n onSelect?: (toothId: FdiId) => void;\n /** Shortcut for pre-populating conditions: `{ '16': ['caries'], '36': ['filled'] }`. */\n conditions?: Partial<Record<FdiId, ToothCondition[]>>;\n /**\n * Per-tooth radiographs (x-rays / *endorali*), keyed by FDI id — mirrors the\n * `conditions` shape. Teeth carrying at least one radiograph get a corner\n * count badge; in `radiographDisplay=\"thumbnail\"` the most-recent film also\n * fills the slot. Image urls are opaque / consumer-hosted — never bundle real\n * scans (PHI).\n */\n radiographs?: Partial<Record<FdiId, Radiograph[]>>;\n /**\n * How a tooth carrying radiographs is marked. `'badge'` (default) keeps the\n * photoreal tooth render and adds a corner count badge; `'thumbnail'` shows\n * the most-recent radiograph inset in the slot (still badged).\n */\n radiographDisplay?: 'badge' | 'thumbnail';\n /**\n * Fired when a tooth's radiograph archive is opened — i.e. a tooth is\n * activated (click / Enter / Space) in `mode=\"display\"`. Wire this to a\n * Sheet/Dialog that manages the tooth's films. Setting this makes display-mode\n * teeth focusable buttons; it is mutually exclusive with interactive\n * findings-editing (`mode=\"interactive\"` / `activeCondition`).\n *\n * EVERY tooth becomes an open-archive button — including unfilmed teeth, so the\n * user can add the first film to an empty tooth (matching a real imaging hub).\n * Filmed teeth are distinguished by the radiograph count folded into their\n * accessible name and tooltip.\n */\n onOpenRadiographs?: (toothId: FdiId) => void;\n /**\n * The finding a tooth-click applies in interactive mode (the selected\n * tool in a Findings / \"Stato dentale\" panel). Clicking a tooth toggles\n * this condition. When unset, clicking cycles caries on/off.\n *\n * A surface-part tool (caries / filled) drills into the tooth's surfaces in\n * the occlusal view; a root-part tool (root canal, post, apicectomy) drills\n * into the roots of a multi-rooted tooth in the facial view. Accepts a\n * `conditionRegistry` id as well as a built-in.\n */\n activeCondition?: ConditionId;\n /**\n * Practice-defined findings, resolved AHEAD of the built-in vocabulary field\n * by field — so an entry may re-tint or re-label a shipped finding without\n * losing its artwork, or add a wholly new one. An entry with no artwork\n * renders its `glyph` badge, which is the seam that lets a practice chart a\n * finding before a designer draws it. Labels are already-translated text:\n * the consuming app owns custom-condition copy, not the kit.\n */\n conditionRegistry?: ConditionDefinition[];\n /**\n * Base URL the photoreal tooth renders are served from. Resolves to\n * `${assetBaseUrl}/{side|plan}/{symbol}/{top|bottom}/{fdi}.webp`. Defaults\n * to the kit's bundled static path; host the `toothscheme/teeth` set\n * elsewhere (CDN) by overriding this. Trusted developer-controlled value —\n * interpolated into an SVG `<image href>` (which cannot execute scripts),\n * not user input; intentionally not runtime-validated.\n */\n assetBaseUrl?: string;\n /**\n * Show the finding-colour legend below the chart. Default `false` — findings\n * render as distinct symbol glyphs (self-describing) + tooltips, so the\n * colour key is opt-in; a consuming \"Stato dentale\" surface uses a\n * finding-type panel as its key instead.\n */\n legend?: boolean;\n /**\n * Render a built-in options affordance: a gear button that opens a popover\n * letting the END USER toggle the legend + special elements and switch\n * dentition / numbering / projection. Opt-in — when on, those become\n * user-overridable (seeded from the props); when off, the props drive the\n * chart directly. Default `false`.\n */\n controls?: boolean;\n /**\n * Where to render the `controls` gear. `undefined` (default) renders it\n * inline at the top-end of the chart. Pass a DOM element (e.g. a ref'd slot in\n * your card header) to portal the gear + its popover into that slot instead,\n * so the chart options can sit on the title line. While the slot is mounting\n * the prop will be `null`; the gear renders nothing until the element exists,\n * so it never flashes inline first. No effect unless `controls` is on.\n */\n controlsContainer?: HTMLElement | null;\n /** Accessible label override for the chart region. */\n ariaLabel?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n}\n\n/** Number-label placement for a sub-chart. */\ntype NumbersPosition = 'between' | 'above' | 'below' | 'none';\n\n/**\n * Which sub-part of a tooth the keyboard has drilled into. Surfaces and roots\n * share one state so the modal \"everything else steps out of the tab order\"\n * guard has a single source of truth.\n */\ntype Drill =\n | { fdi: FdiId; part: 'surface'; zone: SurfaceZone }\n | { fdi: FdiId; part: 'root'; root: Root };\n\n/**\n * Internal-only props (prefixed `_`) used when the component composes itself\n * into the four-row `both` view — never part of the public API.\n */\ninterface ToothSchemeInternalProps {\n /** Render a single arch (the `both` view stacks one arch per sub-chart). */\n _arch?: Arch;\n /** Number-label placement for this sub-chart. */\n _numbersPosition?: NumbersPosition;\n /** Render only the `<svg>` (no region wrapper, controls, legend, or chrome). */\n _inner?: boolean;\n /**\n * Force the SVG content width (the `both` view shares one width across all\n * four sub-charts so they scale identically and stay column-aligned —\n * otherwise rows with fewer special-element columns would scale up larger).\n */\n _contentWidth?: number;\n}\n\nexport interface ToothSchemeHandle {\n /** Programmatically focus a tooth by FDI id. */\n focusTooth: (id: FdiId) => void;\n /** Read the current chart state. */\n getChart: () => ToothChart;\n /**\n * Read the built-in findings recorded on one tooth (empty array if none).\n * Registry ids are omitted — use `getSymbols` for the full list.\n */\n getTooth: (id: FdiId) => ToothCondition[];\n /** Read the findings on one tooth as symbols, with surfaces, roots and status. */\n getSymbols: (id: FdiId) => ToothSymbol[];\n /** Read the FDI ids of every tooth carrying a given finding. */\n teethWith: (condition: ToothCondition) => FdiId[];\n /** As `teethWith`, but open to a `conditionRegistry` id. */\n teethWithSymbol: (condition: ConditionId) => FdiId[];\n /** Add a finding to a tooth (no-op if already present). Optionally mark surfaces. */\n setFinding: (\n id: FdiId,\n condition: ToothCondition,\n surfaces?: Surface[],\n ) => void;\n /**\n * Add or replace one symbol on a tooth — the surface-, root- and\n * status-aware form of `setFinding`. Matched by `symbol.id` when the symbol\n * carries provenance, else by its condition.\n */\n setSymbol: (id: FdiId, symbol: ToothSymbol) => void;\n /** Remove a finding from a tooth (no-op if absent). */\n removeFinding: (id: FdiId, condition: ToothCondition) => void;\n /** Clear every finding from a tooth. */\n clearTooth: (id: FdiId) => void;\n /** Read the radiographs attached to one tooth (empty array if none). */\n getRadiographs: (id: FdiId) => Radiograph[];\n /** Read the FDI ids of every tooth carrying at least one radiograph. */\n teethWithRadiographs: () => FdiId[];\n /** Focus a tooth and open its radiograph archive (fires `onOpenRadiographs`). */\n openRadiographs: (id: FdiId) => void;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst rootVariants = cva(\n [\n 'ds:tooth-scheme-alfadocs',\n 'ds:flex ds:flex-col',\n 'ds:gap-[var(--spacing-sm)]',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n // Block-level flex column so the SVG's w-full can grow to fill the frame.\n // min-w-fit on the SVG floors it at natural size, so narrow frames scroll\n // here rather than shrinking the per-tooth hit target below the 44px floor.\n 'ds:max-w-full ds:overflow-x-auto',\n // When the scroll container itself is the tab stop (display mode, see\n // scrollTabIndex) it needs a focus ring. Use an outline (not box-shadow):\n // forced-colors / high-contrast mode zeroes box-shadow, which would leave\n // HCM keyboard users with no visible focus. outline survives, and the\n // CanvasText fallback repaints it in the system palette.\n 'ds:outline-none',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n ].join(' '),\n);\n\n// The four `both`-view sub-charts stack in a tight column (no inter-row gap),\n// so the facial → occlusal → occlusal → facial rows read as one chart.\nconst bothStackVariants = cva(['ds:flex ds:flex-col ds:gap-0'].join(' '));\n\n// Responsive width: w-full lets the SVG grow to FILL a wider frame and h-auto\n// keeps the viewBox aspect. min-w-fit floors it at the viewBox's natural width\n// so it never scales the per-tooth tap target below the ≥44px AAA floor (WCAG\n// 2.5.5) — narrower frames scroll on the root rather than shrinking the teeth.\nconst svgVariants = cva(\n [\n 'ds:block',\n 'ds:w-full ds:min-w-fit ds:h-auto',\n 'ds:text-[var(--foreground)]',\n ].join(' '),\n);\n\n// `group` here is load-bearing — the focus-ring <rect> below uses\n// `group-focus-visible:opacity-100` to appear when the parent <g> takes\n// focus. Without this class the selector never fires and keyboard users\n// see no focus indicator (a11y-critical-fixes.mdx).\nconst toothGroupVariants = cva(\n [\n 'ds:group ds:cursor-pointer',\n 'ds:focus:outline-none',\n 'ds:transition-[fill,stroke,opacity] ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n ].join(' '),\n);\n\nconst legendVariants = cva(\n [\n 'ds:flex ds:flex-wrap ds:items-center',\n 'ds:gap-[var(--spacing-sm)]',\n 'type-meta ds:text-[var(--muted-foreground)]',\n ].join(' '),\n);\n\nconst legendItemVariants = cva(\n ['ds:inline-flex ds:items-center', 'ds:gap-[var(--spacing-xs)]'].join(' '),\n);\n\nconst liveRegionVariants = cva(['ds:sr-only'].join(' '));\n\n// Surface-zone affordance (plan view, interactive surface-picking). Invisible\n// until hovered (pointer) or focused (keyboard, drilled-in) — the marked\n// surface itself is shown by the photoreal per-surface overlay underneath.\nconst zoneVariants = cva(\n [\n 'ds:cursor-pointer ds:outline-none',\n 'ds:fill-transparent ds:stroke-transparent',\n 'ds:transition-[fill] ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n 'ds:hover:fill-[color-mix(in_srgb,var(--accent)_18%,transparent)]',\n // `:focus` as well as `:focus-visible` — a pointer drill-in moves focus\n // programmatically, so the browser's focus-visible heuristic does not match\n // and the newly focused zone would otherwise show nothing at all.\n 'ds:focus:fill-[color-mix(in_srgb,var(--accent)_22%,transparent)]',\n 'ds:focus:stroke-[var(--ring)]',\n 'ds:focus-visible:fill-[color-mix(in_srgb,var(--accent)_22%,transparent)]',\n 'ds:focus-visible:stroke-[var(--ring)]',\n 'ds:forced-colors:focus:stroke-[CanvasText]',\n 'ds:forced-colors:focus-visible:stroke-[CanvasText]',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nfunction isControlled(props: Pick<ToothSchemeProps, 'value'>): boolean {\n return props.value !== undefined;\n}\n\nfunction emptyState(): ToothState {\n return { conditions: [], surfaces: [] };\n}\n\n/** Toggle a whole-tooth finding on a symbol list (no tool → cycle caries). */\nfunction toggleSymbolCondition(\n symbols: ToothSymbol[],\n active: ConditionId | undefined,\n registry?: ConditionRegistry,\n): ToothSymbol[] {\n const condition: ConditionId = active ?? 'caries';\n const symbol: ToothSymbol = {\n condition,\n part: conditionPart(condition, registry),\n };\n // No tool selected → cycle caries on/off (legacy demo behaviour).\n if (!active) return symbols.length === 0 ? [symbol] : [];\n return symbols.some((entry) => entry.condition === condition)\n ? symbols.filter((entry) => entry.condition !== condition)\n : [...symbols, symbol];\n}\n\n/**\n * Toggle one surface or root inside the symbol carrying the active finding,\n * adding the symbol when the tooth has none. Each symbol scopes its OWN\n * surfaces / roots, so two fillings on one tooth stay distinct.\n */\nfunction toggleSymbolTarget(\n symbols: ToothSymbol[],\n condition: ConditionId,\n part: 'surface' | 'root',\n target: Surface | Root,\n): ToothSymbol[] {\n const covers = (entry: ToothSymbol): boolean =>\n part === 'surface'\n ? (entry.surfaces ?? []).includes(target as Surface)\n : (entry.roots ?? []).includes(target as Root);\n const sameCondition = (entry: ToothSymbol): boolean =>\n entry.condition === condition;\n // Un-marking edits the symbol the click actually falls in. Marking grows a\n // symbol only when it carries no provenance id — attributing a new surface to\n // someone else's care-plan entry would silently rewrite that record, so a\n // provenance-bound chart gets a new symbol instead. That is also what lets the\n // two-fillings-one-tooth shape be authored by clicking, not just by data.\n const index = symbols.findIndex(\n (entry) => sameCondition(entry) && covers(entry),\n );\n const growable = symbols.findIndex(\n (entry) => sameCondition(entry) && entry.id === undefined,\n );\n if (index < 0 && growable >= 0) {\n return toggleAt(symbols, growable, part, target);\n }\n if (index < 0) {\n const seed: ToothSymbol =\n part === 'surface'\n ? { condition, part, surfaces: [target as Surface] }\n : { condition, part, roots: [target as Root] };\n return [...symbols, seed];\n }\n return toggleAt(symbols, index, part, target);\n}\n\n/** Add or remove one surface / root inside the symbol at `index`. */\nfunction toggleAt(\n symbols: ToothSymbol[],\n index: number,\n part: 'surface' | 'root',\n target: Surface | Root,\n): ToothSymbol[] {\n const symbol = symbols[index];\n const current: (Surface | Root)[] =\n part === 'surface' ? (symbol.surfaces ?? []) : (symbol.roots ?? []);\n const next = current.includes(target)\n ? current.filter((entry) => entry !== target)\n : [...current, target];\n if (next.length === 0) return symbols.filter((_, i) => i !== index);\n const updated: ToothSymbol =\n part === 'surface'\n ? { ...symbol, part, surfaces: next as Surface[] }\n : { ...symbol, part, roots: next as Root[] };\n return symbols.map((entry, i) => (i === index ? updated : entry));\n}\n\n/**\n * Fold a symbol list back onto the legacy `conditions` + `surfaces` pair so\n * `data-condition` and consumers that predate `symbols` keep reading. Registry\n * ids are omitted — a legacy reader does not know that vocabulary.\n */\nfunction stateFromSymbols(\n symbols: ToothSymbol[],\n previous?: ToothState,\n): ToothState {\n const conditions: ToothCondition[] = [];\n const surfaces: Surface[] = [];\n for (const symbol of symbols) {\n if (\n isBuiltInCondition(symbol.condition) &&\n !conditions.includes(symbol.condition)\n ) {\n conditions.push(symbol.condition);\n }\n for (const surface of symbol.surfaces ?? []) {\n if (!surfaces.includes(surface)) surfaces.push(surface);\n }\n }\n return { ...(previous ?? emptyState()), conditions, surfaces, symbols };\n}\n\n/** Translate a special element to its accessible name. */\nfunction elementName(\n element: SpecialElement,\n t: (key: string, opts?: Record<string, unknown>) => string,\n): string {\n switch (element.labelKey) {\n case 'quadrant':\n return t('toothScheme.special.quadrant', { n: element.labelIndex });\n case 'sextant':\n return t('toothScheme.special.sextant', { n: element.labelIndex });\n case 'archUpper':\n return t('toothScheme.special.archUpper');\n case 'archLower':\n return t('toothScheme.special.archLower');\n default:\n return t('toothScheme.special.general');\n }\n}\n\n/**\n * Drill-in arrow navigation between a tooth's surface zones. 4-zone teeth map\n * each arrow straight to its zone; 5-zone teeth pivot through the occlusal\n * centre (every edge connects only to the centre, the centre to all edges).\n */\nfunction nextZone(\n zone: SurfaceZone,\n key: string,\n hasCenter: boolean,\n): SurfaceZone {\n if (!hasCenter) {\n if (key === 'ArrowUp') return 'top';\n if (key === 'ArrowDown') return 'bottom';\n if (key === 'ArrowLeft') return 'left';\n if (key === 'ArrowRight') return 'right';\n return zone;\n }\n const hub: Record<SurfaceZone, Partial<Record<string, SurfaceZone>>> = {\n top: { ArrowDown: 'center' },\n bottom: { ArrowUp: 'center' },\n left: { ArrowRight: 'center' },\n right: { ArrowLeft: 'center' },\n center: {\n ArrowUp: 'top',\n ArrowDown: 'bottom',\n ArrowLeft: 'left',\n ArrowRight: 'right',\n },\n };\n return hub[zone]?.[key] ?? zone;\n}\n\n/**\n * A tooth's roots in SCREEN order (left → centre → right). The palatal root\n * renders between the other two; mesial / distal flip across the midline, which\n * `rootScreenSide` already knows.\n */\nfunction orderedRoots(meta: ToothMeta): Root[] {\n const slot = (root: Root): number => {\n if (root === 'mesial' || root === 'distal')\n return rootScreenSide(meta, root) === 'left' ? 0 : 2;\n return 1;\n };\n return [...rootsForTooth(meta)].sort((a, b) => slot(a) - slot(b));\n}\n\n/** The roots a tooth can be drilled into — a single-rooted tooth has no choice. */\nfunction drillableRoots(meta: ToothMeta): Root[] {\n const roots = orderedRoots(meta);\n return roots.length > 1 ? roots : [];\n}\n\n/**\n * Drill-in arrow navigation between a tooth's roots. They lie in one\n * screen-ordered strip, so only the inline arrows step — there is no second\n * axis to move on.\n */\nfunction nextRoot(root: Root, key: string, roots: Root[]): Root {\n const index = roots.indexOf(root);\n if (index < 0) return root;\n if (key === 'ArrowRight') return roots[Math.min(roots.length - 1, index + 1)];\n if (key === 'ArrowLeft') return roots[Math.max(0, index - 1)];\n return root;\n}\n\ninterface SlotRect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\n/**\n * Hit strip for one root over the facial render. Roots point away from the\n * occlusal plane, so they occupy the block-start half of an upper tooth and the\n * block-end half of a lower one.\n */\n/**\n * A root's pick column. Root identity is the HORIZONTAL position — which is why\n * the column runs the full height of the slot rather than only the apical half:\n * a third of a 36-wide slot is a slim target already, and halving its height\n * again put it well under `--min-target-size`. While a tooth is drilled its\n * group is a `role=\"group\"`, so a full-height column competes with nothing.\n */\nfunction rootRect(index: number, count: number, rect: SlotRect): SlotRect {\n const w = rect.w / count;\n return { x: rect.x + index * w, y: rect.y, w, h: rect.h };\n}\n\n/* ------------------------------------------------------------------ */\n/* Legend */\n/* */\n/* Each entry shows the finding EXACTLY as it renders on the chart — a */\n/* mini tooth (the upper-right molar) carrying that finding's symbol */\n/* glyph, surface ring, or missing-X — so the key actually maps to the */\n/* scheme rather than to an abstract colour swatch. */\n/* ------------------------------------------------------------------ */\n\n/**\n * Fallback mark for a condition with no artwork in this projection — a\n * token-coloured badge carrying the registry glyph. The `--card` fill keeps the\n * text legible over the photoreal render in all four themes; the condition's\n * label rides in the tooth's accessible name, so the badge itself is decorative.\n */\nfunction GlyphMark({\n glyph,\n colour,\n cx,\n cy,\n opacity,\n testId,\n}: {\n glyph: string;\n colour: string;\n cx: number;\n cy: number;\n opacity?: number;\n testId?: string;\n}): ReactElement {\n const w = 9 + glyph.length * 5;\n return (\n <g\n transform={`translate(${cx - w / 2}, ${cy - 7})`}\n data-testid={testId}\n pointerEvents=\"none\"\n aria-hidden=\"true\"\n >\n {/* The planned dimming rides on the badge chrome only. Fading the glyph\n too would drag real text under the contrast floor (0.55 of\n `--foreground` on `--card` is ~3.3:1), and axe cannot see SVG text.\n Status still has two channels: the badge tint and the StatusDot. */}\n <rect\n width={w}\n height={14}\n rx=\"3.5\"\n fill=\"var(--card)\"\n stroke={colour}\n strokeWidth=\"1.5\"\n opacity={opacity}\n />\n <text\n x={w / 2}\n y={10}\n textAnchor=\"middle\"\n fontSize=\"9\"\n fontWeight=\"600\"\n fill=\"var(--foreground)\"\n className=\"ds:select-none\"\n >\n {glyph}\n </text>\n </g>\n );\n}\n\n/**\n * Execution-status marker: a filled disc for executed, a hollow ring for\n * planned. The shape is the second channel — the status token colour never\n * carries the distinction on its own.\n */\nfunction StatusDot({\n status,\n cx,\n cy,\n r,\n strokeWidth,\n testId,\n}: {\n status: SymbolStatus;\n cx: number;\n cy: number;\n r: number;\n strokeWidth: number;\n testId?: string;\n}): ReactElement {\n return (\n <circle\n cx={cx}\n cy={cy}\n r={r}\n fill={status === 'executed' ? STATUS_COLORS.executed : 'var(--card)'}\n stroke={STATUS_COLORS[status]}\n strokeWidth={strokeWidth}\n data-testid={testId}\n pointerEvents=\"none\"\n aria-hidden=\"true\"\n />\n );\n}\n\n/** Status rendering order — planned first, mirroring the care-plan flow. */\nconst STATUS_ORDER: SymbolStatus[] = ['planned', 'executed'];\n\n/** A 36×62 mini tooth rendering one finding, mirroring the chart's visuals. */\nfunction LegendSymbol({\n condition,\n assetBaseUrl,\n registry,\n}: {\n condition: ConditionId;\n assetBaseUrl: string;\n registry?: ConditionRegistry;\n}): ReactElement {\n const meta = FDI_TO_META['16'];\n const spec = conditionSideSymbol(condition, registry);\n const isMissing = condition === 'missing';\n const colour = conditionColor(condition, registry);\n // caries / filled carry no side artwork — the chart rings them instead.\n const isSurface =\n !spec && !isMissing && conditionHasArtwork(condition, 'side', registry);\n // Match the chart: the render is inset (scaled 0.9) so the surface ring and\n // missing-X never touch the tooth — the same fix applied to the live teeth.\n const w = 36 * 0.9;\n const h = 62 * 0.9;\n const x = (36 - w) / 2;\n const y = (62 - h) / 2;\n return (\n <svg\n width=\"22\"\n height=\"38\"\n viewBox=\"0 0 36 62\"\n aria-hidden=\"true\"\n className=\"ds:block ds:shrink-0\"\n >\n <image\n href={toothImageUrl(meta, assetBaseUrl)}\n x={x}\n y={y}\n width={w}\n height={h}\n preserveAspectRatio=\"xMidYMid meet\"\n opacity={isMissing ? 0.25 : 1}\n />\n {spec ? (\n <image\n href={conditionSymbolUrl(meta, assetBaseUrl, spec)}\n x={x}\n y={y}\n width={w}\n height={h}\n preserveAspectRatio=\"xMidYMid meet\"\n />\n ) : null}\n {isSurface ? (\n <rect\n x={3}\n y={2}\n width={30}\n height={58}\n fill=\"none\"\n stroke={colour}\n strokeWidth={2}\n strokeDasharray={condition === 'filled' ? '4 2' : undefined}\n rx={6}\n />\n ) : null}\n {isMissing ? (\n <path\n d=\"M7 9 L29 53 M29 9 L7 53\"\n stroke={CONDITION_COLORS.missing}\n strokeWidth={2}\n fill=\"none\"\n />\n ) : null}\n {!spec && !isSurface && !isMissing ? (\n <GlyphMark\n glyph={conditionGlyph(condition, registry)}\n colour={colour}\n cx={18}\n cy={31}\n />\n ) : null}\n </svg>\n );\n}\n\nfunction Legend({\n assetBaseUrl,\n registry,\n}: {\n assetBaseUrl: string;\n registry?: ConditionRegistry;\n}): ReactElement {\n const { t } = useTranslation();\n // Built-ins first, in the vocabulary's own order, then whatever the practice\n // registered — a registry entry that shadows a built-in shows once.\n const conditions: ConditionId[] = [\n ...TOOTH_CONDITIONS,\n ...(registry ?? [])\n .map((entry) => entry.id)\n .filter((id) => !isBuiltInCondition(id)),\n ];\n return (\n <section\n aria-label={t('toothScheme.legendLabel')}\n data-testid=\"tooth-scheme-legend\"\n // Matches the Card `elevated` variant exactly: --card surface, a subtle\n // --card-border, --shadow-card, and the thicker border in the accessible\n // theme. --muted-foreground on --card stays a validated pair.\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:rounded-[var(--radius-md)] ds:bg-[var(--card)] ds:border ds:border-[color:var(--card-border)] ds:p-[var(--spacing-sm)] ds:shadow-[var(--shadow-card)] ds:[.theme-accessible_&]:border-2\"\n >\n <span className=\"type-eyebrow ds:text-[color:var(--muted-foreground)]\">\n {t('toothScheme.legendLabel')}\n </span>\n <ul className={legendVariants()}>\n {conditions.map((condition) => {\n const label = conditionLabel(condition, registry);\n return (\n <li\n key={condition}\n className={legendItemVariants()}\n data-condition={condition}\n data-testid={`tooth-scheme-legend-item-${condition}`}\n >\n <LegendSymbol\n condition={condition}\n assetBaseUrl={assetBaseUrl}\n registry={registry}\n />\n <span>{label.kind === 'key' ? t(label.key) : label.text}</span>\n </li>\n );\n })}\n </ul>\n <span className=\"type-eyebrow ds:text-[color:var(--muted-foreground)]\">\n {t('toothScheme.legendStatusLabel')}\n </span>\n <ul className={legendVariants()}>\n {STATUS_ORDER.map((status) => (\n <li\n key={status}\n className={legendItemVariants()}\n data-status={status}\n data-testid={`tooth-scheme-legend-status-${status}`}\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n aria-hidden=\"true\"\n className=\"ds:block ds:shrink-0\"\n >\n <StatusDot\n status={status}\n cx={7}\n cy={7}\n r={5}\n strokeWidth={1.75}\n />\n </svg>\n <span>{t(statusLabelKey(status))}</span>\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\n// One labelled Select row inside the options popover. The label stacks ABOVE a\n// full-width Select so long option values (e.g. \"Permanent dentition\") fit on\n// one line. The visible label is `aria-hidden` (sighted-only) and duplicated as\n// the Select's `aria-label`, so screen-reader users get the name once.\nfunction OptionRow({\n label,\n value,\n options,\n onValueChange,\n container,\n}: {\n label: string;\n value: string;\n options: { value: string; label: string }[];\n onValueChange: (value: string) => void;\n container?: HTMLElement | null;\n}): ReactElement {\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <span\n aria-hidden=\"true\"\n className=\"type-label ds:text-[color:var(--muted-foreground)]\"\n >\n {label}\n </span>\n <Select\n size=\"md\"\n aria-label={label}\n value={value}\n options={options}\n onValueChange={onValueChange}\n // Keeps the listbox inside the popover's scroll container. Not needed\n // for stacking — dropdown and popover share a layer, so the listbox\n // already paints on top by portal order.\n container={container}\n />\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\n/** Sort radiographs newest-first; undated films sink to the end. */\nfunction sortByDateDesc(a: Radiograph, b: Radiograph): number {\n if (a.date === b.date) return 0;\n if (!a.date) return 1;\n if (!b.date) return -1;\n return a.date < b.date ? 1 : -1;\n}\n\nexport const ToothScheme = forwardRef<\n ToothSchemeHandle,\n ToothSchemeProps & ToothSchemeInternalProps\n>(\n (\n {\n id,\n dentition: dentitionProp = 'permanent',\n numbering: numberingProp = 'fdi',\n mode = 'interactive',\n projection: projectionProp = 'side',\n specialElements: specialElementsProp,\n value,\n defaultValue,\n onChange,\n onSelect,\n conditions,\n radiographs,\n radiographDisplay = 'badge',\n onOpenRadiographs,\n activeCondition,\n conditionRegistry,\n assetBaseUrl = '/toothscheme/teeth',\n legend: legendProp = false,\n controls = false,\n controlsContainer,\n ariaLabel,\n className,\n _arch,\n _numbersPosition = 'between',\n _inner = false,\n _contentWidth,\n },\n ref,\n ) => {\n const { t } = useTranslation();\n\n // User-facing options (the gear popover). When `controls` is on, the\n // chart's dentition / numbering / projection / legend / special elements\n // become user-overridable: internal state is seeded from the props and the\n // popover updates it. When `controls` is off, the props drive the chart\n // directly (the component stays fully controlled for consumers who don't\n // want it).\n const [uiDentition, setUiDentition] = useState<Dentition>(dentitionProp);\n const [uiNumbering, setUiNumbering] = useState<Numbering>(numberingProp);\n const [uiProjection, setUiProjection] = useState<ViewMode>(projectionProp);\n const [uiLegend, setUiLegend] = useState<boolean>(legendProp);\n const [uiSpecial, setUiSpecial] = useState<boolean | undefined>(\n specialElementsProp,\n );\n\n // Portal target for the option selects, captured from the popover content\n // so their listboxes render above the popover (not behind it).\n const [optionsPopoverEl, setOptionsPopoverEl] =\n useState<HTMLElement | null>(null);\n\n const dentition = controls ? uiDentition : dentitionProp;\n const numbering = controls ? uiNumbering : numberingProp;\n const legend = controls ? uiLegend : legendProp;\n // The View select can pick a single projection or 'both'. The single\n // projections render one chart; 'both' lays four arch-scoped sub-charts so\n // the occlusal rows sit between the facial rows.\n const viewMode: ViewMode = controls ? uiProjection : projectionProp;\n const projection: Projection = viewMode === 'plan' ? 'plan' : 'side';\n const showBoth = viewMode === 'both' && !_inner;\n // Special elements default to visible in the `both` view and hidden in the\n // single side / plan views; an explicit prop (or the gear toggle) overrides.\n const specialAuto = viewMode === 'both';\n const showSpecials = controls\n ? (uiSpecial ?? specialAuto)\n : (specialElementsProp ?? specialAuto);\n\n // The `ui*` seeds above only run once (at mount). If `controls` flips on\n // later, re-seed from the current props so the popover opens from the\n // consumer's latest values rather than the stale mount-time snapshot.\n const controlsWasOn = useRef(controls);\n useEffect(() => {\n if (controls && !controlsWasOn.current) {\n setUiDentition(dentitionProp);\n setUiNumbering(numberingProp);\n setUiProjection(projectionProp);\n setUiLegend(legendProp);\n setUiSpecial(specialElementsProp);\n }\n controlsWasOn.current = controls;\n }, [\n controls,\n dentitionProp,\n numberingProp,\n projectionProp,\n legendProp,\n specialElementsProp,\n ]);\n\n // Chart state — controlled / uncontrolled.\n const [internalChart, setInternalChart] = useState<ToothChart>(() => {\n if (value !== undefined) return value;\n if (defaultValue !== undefined) return defaultValue;\n if (conditions) return chartFromConditions(conditions);\n return {};\n });\n\n const chart: ToothChart = isControlled({ value })\n ? (value as ToothChart)\n : internalChart;\n\n // Keep uncontrolled chart in sync when `conditions` shortcut updates.\n useEffect(() => {\n if (isControlled({ value })) return;\n if (conditions === undefined) return;\n setInternalChart(chartFromConditions(conditions));\n // Intentionally depend on a stable key — swapping the entire prop\n // snapshot is the consumer's signal to reset.\n }, [conditions, value]);\n\n // Plan (occlusal) teeth are square; facial teeth are tall (crown + root).\n const slotHeight = projection === 'plan' ? 44 : TOOTH_SLOT_HEIGHT;\n\n // Layout — single-arch (a `both`-view sub-chart) or both arches.\n const layout = useMemo(\n () => layoutTeeth(dentition, slotHeight, _arch ? { arch: _arch } : {}),\n [dentition, slotHeight, _arch],\n );\n\n // Special-element slots positioned to the inline-end of each arch row.\n const specials = useMemo<PositionedSpecial[]>(() => {\n if (!showSpecials) return [];\n if (_arch) {\n // A `both`-view sub-chart: one arch row, specials at y = 0.\n return layoutSpecials(\n specialsForRow(dentition, _arch, projection),\n layout.width,\n ).specials;\n }\n // Single-projection chart: specials attach to both arch rows.\n const upper = layoutSpecials(\n specialsForRow(dentition, 'upper', projection),\n layout.width,\n ).specials;\n const lowerRowY = slotHeight + TOOTH_ROW_GAP;\n const lower = layoutSpecials(\n specialsForRow(dentition, 'lower', projection),\n layout.width,\n ).specials.map((s) => ({ ...s, y: lowerRowY }));\n return [...upper, ...lower];\n }, [showSpecials, _arch, dentition, projection, layout.width, slotHeight]);\n\n // The `both` view pins every sub-chart to the widest row's width (upper\n // facial carries the most columns: Q1, Q2, AS, Gen.) so all four scale\n // identically and stay column-aligned.\n const bothContentWidth = useMemo(() => {\n if (!showBoth) return undefined;\n if (!showSpecials) return layout.width;\n let max = layout.width;\n for (const arch of ['upper', 'lower'] as Arch[]) {\n for (const proj of ['side', 'plan'] as Projection[]) {\n const w = layoutSpecials(\n specialsForRow(dentition, arch, proj),\n layout.width,\n ).width;\n if (w > max) max = w;\n }\n }\n return max;\n }, [showBoth, showSpecials, dentition, layout.width]);\n\n const visibleIds = useMemo(\n () => [\n ...layout.teeth.map((tooth) => tooth.fdi),\n // Special slots join keyboard nav only when interactive — in display /\n // radiograph-open mode they are decorative (role=\"img\"), so the\n // radiograph-open keyboard path never reaches a region id.\n ...(mode === 'interactive' ? specials.map((s) => s.element.id) : []),\n ],\n [layout, specials, mode],\n );\n\n // Roving tabindex: which slot (tooth or special) owns `tabindex=\"0\"`.\n const firstId: FdiId | undefined = visibleIds[0];\n const [focusedId, setFocusedId] = useState<FdiId | undefined>(firstId);\n useEffect(() => {\n if (!focusedId || !visibleIds.includes(focusedId)) {\n setFocusedId(firstId);\n }\n }, [firstId, focusedId, visibleIds]);\n\n // Live-region announcement text.\n const [announcement, setAnnouncement] = useState<string>('');\n\n const svgRef = useRef<SVGSVGElement>(null);\n\n const commitChart = useCallback(\n (next: ToothChart) => {\n if (!isControlled({ value })) {\n setInternalChart(next);\n }\n onChange?.(next);\n },\n [onChange, value],\n );\n\n const focusToothById = useCallback((id: FdiId) => {\n const svg = svgRef.current;\n if (!svg) return;\n const node = svg.querySelector<SVGGElement>(`g[data-fdi=\"${id}\"]`);\n if (node) {\n node.focus();\n setFocusedId(id);\n }\n }, []);\n\n // A condition's display name — a registry entry carries its own translated\n // text, a built-in resolves to its `ui.toothScheme.condition.*` key.\n const labelOf = useCallback(\n (condition: ConditionId): string => {\n const label = conditionLabel(condition, conditionRegistry);\n return label.kind === 'key' ? t(label.key) : label.text;\n },\n [t, conditionRegistry],\n );\n\n // One symbol as text. Scope (the roots or surfaces it covers) and status are\n // folded in here so both reach the accessible name, the tooltip and the live\n // region together — never colour alone, and never two root canals on one\n // molar reading alike. A drill target passes `scoped: false`, since the\n // element the name belongs to already IS the scope.\n const symbolText = useCallback(\n (symbol: ToothSymbol, scoped = true): string => {\n const condition = labelOf(symbol.condition);\n const scope = !scoped\n ? ''\n : (symbol.roots?.length\n ? symbol.roots.map((root) => t(`toothScheme.root.${root}`))\n : (symbol.surfaces ?? []).map((surface) =>\n t(`toothScheme.surface.${surface}`),\n )\n ).join(', ');\n const status = symbol.status ? t(statusLabelKey(symbol.status)) : '';\n if (scope && status)\n return t('toothScheme.symbolWithScopeAndStatus', {\n condition,\n scope,\n status,\n });\n if (scope)\n return t('toothScheme.symbolWithScope', { condition, scope });\n if (status)\n return t('toothScheme.symbolWithStatus', { condition, status });\n return condition;\n },\n [labelOf, t],\n );\n\n // What one root / surface carries, for the drill target's own name.\n // `aria-pressed` there tracks the ARMED TOOL, so without this a finding\n // charted with a different tool is unreadable to a screen reader.\n const targetSuffix = useCallback(\n (\n symbols: ToothSymbol[],\n part: 'surface' | 'root',\n target: Surface | Root,\n ): string =>\n symbols\n .filter((symbol) =>\n part === 'surface'\n ? (symbol.surfaces ?? []).includes(target as Surface)\n : (symbol.roots ?? []).includes(target as Root),\n )\n .map((symbol) => `, ${symbolText(symbol, false)}`)\n .join(''),\n [symbolText],\n );\n\n // The announcement string for selecting / deselecting a tooth or element.\n const buildAnnouncement = useCallback(\n (id: FdiId, symbols: ToothSymbol[]): string => {\n const conditionText = symbols.map((s) => symbolText(s)).join(', ');\n if (isSpecialElement(id)) {\n const name = elementName(SPECIAL_BY_ID[id], t);\n return symbols.length > 0\n ? t('toothScheme.elementSelected', {\n name,\n conditions: conditionText,\n })\n : t('toothScheme.elementDeselected', { name });\n }\n return symbols.length > 0\n ? t('toothScheme.selected', { id, conditions: conditionText })\n : t('toothScheme.deselected', { id });\n },\n [symbolText, t],\n );\n\n // The ONE write path. Every edit builds a symbol list and folds it back\n // onto `conditions` / `surfaces`, so the rich and legacy shapes stay in\n // step and nothing reads a stale flat list.\n const writeSymbols = useCallback(\n (fdi: FdiId, symbols: ToothSymbol[]) => {\n const next: ToothChart = { ...chart };\n if (symbols.length === 0) {\n delete next[fdi];\n } else {\n next[fdi] = stateFromSymbols(symbols, chart[fdi]);\n }\n commitChart(next);\n },\n [chart, commitChart],\n );\n\n // As `writeSymbols`, plus the announcement + selection callback a user\n // edit owes. The imperative handle writes silently instead.\n const commitSymbols = useCallback(\n (fdi: FdiId, symbols: ToothSymbol[]) => {\n writeSymbols(fdi, symbols);\n setAnnouncement(buildAnnouncement(fdi, symbols));\n onSelect?.(fdi);\n },\n [buildAnnouncement, onSelect, writeSymbols],\n );\n\n /* ------------------------------------------------------------- */\n /* Drill-in picking — surfaces (plan) and roots (side) */\n /* ------------------------------------------------------------- */\n\n // Which layer the selected tool marks decides what a tooth drills into: a\n // surface tool (caries / filling) picks surfaces in the occlusal view, a\n // root tool (root canal, post, apicectomy) picks roots in the facial view.\n const activePart = activeCondition\n ? conditionPart(activeCondition, conditionRegistry)\n : undefined;\n const surfacePicking =\n projection === 'plan' &&\n mode === 'interactive' &&\n activePart === 'surface';\n const rootPicking =\n projection === 'side' && mode === 'interactive' && activePart === 'root';\n\n // Drill-in state: the tooth + surface zone or root the keyboard is\n // currently inside (null = tooth-level navigation, the default).\n const [drilled, setDrilled] = useState<Drill | null>(null);\n\n // End the drill if its picking mode turns off (tool / view change) OR the\n // drilled tooth leaves the layout (e.g. the dentition changes mid-drill) —\n // a stale drill would leave every tooth tabIndex=-1 and lock out keyboard.\n useEffect(() => {\n if (!drilled) return;\n const live = drilled.part === 'surface' ? surfacePicking : rootPicking;\n if (!live || !visibleIds.includes(drilled.fdi)) setDrilled(null);\n }, [surfacePicking, rootPicking, drilled, visibleIds]);\n\n const focusDrill = useCallback((drill: Drill) => {\n const selector =\n drill.part === 'surface'\n ? `path[data-fdi=\"${drill.fdi}\"][data-zone=\"${drill.zone}\"]`\n : `rect[data-fdi=\"${drill.fdi}\"][data-root=\"${drill.root}\"]`;\n svgRef.current?.querySelector<SVGGraphicsElement>(selector)?.focus();\n }, []);\n\n // Set by the user-driven exits (Escape) so focus returns to the tooth it\n // came from. The teardown above deliberately leaves it unset: a drill that\n // ends because a sibling palette changed tool must not pull focus back into\n // the chart and out from under the user.\n const restoreFocusTo = useRef<FdiId | null>(null);\n\n // Move DOM focus onto the drilled target when it changes; restore it to the\n // tooth only when an exit asked for it.\n useEffect(() => {\n if (drilled) {\n focusDrill(drilled);\n return;\n }\n const fdi = restoreFocusTo.current;\n restoreFocusTo.current = null;\n if (fdi) focusToothById(fdi);\n }, [drilled, focusDrill, focusToothById]);\n\n // `aria-pressed` on a zone / root reflects the ACTIVE TOOL, not any finding\n // — switching tools repaints every pressed state.\n const isTargetMarked = useCallback(\n (\n fdi: FdiId,\n part: 'surface' | 'root',\n target: Surface | Root,\n ): boolean => {\n if (!activeCondition) return false;\n return symbolsForTooth(chart[fdi], conditionRegistry).some(\n (symbol) =>\n symbol.condition === activeCondition &&\n (part === 'surface'\n ? (symbol.surfaces ?? []).includes(target as Surface)\n : (symbol.roots ?? []).includes(target as Root)),\n );\n },\n [activeCondition, chart, conditionRegistry],\n );\n\n const toggleTarget = useCallback(\n (fdi: FdiId, part: 'surface' | 'root', target: Surface | Root) => {\n if (!activeCondition) return;\n if (part === 'surface' ? !surfacePicking : !rootPicking) return;\n const symbols = symbolsForTooth(chart[fdi], conditionRegistry);\n commitSymbols(\n fdi,\n toggleSymbolTarget(symbols, activeCondition, part, target),\n );\n },\n [\n activeCondition,\n chart,\n commitSymbols,\n conditionRegistry,\n rootPicking,\n surfacePicking,\n ],\n );\n\n const drillInto = useCallback(\n (fdi: FdiId) => {\n const meta = FDI_TO_META[fdi];\n if (!meta) return;\n setFocusedId(fdi);\n if (surfacePicking) {\n setDrilled({ fdi, part: 'surface', zone: zonesForTooth(meta)[0] });\n return;\n }\n const roots = drillableRoots(meta);\n if (roots.length > 0) setDrilled({ fdi, part: 'root', root: roots[0] });\n },\n [surfacePicking],\n );\n\n const handleSurfaceKeyDown = useCallback(\n (event: KeyboardEvent<SVGPathElement>, fdi: FdiId, zone: SurfaceZone) => {\n const meta = FDI_TO_META[fdi];\n if (!meta) return;\n switch (event.key) {\n case 'ArrowUp':\n case 'ArrowDown':\n case 'ArrowLeft':\n case 'ArrowRight': {\n event.preventDefault();\n event.stopPropagation();\n const hasCenter = zonesForTooth(meta).includes('center');\n const nz = nextZone(zone, event.key, hasCenter);\n if (nz !== zone) setDrilled({ fdi, part: 'surface', zone: nz });\n return;\n }\n case ' ':\n case 'Enter': {\n event.preventDefault();\n event.stopPropagation();\n toggleTarget(fdi, 'surface', zoneSurface(meta, zone));\n return;\n }\n case 'Escape': {\n event.preventDefault();\n event.stopPropagation();\n restoreFocusTo.current = fdi;\n setDrilled(null);\n return;\n }\n default:\n return;\n }\n },\n [toggleTarget],\n );\n\n const handleRootKeyDown = useCallback(\n (event: KeyboardEvent<SVGRectElement>, fdi: FdiId, root: Root) => {\n const meta = FDI_TO_META[fdi];\n if (!meta) return;\n switch (event.key) {\n case 'ArrowUp':\n case 'ArrowDown':\n case 'ArrowLeft':\n case 'ArrowRight': {\n event.preventDefault();\n event.stopPropagation();\n const nr = nextRoot(root, event.key, drillableRoots(meta));\n if (nr !== root) setDrilled({ fdi, part: 'root', root: nr });\n return;\n }\n case ' ':\n case 'Enter': {\n event.preventDefault();\n event.stopPropagation();\n toggleTarget(fdi, 'root', root);\n return;\n }\n case 'Escape': {\n event.preventDefault();\n event.stopPropagation();\n restoreFocusTo.current = fdi;\n setDrilled(null);\n return;\n }\n default:\n return;\n }\n },\n [toggleTarget],\n );\n\n const rootRef = useRef<HTMLDivElement>(null);\n\n // Radiograph \"open archive\" affordance. In display mode, when an open\n // handler is provided, each tooth becomes a button that opens its film\n // archive — reusing the roving-tabindex + button wiring (no nested\n // interactivity), mutually exclusive with interactive findings-editing.\n const radiographOpenable =\n mode === 'display' && typeof onOpenRadiographs === 'function';\n // Teeth are keyboard-focusable in interactive mode OR radiograph-open mode.\n const teethFocusable = mode === 'interactive' || radiographOpenable;\n\n const handleOpenRadiographs = useCallback(\n (id: FdiId) => {\n setFocusedId(id);\n onSelect?.(id);\n onOpenRadiographs?.(id);\n },\n [onSelect, onOpenRadiographs],\n );\n\n const agentHandle = useMemo<ToothSchemeHandle>(\n () => ({\n focusTooth: (id: FdiId) => {\n focusToothById(id);\n },\n getChart: () => chart,\n getTooth: (id: FdiId) =>\n symbolsForTooth(chart[id], conditionRegistry)\n .map((symbol) => symbol.condition)\n .filter(isBuiltInCondition),\n getSymbols: (id: FdiId) =>\n symbolsForTooth(chart[id], conditionRegistry),\n teethWith: (condition: ToothCondition) =>\n Object.keys(chart).filter((fdi) =>\n symbolsForTooth(chart[fdi], conditionRegistry).some(\n (symbol) => symbol.condition === condition,\n ),\n ),\n teethWithSymbol: (condition: ConditionId) =>\n Object.keys(chart).filter((fdi) =>\n symbolsForTooth(chart[fdi], conditionRegistry).some(\n (symbol) => symbol.condition === condition,\n ),\n ),\n setFinding: (\n id: FdiId,\n condition: ToothCondition,\n surfaces?: Surface[],\n ) => {\n const symbols = symbolsForTooth(chart[id], conditionRegistry);\n const index = symbols.findIndex(\n (symbol) => symbol.condition === condition,\n );\n if (index >= 0 && !surfaces) return;\n const part = conditionPart(condition, conditionRegistry);\n writeSymbols(\n id,\n index >= 0\n ? symbols.map((symbol, i) =>\n i === index ? { ...symbol, surfaces } : symbol,\n )\n : [...symbols, { condition, part, surfaces }],\n );\n },\n setSymbol: (id: FdiId, symbol: ToothSymbol) => {\n const symbols = symbolsForTooth(chart[id], conditionRegistry);\n const index = symbol.id\n ? symbols.findIndex((entry) => entry.id === symbol.id)\n : symbols.findIndex(\n (entry) => entry.condition === symbol.condition,\n );\n writeSymbols(\n id,\n index >= 0\n ? symbols.map((entry, i) => (i === index ? symbol : entry))\n : [...symbols, symbol],\n );\n },\n removeFinding: (id: FdiId, condition: ToothCondition) => {\n const symbols = symbolsForTooth(chart[id], conditionRegistry);\n const next = symbols.filter(\n (symbol) => symbol.condition !== condition,\n );\n if (next.length === symbols.length) return;\n writeSymbols(id, next);\n },\n clearTooth: (id: FdiId) => {\n if (!chart[id]) return;\n const next: ToothChart = { ...chart };\n delete next[id];\n commitChart(next);\n },\n getRadiographs: (id: FdiId) => radiographs?.[id] ?? [],\n teethWithRadiographs: () =>\n Object.keys(radiographs ?? {}).filter(\n (fdi) => (radiographs?.[fdi]?.length ?? 0) > 0,\n ),\n openRadiographs: (id: FdiId) => {\n focusToothById(id);\n handleOpenRadiographs(id);\n },\n }),\n [\n chart,\n commitChart,\n conditionRegistry,\n focusToothById,\n radiographs,\n handleOpenRadiographs,\n writeSymbols,\n ],\n );\n useImperativeHandle(ref, () => agentHandle, [agentHandle]);\n // Only the outer chart registers with the agent registry; the inner\n // `both`-view sub-charts share its chart data and pass no id, so the\n // registration is a no-op for them (guarded on a truthy instanceId).\n useAgentRegistration(\n toothSchemeAgent,\n agentHandle,\n _inner ? undefined : id,\n );\n\n /* ------------------------------------------------------------- */\n /* Keyboard navigation */\n /* ------------------------------------------------------------- */\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<SVGGElement>, id: FdiId) => {\n if (!teethFocusable) return;\n // `meta` is undefined for a special-element slot — those skip the\n // tooth-only vertical / quadrant navigation but keep linear nav + activation.\n const meta = FDI_TO_META[id];\n\n // Resolve the ordered list of visible ids for Left/Right.\n const order = visibleIds;\n const currentIndex = order.indexOf(id);\n\n switch (event.key) {\n case 'ArrowRight': {\n event.preventDefault();\n const nextIndex = Math.min(order.length - 1, currentIndex + 1);\n focusToothById(order[nextIndex]);\n return;\n }\n case 'ArrowLeft': {\n event.preventDefault();\n const nextIndex = Math.max(0, currentIndex - 1);\n focusToothById(order[nextIndex]);\n return;\n }\n case 'ArrowUp':\n case 'ArrowDown': {\n event.preventDefault();\n if (!meta) return;\n // Map to the opposing arch, same FDI position where possible.\n // Permanent: 1 ↔ 4, 2 ↔ 3. Primary: 5 ↔ 8, 6 ↔ 7.\n const quadrantMap: Record<number, number> = {\n 1: 4,\n 4: 1,\n 2: 3,\n 3: 2,\n 5: 8,\n 8: 5,\n 6: 7,\n 7: 6,\n };\n const targetQuadrant = quadrantMap[meta.quadrant];\n if (!targetQuadrant) return;\n const candidate = `${targetQuadrant}${meta.positionInQuadrant}`;\n if (order.includes(candidate)) {\n focusToothById(candidate);\n }\n return;\n }\n case 'Home': {\n event.preventDefault();\n if (!meta) return;\n // First tooth in the same quadrant (visible).\n const inQuadrant = order.filter(\n (other) => FDI_TO_META[other]?.quadrant === meta.quadrant,\n );\n if (inQuadrant.length > 0) {\n focusToothById(inQuadrant[0]);\n }\n return;\n }\n case 'End': {\n event.preventDefault();\n if (!meta) return;\n const inQuadrant = order.filter(\n (other) => FDI_TO_META[other]?.quadrant === meta.quadrant,\n );\n if (inQuadrant.length > 0) {\n focusToothById(inQuadrant[inQuadrant.length - 1]);\n }\n return;\n }\n case ' ':\n case 'Enter': {\n event.preventDefault();\n // Radiograph-open mode: Enter/Space opens the tooth's film archive\n // rather than editing findings.\n if (radiographOpenable) {\n handleOpenRadiographs(id);\n return;\n }\n // In a picking mode, Enter drills into the tooth's surfaces or\n // roots rather than toggling the whole tooth (teeth only, and only\n // where there is something to choose between).\n if (\n meta &&\n (surfacePicking ||\n (rootPicking && drillableRoots(meta).length > 0))\n ) {\n drillInto(id);\n return;\n }\n commitSymbols(\n id,\n toggleSymbolCondition(\n symbolsForTooth(chart[id], conditionRegistry),\n activeCondition,\n conditionRegistry,\n ),\n );\n return;\n }\n default:\n return;\n }\n },\n [\n activeCondition,\n chart,\n commitSymbols,\n conditionRegistry,\n drillInto,\n focusToothById,\n handleOpenRadiographs,\n radiographOpenable,\n rootPicking,\n surfacePicking,\n teethFocusable,\n visibleIds,\n ],\n );\n\n const handleClick = useCallback(\n (id: FdiId) => {\n if (mode !== 'interactive') return;\n setFocusedId(id);\n commitSymbols(\n id,\n toggleSymbolCondition(\n symbolsForTooth(chart[id], conditionRegistry),\n activeCondition,\n conditionRegistry,\n ),\n );\n },\n [activeCondition, chart, commitSymbols, conditionRegistry, mode],\n );\n\n // The whole-mouth `general` element is a switch beneath the chart (not a\n // column). It carries the active finding (or caries by default) across the\n // whole mouth — on records it, off clears it.\n const generalId: FdiId = dentition === 'primary' ? 'mGeneral' : 'general';\n const generalChecked =\n symbolsForTooth(chart[generalId], conditionRegistry).length > 0;\n const toggleGeneral = useCallback(\n (checked: boolean) => {\n const condition: ConditionId = activeCondition ?? 'caries';\n commitSymbols(\n generalId,\n checked\n ? [{ condition, part: conditionPart(condition, conditionRegistry) }]\n : [],\n );\n },\n [activeCondition, commitSymbols, conditionRegistry, generalId],\n );\n\n /* ------------------------------------------------------------- */\n /* Rendering */\n /* ------------------------------------------------------------- */\n\n // Number-label headroom: `above` lifts numbers over the crowns (negative y),\n // `below` drops them under (past the slot); the single-view `between`\n // placement keeps numbers in the inter-arch gap, so it needs no extra pad.\n const topPad = _numbersPosition === 'above' ? 16 : 2;\n const bottomPad = _numbersPosition === 'below' ? 16 : 2;\n const specialsWidth =\n specials.length > 0\n ? Math.max(...specials.map((s) => s.x)) + SPECIAL_SLOT_WIDTH\n : 0;\n // `_contentWidth` (set on the four `both`-view sub-charts) pins every row to\n // one width so they scale identically; otherwise each row sizes to its own\n // content and a row with fewer special columns would render larger.\n const contentWidth = Math.max(\n _contentWidth ?? 0,\n layout.width,\n specialsWidth,\n );\n const viewBoxWidth = contentWidth + 4;\n const viewBoxHeight = layout.height + topPad + bottomPad;\n\n const baseLabel = ariaLabel ?? t('toothScheme.ariaLabel');\n\n // The root is horizontally scrollable (`overflow-x-auto`), so it needs\n // keyboard access. In interactive mode the roving-tabindex teeth supply\n // it; in display mode nothing inside is focusable, so the scroll\n // container itself becomes the tab stop (WCAG 2.1.1 / axe\n // scrollable-region-focusable).\n const scrollTabIndex = teethFocusable ? undefined : 0;\n\n // The chart `<svg>` — reused for the single-projection view (this instance)\n // and each `both`-view sub-chart (an `_inner` instance). Built only when\n // this instance renders its own teeth (i.e. NOT the `both`-view outer host).\n const chartSvg = showBoth ? null : (\n <svg\n ref={svgRef}\n viewBox={`0 ${-topPad} ${viewBoxWidth} ${viewBoxHeight}`}\n width={viewBoxWidth}\n height={viewBoxHeight}\n className={svgVariants()}\n role=\"group\"\n aria-label={baseLabel}\n // Never a tab stop itself — keyboard focus lives on the teeth\n // (interactive) or the scroll container (display). Legacy engines\n // make a labelled SVG focusable without this.\n focusable=\"false\"\n data-testid=\"tooth-scheme-svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n {layout.teeth.map((tooth) => {\n // ONE read path: legacy `conditions` + `surfaces` and the rich\n // `symbols` list both arrive here as symbols, each scoping its own\n // surfaces and roots.\n const symbols = symbolsForTooth(chart[tooth.fdi], conditionRegistry);\n const primaryCondition: ConditionId | undefined =\n symbols[0]?.condition;\n\n const anatomyLabel = t(`toothScheme.anatomy.${tooth.meta.anatomy}`);\n // EVERY symbol is named, not just the first — a tooth carrying two\n // findings used to paint two glyphs and report one.\n const conditionSuffix = symbols\n .map((symbol) => `, ${symbolText(symbol)}`)\n .join('');\n const toothRadiographs = radiographs?.[tooth.fdi] ?? [];\n const radiographCount = toothRadiographs.length;\n const hasRadiographs = radiographCount > 0;\n // Most-recent film (newest date first; undated sink last) drives\n // the thumbnail + tooltip.\n const latestRadiograph = hasRadiographs\n ? [...toothRadiographs].sort(sortByDateDesc)[0]\n : undefined;\n const showThumbnail =\n radiographDisplay === 'thumbnail' && latestRadiograph !== undefined;\n // Surface the radiograph count to AT via the accessible name so\n // it is announced, not signalled by the corner badge alone.\n const radiographSuffix = hasRadiographs\n ? `, ${t('toothScheme.radiographBadge', { count: radiographCount })}`\n : '';\n // In the `both` view the same tooth renders in a facial AND an\n // occlusal sub-chart — fold the projection into the name so a screen\n // reader can tell the two apart (a `role=\"group\"` name is not reliably\n // announced on a focused SVG descendant).\n const projectionSuffix = _inner\n ? `, ${\n projection === 'plan'\n ? t('toothScheme.view.occlusal')\n : t('toothScheme.view.side')\n }`\n : '';\n const label =\n t('toothScheme.toothLabel', {\n id: labelFor(tooth.fdi, numbering),\n anatomy: anatomyLabel,\n conditionSuffix,\n }) +\n radiographSuffix +\n projectionSuffix;\n\n const tabIndex = teethFocusable\n ? drilled\n ? -1\n : tooth.fdi === focusedId\n ? 0\n : -1\n : undefined;\n\n const isMissing = symbols.some(\n (symbol) => symbol.condition === 'missing',\n );\n // Whole-tooth findings (crown, implant, RCT…) overlay a photoreal\n // symbol render, resolved per projection so the occlusal view no\n // longer drops them. A symbol scoped to roots paints one per root.\n const symbolOverlays = symbols.flatMap((symbol, index) => {\n const spec =\n projection === 'side'\n ? conditionSideSymbol(symbol.condition, conditionRegistry)\n : conditionPlanSymbol(symbol.condition, conditionRegistry);\n if (!spec) return [];\n const roots: (Root | undefined)[] = symbol.roots?.length\n ? symbol.roots\n : [undefined];\n // `region` picks the placement of a gingival-surgery marker\n // (left / right / total / repeat); without it every one of them\n // resolves to `repeat`.\n return roots.map((root) => ({\n key: `${index}-${symbol.condition}-${root ?? 'whole'}`,\n url:\n projection === 'side'\n ? conditionSymbolUrl(tooth.meta, assetBaseUrl, spec, {\n root,\n region: symbol.region,\n })\n : planSymbolUrl(tooth.meta, assetBaseUrl, spec, {\n root,\n region: symbol.region,\n }),\n opacity: symbol.status ? STATUS_OPACITY[symbol.status] : 1,\n }));\n });\n // A finding with no artwork in this projection falls back to its\n // glyph badge — the seam that lets a practice-defined finding chart\n // before a designer draws it.\n const glyphMarks = symbols\n .filter(\n (symbol) =>\n !conditionHasArtwork(\n symbol.condition,\n projection,\n conditionRegistry,\n ),\n )\n .map((symbol, index) => ({\n key: `${symbol.condition}-${index}`,\n condition: symbol.condition,\n glyph: conditionGlyph(symbol.condition, conditionRegistry),\n colour: symbolColor(symbol, conditionRegistry),\n opacity: symbol.status ? STATUS_OPACITY[symbol.status] : 1,\n }));\n // Surface findings (caries / filled) have no side symbol — flag\n // them with a token-coloured ring in the facial view.\n const ringSymbol = symbols.find(\n (symbol) =>\n symbol.condition !== 'missing' &&\n !conditionSideSymbol(symbol.condition, conditionRegistry) &&\n conditionHasArtwork(symbol.condition, 'side', conditionRegistry),\n );\n const ringColour = ringSymbol\n ? symbolColor(ringSymbol, conditionRegistry)\n : undefined;\n // Planned vs executed: the token colour rides on a pip whose SHAPE\n // also differs, and the symbols themselves render lighter when\n // planned. One pip per distinct status on the tooth.\n const statuses = STATUS_ORDER.filter((status) =>\n symbols.some((symbol) => symbol.status === status),\n );\n\n const tooltipContent =\n (symbols.length > 0\n ? `${anatomyLabel} · ${symbols.map((s) => symbolText(s)).join(' · ')}`\n : anatomyLabel) +\n (hasRadiographs\n ? ` · ${t('toothScheme.radiographBadge', { count: radiographCount })}`\n : '');\n\n const labelText = labelFor(tooth.fdi, numbering);\n const imageUrl = toothImageUrl(\n tooth.meta,\n assetBaseUrl,\n 'default',\n projection,\n );\n // In thumbnail display the most-recent film fills the slot\n // (cropped via `slice`) in place of the photoreal render.\n const slotImageHref =\n showThumbnail && latestRadiograph\n ? (latestRadiograph.thumbnailUrl ?? latestRadiograph.url)\n : imageUrl;\n // Plan (occlusal) view: per-surface caries / filling overlays — the\n // \"Stato dentale\" surface marking. Each symbol paints only ITS OWN\n // surfaces, so a mesial filling and a distal one stay apart.\n const surfaceOverlays =\n projection === 'plan'\n ? symbols.flatMap((symbol, index) => {\n const folder = conditionPlanFolder(\n symbol.condition,\n conditionRegistry,\n );\n if (!folder) return [];\n return (symbol.surfaces ?? []).map((surface) => ({\n key: `${index}-${symbol.condition}-${surface}`,\n url: surfaceSymbolUrl(\n tooth.meta,\n assetBaseUrl,\n folder,\n surface,\n ),\n opacity: symbol.status ? STATUS_OPACITY[symbol.status] : 1,\n }));\n })\n : [];\n\n // Primary teeth reuse the permanent render scaled down. A small\n // inset on every tooth keeps the render off the slot edges so\n // the focus ring + labels never crowd or touch it.\n const imgScale =\n (tooth.meta.dentition === 'primary' ? PRIMARY_TOOTH_SCALE : 1) *\n 0.9;\n const imgW = TOOTH_SLOT_WIDTH * imgScale;\n const imgH = slotHeight * imgScale;\n const imgX = (TOOTH_SLOT_WIDTH - imgW) / 2;\n const imgY = (slotHeight - imgH) / 2;\n\n // Picking targets — surface zones (plan) or root strips (side).\n // Drilled into THIS tooth they become the focusable buttons and the\n // tooth group steps back to a container (no nested interactive).\n const surfaceDrilled =\n drilled?.part === 'surface' && drilled.fdi === tooth.fdi;\n const rootDrilled =\n drilled?.part === 'root' && drilled.fdi === tooth.fdi;\n const isDrilled = surfaceDrilled || rootDrilled;\n const toothZones = surfacePicking ? zonesForTooth(tooth.meta) : [];\n const hasCenter = toothZones.includes('center');\n // Single-rooted teeth are never drillable — there is nothing to pick.\n const toothRoots = rootPicking ? drillableRoots(tooth.meta) : [];\n // Activating this tooth opens its sub-level instead of toggling it,\n // so it must advertise `aria-expanded`, not a `aria-pressed` state it\n // never honours.\n const drillsIn = toothZones.length > 0 || toothRoots.length > 0;\n\n // Number-label y per the sub-chart's number placement.\n const numberY =\n _numbersPosition === 'above'\n ? -4\n : _numbersPosition === 'below'\n ? slotHeight + 12\n : _numbersPosition === 'none'\n ? null\n : tooth.meta.arch === 'upper'\n ? slotHeight + 12\n : -4;\n\n return (\n <RadixTooltip.Root key={tooth.fdi}>\n <RadixTooltip.Trigger asChild>\n <g\n data-fdi={tooth.fdi}\n data-anatomy={tooth.meta.anatomy}\n data-arch={tooth.meta.arch}\n data-side={tooth.meta.side}\n data-quadrant={tooth.meta.quadrant}\n data-condition={primaryCondition ?? 'none'}\n // `data-condition` keeps its first-finding semantics; the\n // symbol-aware attributes sit alongside it rather than\n // repurposing it.\n data-symbol-count={symbols.length}\n data-conditions={\n symbols.length > 0\n ? symbols.map((symbol) => symbol.condition).join(' ')\n : undefined\n }\n data-status={symbols[0]?.status}\n data-testid={`tooth-${tooth.fdi}`}\n transform={`translate(${tooth.x}, ${tooth.y})`}\n tabIndex={tabIndex}\n // SVG `<g>` has no implicit role, so `aria-label`\n // would be rejected by axe's `aria-prohibited-attr`\n // rule. Give it an explicit role: `button` in\n // interactive mode, `img` in display mode. When drilled\n // into for surface picking it becomes a `group` so its\n // focusable surface zones aren't nested in a button.\n role={isDrilled ? 'group' : teethFocusable ? 'button' : 'img'}\n aria-label={label}\n aria-pressed={\n isDrilled || drillsIn\n ? undefined\n : mode === 'interactive'\n ? primaryCondition !== undefined\n : undefined\n }\n aria-expanded={\n !isDrilled && drillsIn && teethFocusable ? false : undefined\n }\n className={toothGroupVariants()}\n onClick={\n isDrilled\n ? undefined\n : mode === 'interactive'\n ? surfacePicking || toothRoots.length > 0\n ? () => drillInto(tooth.fdi)\n : () => handleClick(tooth.fdi)\n : radiographOpenable\n ? () => handleOpenRadiographs(tooth.fdi)\n : undefined\n }\n onFocus={() => setFocusedId(tooth.fdi)}\n onKeyDown={\n isDrilled\n ? undefined\n : (event) => handleKeyDown(event, tooth.fdi)\n }\n >\n {/* Invisible ≥44px hit target (WCAG 2.5.5). */}\n <rect\n x={-TOOTH_HIT_PAD}\n y={-TOOTH_HIT_PAD}\n width={TOOTH_SLOT_WIDTH + TOOTH_HIT_PAD * 2}\n height={slotHeight + TOOTH_HIT_PAD * 2}\n fill=\"transparent\"\n />\n {/* Photoreal tooth render (side = facial, plan =\n occlusal). The upper/lower view folders are\n pre-oriented, so no mirroring is needed. Decorative —\n the parent <g> carries the accessible name. */}\n <image\n href={slotImageHref}\n x={imgX}\n y={imgY}\n width={imgW}\n height={imgH}\n preserveAspectRatio={\n showThumbnail ? 'xMidYMid slice' : 'xMidYMid meet'\n }\n opacity={isMissing && !showThumbnail ? 0.25 : 1}\n aria-hidden=\"true\"\n />\n {/* Whole-tooth symbol overlays (crown, implant, RCT,\n bridge…) in BOTH projections. The distinct glyph is\n the colour-independent channel; the group's\n accessible name names it. Width / height are forced —\n the plan canvases are not all one size, so intrinsic\n sizing would drift. */}\n {symbolOverlays.map(({ key, url, opacity }) => {\n // A handful of plan renders ship on a larger canvas, so\n // fitting them into the base rect lands them inset. Scale\n // by the ratio, about the same centre.\n const scale =\n projection === 'plan' ? planOverlayScale(url) : 1;\n const w = imgW * scale;\n const h = imgH * scale;\n return (\n <image\n key={key}\n href={url}\n x={imgX - (w - imgW) / 2}\n y={imgY - (h - imgH) / 2}\n width={w}\n height={h}\n preserveAspectRatio=\"xMidYMid meet\"\n opacity={opacity}\n aria-hidden=\"true\"\n pointerEvents=\"none\"\n />\n );\n })}\n {/* Plan view: per-surface caries / filling overlays —\n the \"Stato dentale\" surface marking. */}\n {surfaceOverlays.map(({ key, url, opacity }) => (\n <image\n key={key}\n href={url}\n x={imgX}\n y={imgY}\n width={imgW}\n height={imgH}\n preserveAspectRatio=\"xMidYMid meet\"\n opacity={opacity}\n aria-hidden=\"true\"\n pointerEvents=\"none\"\n />\n ))}\n {/* Registry findings with no artwork yet — a glyph badge\n stacked down the middle of the slot. */}\n {glyphMarks.map(\n ({ key, condition, glyph, colour, opacity }, index) => (\n <GlyphMark\n key={key}\n glyph={glyph}\n colour={colour}\n opacity={opacity}\n cx={TOOTH_SLOT_WIDTH / 2}\n cy={slotHeight / 2 + index * 16}\n testId={`tooth-${tooth.fdi}-glyph-${condition}`}\n />\n ),\n )}\n {/* Plan view: interactive surface-picking zones. Pointer\n clicks mark a surface directly; keyboard users drill\n in (Enter) then pick a zone (arrows), so the zones are\n focusable buttons only while THIS tooth is drilled. */}\n {toothZones.map((zone) => {\n const surface = zoneSurface(tooth.meta, zone);\n const marked = isTargetMarked(\n tooth.fdi,\n 'surface',\n surface,\n );\n return (\n <path\n key={zone}\n d={zonePath(\n zone,\n { x: imgX, y: imgY, w: imgW, h: imgH },\n hasCenter,\n )}\n data-fdi={tooth.fdi}\n data-zone={zone}\n data-surface={surface}\n data-testid={`tooth-${tooth.fdi}-zone-${zone}`}\n role={surfaceDrilled ? 'button' : undefined}\n tabIndex={\n surfaceDrilled\n ? drilled?.part === 'surface' &&\n drilled.zone === zone\n ? 0\n : -1\n : undefined\n }\n aria-label={\n surfaceDrilled\n ? t('toothScheme.toothLabel', {\n id: labelText,\n anatomy: t(`toothScheme.surface.${surface}`),\n conditionSuffix: targetSuffix(\n symbols,\n 'surface',\n surface,\n ),\n })\n : undefined\n }\n aria-pressed={surfaceDrilled ? marked : undefined}\n strokeWidth=\"var(--focus-ring-width)\"\n className={zoneVariants()}\n onClick={(event) => {\n event.stopPropagation();\n if (!surfaceDrilled) setFocusedId(tooth.fdi);\n toggleTarget(tooth.fdi, 'surface', surface);\n }}\n onKeyDown={\n surfaceDrilled\n ? (event) =>\n handleSurfaceKeyDown(event, tooth.fdi, zone)\n : undefined\n }\n onFocus={\n surfaceDrilled\n ? () =>\n setDrilled((d) =>\n d &&\n d.part === 'surface' &&\n d.fdi === tooth.fdi &&\n d.zone === zone\n ? d\n : { fdi: tooth.fdi, part: 'surface', zone },\n )\n : undefined\n }\n />\n );\n })}\n {/* Side view: per-root picking strips over the root half\n of the render (roots point away from the occlusal\n plane). Same contract as the surface zones — pointer\n users click a root, keyboard users drill in first. */}\n {toothRoots.map((root, index) => {\n const rect = rootRect(index, toothRoots.length, {\n x: imgX,\n y: imgY,\n w: imgW,\n h: imgH,\n });\n const marked = isTargetMarked(tooth.fdi, 'root', root);\n return (\n <rect\n key={root}\n x={rect.x}\n y={rect.y}\n width={rect.w}\n height={rect.h}\n rx=\"2\"\n data-fdi={tooth.fdi}\n data-root={root}\n data-testid={`tooth-${tooth.fdi}-root-${root}`}\n role={rootDrilled ? 'button' : undefined}\n tabIndex={\n rootDrilled\n ? drilled?.part === 'root' && drilled.root === root\n ? 0\n : -1\n : undefined\n }\n aria-label={\n rootDrilled\n ? t('toothScheme.toothLabel', {\n id: labelText,\n anatomy: t(`toothScheme.root.${root}`),\n conditionSuffix: targetSuffix(\n symbols,\n 'root',\n root,\n ),\n })\n : undefined\n }\n aria-pressed={rootDrilled ? marked : undefined}\n strokeWidth=\"var(--focus-ring-width)\"\n className={zoneVariants()}\n onClick={(event) => {\n event.stopPropagation();\n if (!rootDrilled) setFocusedId(tooth.fdi);\n toggleTarget(tooth.fdi, 'root', root);\n }}\n onKeyDown={\n rootDrilled\n ? (event) =>\n handleRootKeyDown(event, tooth.fdi, root)\n : undefined\n }\n onFocus={\n rootDrilled\n ? () =>\n setDrilled((d) =>\n d &&\n d.part === 'root' &&\n d.fdi === tooth.fdi &&\n d.root === root\n ? d\n : { fdi: tooth.fdi, part: 'root', root },\n )\n : undefined\n }\n />\n );\n })}\n {/* Side view: surface-finding ring (caries / filled)\n stands in until the plan view marks the surface. */}\n {projection === 'side' && ringColour ? (\n <rect\n x={3}\n y={2}\n width={TOOTH_SLOT_WIDTH - 6}\n height={slotHeight - 4}\n fill=\"none\"\n stroke={ringColour}\n strokeWidth=\"2\"\n // Distinguish caries (solid) from filled (dashed) by\n // line style, not colour alone (WCAG 1.4.1).\n strokeDasharray={\n ringSymbol?.condition === 'filled' ? '4 2' : undefined\n }\n rx=\"6\"\n pointerEvents=\"none\"\n />\n ) : null}\n {/* Execution-status pips — the status token colour paired\n with a shape (ring = planned, disc = executed), never\n the colour on its own. The status is also spoken in\n the tooth's accessible name and shown in the tooltip. */}\n {statuses.map((status, index) => (\n <StatusDot\n key={status}\n status={status}\n cx={5 + index * 9}\n cy={5}\n r={3.25}\n strokeWidth={1.25}\n testId={`tooth-${tooth.fdi}-status-${status}`}\n />\n ))}\n {/* Missing-tooth X glyph over the faded render. */}\n {isMissing ? (\n <path\n d={`M7 9 L${TOOTH_SLOT_WIDTH - 7} ${slotHeight - 9} M${TOOTH_SLOT_WIDTH - 7} 9 L7 ${slotHeight - 9}`}\n stroke={CONDITION_COLORS.missing}\n strokeWidth=\"2\"\n fill=\"none\"\n pointerEvents=\"none\"\n />\n ) : null}\n {/* Thumbnail-mode frame — a token border so the x-ray\n reads as a framed film rather than a tooth render. */}\n {showThumbnail ? (\n <rect\n x={imgX}\n y={imgY}\n width={imgW}\n height={imgH}\n fill=\"none\"\n stroke=\"var(--border)\"\n strokeWidth=\"1\"\n rx=\"3\"\n pointerEvents=\"none\"\n />\n ) : null}\n {/* Radiograph count badge — bottom-inline-end corner.\n Decorative (aria-hidden); the count is announced via\n the tooth's accessible name. An opaque --card chip\n keeps the count legible over the photoreal render. */}\n {hasRadiographs ? (\n <g\n data-testid={`tooth-${tooth.fdi}-radiograph-badge`}\n data-radiograph-count={radiographCount}\n transform={`translate(${TOOTH_SLOT_WIDTH - (radiographCount >= 10 ? 19 : 15)}, ${slotHeight - 13})`}\n pointerEvents=\"none\"\n aria-hidden=\"true\"\n >\n <rect\n width={radiographCount >= 10 ? 17 : 13}\n height={12}\n rx=\"3.5\"\n fill=\"var(--card)\"\n stroke=\"var(--info-foreground)\"\n strokeWidth=\"0.75\"\n />\n <text\n x={(radiographCount >= 10 ? 17 : 13) / 2}\n y={9}\n textAnchor=\"middle\"\n fontSize=\"9\"\n fontWeight=\"600\"\n fill=\"var(--info-foreground)\"\n className=\"ds:select-none\"\n >\n {radiographCount}\n </text>\n </g>\n ) : null}\n {/* Focus ring — drawn as a rect so it tracks the hit\n area. `group` on the parent <g> makes this\n group-focus-visible selector fire when a keyboard\n user focuses the tooth. In forced-colors mode the\n ring falls back to `CanvasText` so it stays visible\n when `var(--ring)` is remapped. */}\n <rect\n x={-TOOTH_HIT_PAD}\n y={-TOOTH_HIT_PAD}\n width={TOOTH_SLOT_WIDTH + TOOTH_HIT_PAD * 2}\n height={slotHeight + TOOTH_HIT_PAD * 2}\n fill=\"none\"\n stroke=\"var(--ring)\"\n strokeWidth=\"var(--focus-ring-width)\"\n className={[\n 'ds:opacity-0',\n 'ds:group-focus-visible:opacity-100',\n 'ds:forced-colors:stroke-[CanvasText]',\n ].join(' ')}\n data-testid={`tooth-${tooth.fdi}-focus-ring`}\n pointerEvents=\"none\"\n rx=\"4\"\n />\n {/* Tooth number label — placement follows the sub-chart's\n number position (`above` / `below` / between arches). */}\n {numberY !== null ? (\n <text\n x={TOOTH_SLOT_WIDTH / 2}\n y={numberY}\n textAnchor=\"middle\"\n fontSize=\"10\"\n fill=\"var(--muted-foreground)\"\n className=\"ds:select-none\"\n aria-hidden=\"true\"\n >\n {labelText}\n </text>\n ) : null}\n </g>\n </RadixTooltip.Trigger>\n <RadixTooltip.Portal>\n <RadixTooltip.Content\n side=\"top\"\n sideOffset={6}\n className=\"ds:z-[var(--z-tooltip)] ds:rounded-[var(--radius-sm)] ds:bg-[var(--foreground)] ds:text-[var(--background)] ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)] ds:pt-[calc(var(--spacing-xs)/2)] ds:pb-[calc(var(--spacing-xs)/2)] ds:text-[length:var(--font-size-xs)]\"\n >\n {tooltipContent}\n <RadixTooltip.Arrow className=\"ds:fill-[var(--foreground)]\" />\n </RadixTooltip.Content>\n </RadixTooltip.Portal>\n </RadixTooltip.Root>\n );\n })}\n\n {/* Special elements — selectable quadrant / sextant / arch / whole-mouth\n slots. A label block: outline when empty, accent-tinted with a\n condition-coloured border when a finding is recorded (fill state is\n the colour-independent channel; the finding is also in the name). */}\n {specials.map(({ element, x, y }) => {\n const elementSymbols = symbolsForTooth(\n chart[element.id],\n conditionRegistry,\n );\n const primary = elementSymbols[0];\n const cond = primary?.condition;\n const selected = cond !== undefined;\n const name = elementName(element, t);\n const conditionSuffix = elementSymbols\n .map((symbol) => `, ${symbolText(symbol)}`)\n .join('');\n const label = t('toothScheme.elementLabel', {\n name,\n conditionSuffix,\n });\n const condColour = primary\n ? symbolColor(primary, conditionRegistry)\n : undefined;\n // Quadrants / arches / general render a photoreal icon (matching the\n // platform); sextants are label-only.\n const iconUrl = specialIconUrl(element, assetBaseUrl);\n // Region slots are selectable only in interactive mode — never\n // filmable, so they stay decorative in display / radiograph-open mode.\n const elementInteractive = mode === 'interactive';\n const tabIndex = elementInteractive\n ? element.id === focusedId\n ? 0\n : -1\n : undefined;\n\n return (\n <RadixTooltip.Root key={element.id}>\n <RadixTooltip.Trigger asChild>\n <g\n data-fdi={element.id}\n data-special={element.kind}\n data-arch={element.arch}\n data-condition={cond ?? 'none'}\n data-testid={`element-${element.id}`}\n transform={`translate(${x}, ${y})`}\n tabIndex={tabIndex}\n role={elementInteractive ? 'button' : 'img'}\n aria-label={label}\n aria-pressed={elementInteractive ? selected : undefined}\n className={toothGroupVariants()}\n onClick={\n elementInteractive\n ? () => handleClick(element.id)\n : undefined\n }\n onFocus={\n elementInteractive\n ? () => setFocusedId(element.id)\n : undefined\n }\n onKeyDown={\n elementInteractive\n ? (event) => handleKeyDown(event, element.id)\n : undefined\n }\n >\n {/* Invisible ≥44px hit target. */}\n <rect\n x={-TOOTH_HIT_PAD}\n y={-TOOTH_HIT_PAD}\n width={SPECIAL_SLOT_WIDTH + TOOTH_HIT_PAD * 2}\n height={slotHeight + TOOTH_HIT_PAD * 2}\n fill=\"transparent\"\n />\n <rect\n x={0}\n y={0}\n width={SPECIAL_SLOT_WIDTH}\n height={slotHeight}\n rx={6}\n fill={selected ? 'var(--accent)' : 'var(--card)'}\n fillOpacity={selected ? 0.16 : 1}\n stroke={condColour ?? 'var(--border)'}\n strokeWidth={selected ? 2 : 1}\n />\n {iconUrl ? (\n <>\n {/* Photoreal region icon (quadrant / arch / general). */}\n <image\n href={iconUrl}\n x={3}\n y={3}\n width={SPECIAL_SLOT_WIDTH - 6}\n height={slotHeight - 16}\n preserveAspectRatio=\"xMidYMid meet\"\n aria-hidden=\"true\"\n pointerEvents=\"none\"\n />\n <text\n x={SPECIAL_SLOT_WIDTH / 2}\n y={slotHeight - 4}\n textAnchor=\"middle\"\n fontSize=\"9\"\n fontWeight=\"600\"\n fill=\"var(--muted-foreground)\"\n className=\"ds:select-none\"\n aria-hidden=\"true\"\n >\n {element.code}\n </text>\n </>\n ) : (\n <text\n x={SPECIAL_SLOT_WIDTH / 2}\n y={slotHeight / 2}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n fontSize=\"11\"\n fontWeight=\"600\"\n fill=\"var(--foreground)\"\n className=\"ds:select-none\"\n aria-hidden=\"true\"\n >\n {element.code}\n </text>\n )}\n {/* Focus ring. */}\n <rect\n x={-TOOTH_HIT_PAD}\n y={-TOOTH_HIT_PAD}\n width={SPECIAL_SLOT_WIDTH + TOOTH_HIT_PAD * 2}\n height={slotHeight + TOOTH_HIT_PAD * 2}\n fill=\"none\"\n stroke=\"var(--ring)\"\n strokeWidth=\"var(--focus-ring-width)\"\n className={[\n 'ds:opacity-0',\n 'ds:group-focus-visible:opacity-100',\n 'ds:forced-colors:stroke-[CanvasText]',\n ].join(' ')}\n data-testid={`element-${element.id}-focus-ring`}\n pointerEvents=\"none\"\n rx=\"6\"\n />\n </g>\n </RadixTooltip.Trigger>\n <RadixTooltip.Portal>\n <RadixTooltip.Content\n side=\"top\"\n sideOffset={6}\n className=\"ds:z-[var(--z-tooltip)] ds:rounded-[var(--radius-sm)] ds:bg-[var(--foreground)] ds:text-[var(--background)] ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)] ds:pt-[calc(var(--spacing-xs)/2)] ds:pb-[calc(var(--spacing-xs)/2)] ds:text-[length:var(--font-size-xs)]\"\n >\n {elementSymbols.length > 0\n ? `${name} · ${elementSymbols.map((s) => symbolText(s)).join(' · ')}`\n : name}\n <RadixTooltip.Arrow className=\"ds:fill-[var(--foreground)]\" />\n </RadixTooltip.Content>\n </RadixTooltip.Portal>\n </RadixTooltip.Root>\n );\n })}\n </svg>\n );\n\n // The sr-only live region announcing selection changes. Each chart (single\n // view or `both`-view sub-chart) owns one, so announcements stay local to\n // the row the user is editing.\n const liveRegion = (\n <div\n className={liveRegionVariants()}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n data-testid=\"tooth-scheme-live\"\n >\n {announcement}\n </div>\n );\n\n // `_inner` sub-chart: render only the svg + its live region (no region\n // wrapper / controls / legend — the outer host supplies those).\n if (_inner) {\n return (\n <RadixTooltip.Provider delayDuration={200}>\n {chartSvg}\n {liveRegion}\n </RadixTooltip.Provider>\n );\n }\n\n // The `both` view: four arch-scoped sub-charts in clinical reading order —\n // upper facial, upper occlusal, lower occlusal, lower facial — so the two\n // occlusal rows sit between the two facial rows, numbers bracketing top and\n // bottom. Each shares this chart's data (value / onChange), so an edit in\n // any row propagates everywhere.\n const archLabel = (arch: Arch) =>\n arch === 'upper'\n ? t('toothScheme.arch.upper')\n : t('toothScheme.arch.lower');\n const rowLabel = (arch: Arch, view: Projection) =>\n `${baseLabel} — ${archLabel(arch)}, ${\n view === 'plan'\n ? t('toothScheme.view.occlusal')\n : t('toothScheme.view.side')\n }`;\n const sharedSubChartProps = {\n dentition,\n numbering,\n mode,\n value: chart,\n onChange: commitChart,\n onSelect,\n activeCondition,\n assetBaseUrl,\n radiographs,\n radiographDisplay,\n onOpenRadiographs,\n conditionRegistry,\n specialElements: showSpecials,\n _inner: true as const,\n _contentWidth: bothContentWidth,\n };\n const bothView = (\n <div className={bothStackVariants()} data-testid=\"tooth-scheme-both\">\n <ToothScheme\n {...sharedSubChartProps}\n projection=\"side\"\n _arch=\"upper\"\n _numbersPosition=\"above\"\n ariaLabel={rowLabel('upper', 'side')}\n />\n <ToothScheme\n {...sharedSubChartProps}\n projection=\"plan\"\n _arch=\"upper\"\n _numbersPosition=\"none\"\n ariaLabel={rowLabel('upper', 'plan')}\n />\n <ToothScheme\n {...sharedSubChartProps}\n projection=\"plan\"\n _arch=\"lower\"\n _numbersPosition=\"none\"\n ariaLabel={rowLabel('lower', 'plan')}\n />\n <ToothScheme\n {...sharedSubChartProps}\n projection=\"side\"\n _arch=\"lower\"\n _numbersPosition=\"below\"\n ariaLabel={rowLabel('lower', 'side')}\n />\n </div>\n );\n\n // The options gear, built once so the inline and portaled placements share\n // the same popover + state wiring. Rendered inline by default; portaled into\n // `controlsContainer` (e.g. a card header) when the consumer provides one.\n const controlsNode = controls ? (\n <div\n className={\n controlsContainer != null\n ? 'ds:flex ds:justify-end'\n : 'ds:flex ds:w-full ds:justify-end'\n }\n data-testid=\"tooth-scheme-controls\"\n >\n <Popover.Root>\n <Popover.Trigger asChild>\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n icon={<Settings aria-hidden=\"true\" />}\n aria-label={t('toothScheme.options.label')}\n tooltip={t('toothScheme.options.label')}\n />\n </Popover.Trigger>\n <Popover.Content\n ref={setOptionsPopoverEl}\n align=\"end\"\n size=\"md\"\n aria-label={t('toothScheme.options.label')}\n >\n <div className=\"ds:flex ds:w-[var(--popover-size-sm)] ds:max-w-full ds:flex-col ds:gap-[var(--spacing-md)]\">\n {/* Stretch the toggle rows full-width so each control\n aligns to the inline-end edge like the selects below. */}\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:border-b ds:border-[color:var(--border)] ds:pb-[var(--spacing-sm)] ds:[&>*]:w-full ds:[&>*]:justify-between\">\n <Switch\n label={t('toothScheme.options.legend')}\n labelSide=\"start\"\n checked={legend}\n onCheckedChange={setUiLegend}\n />\n <Switch\n label={t('toothScheme.options.specialElements')}\n labelSide=\"start\"\n checked={showSpecials}\n onCheckedChange={setUiSpecial}\n />\n </div>\n <OptionRow\n container={optionsPopoverEl}\n label={t('toothScheme.options.dentition')}\n value={dentition}\n onValueChange={(v) => setUiDentition(v as Dentition)}\n options={[\n {\n value: 'permanent',\n label: t('toothScheme.dentition.permanent'),\n },\n {\n value: 'primary',\n label: t('toothScheme.dentition.primary'),\n },\n {\n value: 'mixed',\n label: t('toothScheme.dentition.mixed'),\n },\n ]}\n />\n <OptionRow\n container={optionsPopoverEl}\n label={t('toothScheme.options.numbering')}\n value={numbering}\n onValueChange={(v) => setUiNumbering(v as Numbering)}\n options={[\n {\n value: 'fdi',\n label: t('toothScheme.numbering.fdi'),\n },\n {\n value: 'universal',\n label: t('toothScheme.numbering.universal'),\n },\n {\n value: 'palmer',\n label: t('toothScheme.numbering.palmer'),\n },\n ]}\n />\n <OptionRow\n container={optionsPopoverEl}\n label={t('toothScheme.options.view')}\n value={viewMode}\n onValueChange={(v) => setUiProjection(v as ViewMode)}\n options={[\n {\n value: 'side',\n label: t('toothScheme.view.side'),\n },\n {\n value: 'plan',\n label: t('toothScheme.view.occlusal'),\n },\n {\n value: 'both',\n label: t('toothScheme.view.both'),\n },\n ]}\n />\n </div>\n </Popover.Content>\n </Popover.Root>\n </div>\n ) : null;\n\n return (\n <RadixTooltip.Provider delayDuration={200}>\n <div\n ref={rootRef}\n role=\"region\"\n aria-label={baseLabel}\n tabIndex={scrollTabIndex}\n className={[rootVariants(), className].filter(Boolean).join(' ')}\n data-component=\"tooth-scheme\"\n data-component-id={id}\n data-testid=\"tooth-scheme-root\"\n data-dentition={dentition}\n data-numbering={numbering}\n data-mode={mode}\n data-projection={projection}\n data-view-mode={viewMode}\n data-special-elements={showSpecials ? 'true' : 'false'}\n >\n {/* Options gear — inline by default; portaled into the consumer's\n `controlsContainer` slot (e.g. a card header) when one is passed.\n While that slot mounts the prop is `null`, so nothing renders here\n and the gear never flashes inline first. */}\n {controlsContainer === undefined\n ? controlsNode\n : controlsContainer\n ? createPortal(controlsNode, controlsContainer)\n : null}\n\n {showBoth ? bothView : chartSvg}\n\n {/* Whole-mouth `general` element — a switch beneath the chart, not a\n cramped icon column. Interactive-only; in display mode it shows\n only when a finding is set, as a read-only indicator. */}\n {showSpecials && (mode === 'interactive' || generalChecked) ? (\n <div\n className=\"ds:flex ds:w-full ds:items-center ds:pt-[var(--spacing-2xs)]\"\n data-testid=\"tooth-scheme-general\"\n >\n <Switch\n label={t('toothScheme.special.general')}\n labelSide=\"end\"\n checked={generalChecked}\n disabled={mode !== 'interactive'}\n onCheckedChange={toggleGeneral}\n />\n </div>\n ) : null}\n\n {legend ? (\n <Legend assetBaseUrl={assetBaseUrl} registry={conditionRegistry} />\n ) : null}\n\n {liveRegion}\n </div>\n </RadixTooltip.Provider>\n );\n },\n);\n\nToothScheme.displayName = 'ToothScheme';\n\n/* ------------------------------------------------------------------ */\n/* Re-exports */\n/* ------------------------------------------------------------------ */\n\nexport { rootVariants as toothSchemeVariants, PERMANENT_TEETH, PRIMARY_TEETH };\nexport type {\n Dentition,\n FdiId,\n Numbering,\n SpecialElement,\n ToothChart,\n ToothCondition,\n ToothMode,\n ToothState,\n} from './tooth-data';\n"],"names":["enumOf","ids","CONDITION_IDS","SURFACE_IDS","ROOT_IDS","PART_IDS","STATUS_IDS","RADIOGRAPH_KIND_IDS","FDI_SCHEMA","CONDITION_SCHEMA","CONDITION_ID_SCHEMA","SURFACE_SCHEMA","ROOT_SCHEMA","PART_SCHEMA","STATUS_SCHEMA","SYMBOL_SCHEMA","RADIOGRAPH_SCHEMA","structuralSymbol","symbol","toothSchemeAgent","handle","fdi","state","r","args","_a","rootVariants","cva","bothStackVariants","svgVariants","toothGroupVariants","legendVariants","legendItemVariants","liveRegionVariants","zoneVariants","isControlled","props","emptyState","toggleSymbolCondition","symbols","active","registry","condition","conditionPart","entry","toggleSymbolTarget","part","target","covers","sameCondition","index","growable","toggleAt","seed","current","next","_","i","updated","stateFromSymbols","previous","conditions","surfaces","isBuiltInCondition","surface","elementName","element","t","nextZone","zone","key","hasCenter","orderedRoots","meta","slot","root","rootScreenSide","rootsForTooth","b","drillableRoots","roots","nextRoot","rootRect","count","rect","w","GlyphMark","glyph","colour","cx","cy","opacity","testId","jsxs","jsx","StatusDot","status","strokeWidth","STATUS_COLORS","STATUS_ORDER","LegendSymbol","assetBaseUrl","FDI_TO_META","spec","conditionSideSymbol","isMissing","conditionColor","isSurface","conditionHasArtwork","h","x","y","toothImageUrl","conditionSymbolUrl","CONDITION_COLORS","conditionGlyph","Legend","useTranslation","TOOTH_CONDITIONS","id","label","conditionLabel","statusLabelKey","OptionRow","value","options","onValueChange","container","Select","sortByDateDesc","a","ToothScheme","forwardRef","dentitionProp","numberingProp","mode","projectionProp","specialElementsProp","defaultValue","onChange","onSelect","radiographs","radiographDisplay","onOpenRadiographs","activeCondition","conditionRegistry","legendProp","controls","controlsContainer","ariaLabel","className","_arch","_numbersPosition","_inner","_contentWidth","ref","uiDentition","setUiDentition","useState","uiNumbering","setUiNumbering","uiProjection","setUiProjection","uiLegend","setUiLegend","uiSpecial","setUiSpecial","optionsPopoverEl","setOptionsPopoverEl","dentition","numbering","legend","viewMode","projection","showBoth","specialAuto","showSpecials","controlsWasOn","useRef","useEffect","internalChart","setInternalChart","chartFromConditions","chart","slotHeight","TOOTH_SLOT_HEIGHT","layout","useMemo","layoutTeeth","specials","layoutSpecials","specialsForRow","upper","lowerRowY","TOOTH_ROW_GAP","lower","s","bothContentWidth","max","arch","proj","visibleIds","tooth","firstId","focusedId","setFocusedId","announcement","setAnnouncement","svgRef","commitChart","useCallback","focusToothById","svg","node","labelOf","symbolText","scoped","scope","targetSuffix","buildAnnouncement","conditionText","isSpecialElement","name","SPECIAL_BY_ID","writeSymbols","commitSymbols","activePart","surfacePicking","rootPicking","drilled","setDrilled","focusDrill","drill","selector","_b","restoreFocusTo","isTargetMarked","symbolsForTooth","toggleTarget","drillInto","zonesForTooth","handleSurfaceKeyDown","event","nz","zoneSurface","handleRootKeyDown","nr","rootRef","radiographOpenable","teethFocusable","handleOpenRadiographs","agentHandle","useImperativeHandle","useAgentRegistration","handleKeyDown","order","currentIndex","nextIndex","targetQuadrant","candidate","inQuadrant","other","handleClick","generalId","generalChecked","toggleGeneral","checked","topPad","bottomPad","specialsWidth","SPECIAL_SLOT_WIDTH","viewBoxWidth","viewBoxHeight","baseLabel","scrollTabIndex","chartSvg","primaryCondition","anatomyLabel","conditionSuffix","toothRadiographs","radiographCount","hasRadiographs","latestRadiograph","showThumbnail","radiographSuffix","projectionSuffix","labelFor","tabIndex","symbolOverlays","conditionPlanSymbol","planSymbolUrl","STATUS_OPACITY","glyphMarks","symbolColor","ringSymbol","ringColour","statuses","tooltipContent","labelText","imageUrl","slotImageHref","surfaceOverlays","folder","conditionPlanFolder","surfaceSymbolUrl","imgScale","PRIMARY_TOOTH_SCALE","imgW","TOOTH_SLOT_WIDTH","imgH","imgX","imgY","surfaceDrilled","rootDrilled","isDrilled","toothZones","toothRoots","drillsIn","numberY","RadixTooltip","TOOTH_HIT_PAD","url","scale","planOverlayScale","marked","zonePath","d","elementSymbols","primary","cond","selected","condColour","iconUrl","specialIconUrl","elementInteractive","Fragment","liveRegion","archLabel","rowLabel","view","sharedSubChartProps","bothView","controlsNode","Popover","IconButton","Settings","Switch","v","createPortal"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tooth-scheme-2IsmbE6w.js","sources":["../../src/components/tooth-scheme/tooth-scheme.agent.ts","../../src/components/tooth-scheme/tooth-scheme.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — ToothScheme. */\n/* */\n/* Odontogram. The agent-relevant surface is the chart itself: the */\n/* findings on each tooth — now one entry per SYMBOL, each scoping its own */\n/* surfaces, roots, planned/executed status and per-practice colour — plus */\n/* structural references to each tooth's radiograph archive. The handle is */\n/* the curated `ToothSchemeHandle`, never React state. */\n/* */\n/* A9 (PRS §26 §3): the always-on state snapshot carries identifiers and */\n/* enums ONLY. The model has two free-text fields — a symbol's `note` and */\n/* a tooth's `notes` — and both are PHI, so both are projected out of */\n/* `state.chart` and fetched deliberately, per tooth, through an audited */\n/* `phi` action (`get_symbols` / `get_notes`). Radiograph notes, dates and */\n/* image urls behave the same way through `get_radiographs`. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { ToothSchemeHandle } from './tooth-scheme';\nimport type {\n ConditionId,\n Radiograph,\n RadiographKind,\n Root,\n Surface,\n SymbolPart,\n SymbolStatus,\n ToothCondition,\n ToothSymbol,\n} from './tooth-data';\n\ntype FdiId = Parameters<ToothSchemeHandle['focusTooth']>[0];\n\n/* -------------------------------------------------------------------- */\n/* Drift guard. */\n/* */\n/* The JSON-Schema enums below are inlined literals, not runtime reads of */\n/* the `tooth-data` unions — the adapter must stay a pure module the ESM */\n/* catalog build can import without TS path resolution. `enumOf` is what */\n/* stops the two copies drifting: it accepts ONLY a literal that covers */\n/* its union EXACTLY. */\n/* */\n/* - a typo or a retired id fails on the `T extends readonly U[]` */\n/* constraint — the compiler names the id that is not in the union; */\n/* - a MISSING id fails on the intersected `EnumIsMissing<…>` brand — */\n/* the error reads `EnumIsMissing<\"xray\">`, naming the ids to add. */\n/* */\n/* `ToothCondition` growing 11 → 21 is exactly the drift this catches, so */\n/* `npx tsc -b` is the gate: the build breaks here until the literal */\n/* catches up with the union. Same guard on Surface / Root / SymbolPart / */\n/* SymbolStatus / RadiographKind. */\n/* -------------------------------------------------------------------- */\n\n/** Error brand — surfaces the ids an enum literal is missing, by name. */\ntype EnumIsMissing<U extends string> = {\n readonly __addTheseIdsToTheLiteral: U;\n};\n\nconst enumOf =\n <U extends string>() =>\n <T extends readonly U[]>(\n ids: T &\n ([U] extends [T[number]]\n ? unknown\n : EnumIsMissing<Exclude<U, T[number]>>),\n ): T =>\n ids;\n\nconst CONDITION_IDS = enumOf<ToothCondition>()([\n 'caries',\n 'filled',\n 'crowned',\n 'temporaryCrown',\n 'bridge',\n 'missing',\n 'implant',\n 'implantExtraction',\n 'stub',\n 'destroyed',\n 'rootCanal',\n 'pin',\n 'rootAmputation',\n 'anchorage',\n 'hook',\n 'attachment',\n 'mucogingivalSurgery',\n 'periodontalSurgery',\n 'curettage',\n 'medication',\n 'xray',\n] as const);\n\nconst SURFACE_IDS = enumOf<Surface>()([\n 'mesial',\n 'distal',\n 'occlusal',\n 'buccal',\n 'lingual',\n] as const);\n\nconst ROOT_IDS = enumOf<Root>()([\n 'mesial',\n 'distal',\n 'palatal',\n 'buccal',\n 'single',\n] as const);\n\nconst PART_IDS = enumOf<SymbolPart>()(['element', 'surface', 'root'] as const);\n\nconst STATUS_IDS = enumOf<SymbolStatus>()(['planned', 'executed'] as const);\n\nconst RADIOGRAPH_KIND_IDS = enumOf<RadiographKind>()([\n 'periapical',\n 'bitewing',\n 'panoramic',\n 'other',\n] as const);\n\n/* -------------------------------------------------------------------- */\n/* JSON-Schema fragments. */\n/* -------------------------------------------------------------------- */\n\nconst FDI_SCHEMA = {\n type: 'string',\n description:\n \"FDI tooth id ('11'–'48' permanent, '51'–'85' primary) or a special-element id ('Q1'–'Q4' quadrants, 'S1'–'S6' sextants, 'AS'/'AI' arches, 'general'; primary mirrors with an 'm' prefix).\",\n} as const;\nconst CONDITION_SCHEMA = {\n enum: [...CONDITION_IDS],\n description:\n \"Built-in finding id. 'destroyed' is the retained root (*radice persistente*); 'xray' is the chartable radiograph SYMBOL, distinct from the image archive reached via get_radiographs.\",\n} as const;\n/**\n * Open finding id — the vocabulary is extensible per practice, so this stays a\n * plain string rather than the closed `CONDITION_SCHEMA` enum.\n */\nconst CONDITION_ID_SCHEMA = {\n type: 'string',\n description:\n \"Finding id — either a built-in (the enum on set_finding) or a practice-defined id from the host's `conditionRegistry`.\",\n} as const;\nconst SURFACE_SCHEMA = {\n enum: [...SURFACE_IDS],\n description: 'Tooth surface, named anatomically.',\n} as const;\nconst ROOT_SCHEMA = {\n enum: [...ROOT_IDS],\n description:\n \"Root, named ANATOMICALLY (not by screen side) — 'palatal' exists only on upper molars, 'single' covers every one-rooted tooth. On flank-mounted markers (anchorage, hook) 'mesial' / 'distal' select the side of the tooth instead.\",\n} as const;\nconst PART_SCHEMA = {\n enum: [...PART_IDS],\n description:\n \"Anatomical layer the finding marks. Omit to take the condition's natural part (caries and fillings are 'surface', root canals are 'root', crowns and implants are 'element').\",\n} as const;\nconst STATUS_SCHEMA = {\n enum: [...STATUS_IDS],\n description:\n \"Execution status — 'planned' (proposed treatment) vs 'executed' (already done). Omit when the finding carries no plan/executed distinction.\",\n} as const;\n/**\n * One charted finding. Used for BOTH the `get_symbols` result and the\n * `set_symbol` argument — the shape is symmetrical.\n */\nconst SYMBOL_SCHEMA = {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description:\n \"Provenance id — the host's care-plan / finding entry this symbol came from. Present on symbols the host seeded; supply it to update that exact entry.\",\n },\n condition: CONDITION_ID_SCHEMA,\n part: PART_SCHEMA,\n surfaces: { type: 'array', items: SURFACE_SCHEMA },\n roots: { type: 'array', items: ROOT_SCHEMA },\n status: STATUS_SCHEMA,\n color: {\n type: 'string',\n description:\n \"Per-practice colour override — a CSS colour or `var(--token)`. Omit to take the condition's own colour.\",\n },\n note: {\n type: 'string',\n description: 'Free-text clinical note. PHI — never in a state snapshot.',\n },\n },\n required: ['condition'],\n} as const;\nconst RADIOGRAPH_SCHEMA = {\n type: 'object',\n properties: {\n id: { type: 'string' },\n url: { type: 'string' },\n thumbnailUrl: { type: 'string' },\n date: { type: 'string', description: 'ISO acquisition date (YYYY-MM-DD).' },\n note: { type: 'string' },\n kind: { enum: [...RADIOGRAPH_KIND_IDS] },\n alt: { type: 'string' },\n },\n required: ['id', 'url'],\n} as const;\n\n/**\n * A9: the snapshot-safe projection of one symbol — identifiers and enums only.\n * Allow-listed field by field rather than deleting `note`, so a free-text field\n * added to `ToothSymbol` later cannot leak into the always-on snapshot by\n * default; it has to be opted in here.\n */\nfunction structuralSymbol(symbol: ToothSymbol) {\n return {\n id: symbol.id,\n condition: symbol.condition,\n part: symbol.part,\n surfaces: symbol.surfaces,\n roots: symbol.roots,\n status: symbol.status,\n color: symbol.color,\n };\n}\n\nexport const toothSchemeAgent: AgentAdapter<ToothSchemeHandle> = {\n id: 'tooth-scheme',\n // pick — focus/select a tooth (`focus_tooth`, transient, not persisted);\n // set_value / edit_inline — `set_finding` records a built-in finding and\n // marks the affected surfaces (set-surface), `set_symbol` records the full\n // per-symbol form (part / roots / status / colour / note), `remove_finding`\n // clears one; view_change — the side/plan projection + dentition are view\n // props.\n // `view_change` is deliberately NOT claimed: projection / dentition /\n // numbering are props, and the component's own view state only takes effect\n // when `controls` is on, so a `set_view` action would silently no-op for most\n // consumers. The view is readable below; changing it stays the host's job.\n capabilities: ['pick', 'set_value', 'edit_inline'],\n state: {\n chart: {\n // A9: the always-on snapshot carries FDI / element ids plus finding\n // ENUMS only — never the free-text clinical notes (`ToothState.notes`,\n // `ToothSymbol.note`), which are PHI. Those are fetched deliberately,\n // per tooth, via get_notes / get_symbols (both safety: 'phi').\n type: 'Record<FdiId, { conditions: ToothCondition[]; surfaces: Surface[]; symbols: { id?: string; condition: ConditionId; part?: SymbolPart; surfaces?: Surface[]; roots?: Root[]; status?: SymbolStatus; color?: string }[] }>',\n descriptionKey: 'ui.agent.toothScheme.state.chart',\n description:\n 'Current dental chart keyed by FDI id, or by a special-element id (quadrant / sextant / arch / general) for region-spanning findings. Each entry carries the flat `conditions` + `surfaces` pair AND the normalised per-symbol list, where every finding scopes its own surfaces, roots, planned/executed status and colour. Free-text clinical notes are PHI and omitted — read them per tooth via get_symbols / get_notes.',\n read: (handle) =>\n Object.fromEntries(\n Object.entries(handle.getChart()).map(([fdi, state]) => [\n fdi,\n {\n conditions: state.conditions,\n surfaces: state.surfaces,\n // Read back through the handle so a tooth charted the legacy\n // way (flat conditions + surfaces) reports the same symbol\n // shape as one charted per-symbol.\n symbols: handle.getSymbols(fdi).map(structuralSymbol),\n },\n ]),\n ),\n },\n chartedTeeth: {\n type: 'string[]',\n descriptionKey: 'ui.agent.toothScheme.state.chartedTeeth',\n description:\n 'Ids carrying at least one finding — FDI tooth ids and/or special-element ids (quadrant / sextant / arch / general).',\n read: (handle) => Object.keys(handle.getChart()),\n },\n radiographs: {\n // A9: the always-on state snapshot carries identifiers + enums only —\n // never PHI free-text (the radiograph `note`), service dates, or the\n // consumer-hosted image URLs. Those are fetched deliberately, per tooth,\n // via the audited `get_radiographs` action.\n type: 'Record<string, { id: string; kind?: string }[]>',\n descriptionKey: 'ui.agent.toothScheme.state.radiographs',\n description:\n 'Structural references (id + kind) to the radiographs on each tooth, keyed by FDI id. Notes, dates and image URLs are not exposed here — fetch them on demand via get_radiographs.',\n read: (handle) =>\n Object.fromEntries(\n handle\n .teethWithRadiographs()\n .map((fdi) => [\n fdi,\n handle\n .getRadiographs(fdi)\n .map((r) => ({ id: r.id, kind: r.kind ?? 'periapical' })),\n ]),\n ),\n },\n teethWithRadiographs: {\n type: 'string[]',\n descriptionKey: 'ui.agent.toothScheme.state.teethWithRadiographs',\n description: 'FDI ids of every tooth carrying at least one radiograph.',\n read: (handle) => handle.teethWithRadiographs(),\n },\n },\n actions: {\n focus_tooth: {\n safety: 'read',\n argsType: '{ id: FdiId }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA },\n required: ['id'],\n },\n idempotent: true,\n errors: [\n 'In the `both` view the registered instance renders no SVG of its own (the four sub-charts do, and deliberately do not register), so this action has no effect there.',\n ],\n descriptionKey: 'ui.agent.toothScheme.actions.focusTooth',\n description: 'Move focus to a specific tooth by FDI id.',\n invoke: (handle, args: { id: FdiId }) => {\n handle.focusTooth(args.id);\n },\n },\n get_tooth: {\n safety: 'read',\n argsType: '{ id: FdiId }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA },\n required: ['id'],\n },\n returns: 'ToothCondition[]',\n returnsSchema: { type: 'array', items: CONDITION_SCHEMA },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.getTooth',\n description:\n \"Read the BUILT-IN findings recorded on one tooth (FDI id), as a flat list of condition ids. Practice-defined findings, per-finding surfaces, roots and status are not included — use get_symbols for the tooth's full record.\",\n invoke: (handle, args: { id: FdiId }) => handle.getTooth(args.id),\n },\n get_symbols: {\n // phi (not read): a symbol carries a free-text clinical `note`, which is\n // PHI. PRS §26 §3 — phi outranks read so the host gates it behind\n // stricter confirm + audit. The always-on state.chart snapshot stays\n // note-free.\n safety: 'phi',\n argsType: '{ id: FdiId }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA },\n required: ['id'],\n },\n returns: 'ToothSymbol[]',\n returnsSchema: { type: 'array', items: SYMBOL_SCHEMA },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.getSymbols',\n description:\n \"Read one tooth's full finding record (incl. notes) — one entry per symbol, each with its own surfaces, roots, planned/executed status, colour override, provenance id and free-text note. Normalised, so a tooth charted with the flat conditions/surfaces pair reports the same shape.\",\n invoke: (handle, args: { id: FdiId }) => handle.getSymbols(args.id),\n },\n get_notes: {\n // phi (not read): resolves the tooth-level free-text clinical note.\n // Same posture as get_symbols — the note is out of state.chart and only\n // reachable through this audited action.\n safety: 'phi',\n argsType: '{ id: FdiId }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA },\n required: ['id'],\n },\n returns: 'string | null',\n returnsSchema: { type: ['string', 'null'] },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.getNotes',\n description:\n 'Read the tooth-level free-text clinical note, or null when there is none. Per-finding notes are separate — they come back from get_symbols.',\n invoke: (handle, args: { id: FdiId }) =>\n handle.getChart()[args.id]?.notes ?? null,\n },\n teeth_with: {\n safety: 'read',\n argsType: '{ condition: ToothCondition }',\n argsSchema: {\n type: 'object',\n properties: { condition: CONDITION_SCHEMA },\n required: ['condition'],\n },\n returns: 'FdiId[]',\n returnsSchema: { type: 'array', items: FDI_SCHEMA },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.teethWith',\n description:\n 'List the ids carrying a given built-in finding — FDI tooth ids and/or special-element ids (e.g. all teeth with caries). For a practice-defined finding use teeth_with_symbol.',\n invoke: (handle, args: { condition: ToothCondition }) =>\n handle.teethWith(args.condition),\n },\n teeth_with_symbol: {\n safety: 'read',\n argsType: '{ condition: ConditionId }',\n argsSchema: {\n type: 'object',\n properties: { condition: CONDITION_ID_SCHEMA },\n required: ['condition'],\n },\n returns: 'FdiId[]',\n returnsSchema: { type: 'array', items: FDI_SCHEMA },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.teethWithSymbol',\n description:\n \"As teeth_with, but open to the practice-defined ids in the host's `conditionRegistry` as well as the built-ins.\",\n invoke: (handle, args: { condition: ConditionId }) =>\n handle.teethWithSymbol(args.condition),\n },\n get_radiographs: {\n // phi (not read): resolves the radiograph `note` (free-text clinical\n // PHI) alongside the acquisition date and the consumer-hosted image\n // urls. PRS §26 §3 — phi outranks read so the host gates it behind\n // stricter confirm + audit; the always-on state.radiographs snapshot\n // stays structural (id + kind).\n safety: 'phi',\n argsType: '{ id: FdiId }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA },\n required: ['id'],\n },\n returns: 'Radiograph[]',\n returnsSchema: { type: 'array', items: RADIOGRAPH_SCHEMA },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.getRadiographs',\n description:\n 'Read the radiographs (x-rays) attached to one tooth, including their notes, dates and image urls.',\n invoke: (handle, args: { id: FdiId }) => handle.getRadiographs(args.id),\n },\n open_radiographs: {\n safety: 'read',\n argsType: '{ id: FdiId }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA },\n required: ['id'],\n },\n idempotent: true,\n errors: [\n 'In the `both` view the registered instance renders no SVG of its own (the four sub-charts do, and deliberately do not register), so this action has no effect there.',\n ],\n descriptionKey: 'ui.agent.toothScheme.actions.openRadiographs',\n description:\n \"Focus a tooth and open its radiograph archive (fires the host's onOpenRadiographs).\",\n invoke: (handle, args: { id: FdiId }) => {\n handle.openRadiographs(args.id);\n },\n },\n set_finding: {\n safety: 'write',\n argsType:\n '{ id: FdiId; condition: ToothCondition; surfaces?: Surface[] }',\n argsSchema: {\n type: 'object',\n properties: {\n id: FDI_SCHEMA,\n condition: CONDITION_SCHEMA,\n surfaces: { type: 'array', items: SURFACE_SCHEMA },\n },\n required: ['id', 'condition'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.setFinding',\n description:\n 'Record a built-in finding on a tooth or region element (crown, implant, root canal, caries, …). Optionally mark the affected surfaces for a surface finding. Structural only — to set a finding’s roots, planned/executed status, colour or note, or to chart a practice-defined finding, use set_symbol.',\n invoke: (\n handle,\n args: { id: FdiId; condition: ToothCondition; surfaces?: Surface[] },\n ) => {\n handle.setFinding(args.id, args.condition, args.surfaces);\n },\n },\n set_symbol: {\n // phi (not write): the symbol may carry a free-text clinical `note`,\n // which is PHI. PRS §26 §3 — a PHI write must never be auto-confirmed.\n // The structural-only path stays available as set_finding ('write').\n safety: 'phi',\n argsType: '{ id: FdiId; symbol: ToothSymbol }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA, symbol: SYMBOL_SCHEMA },\n required: ['id', 'symbol'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.setSymbol',\n description:\n 'Add or replace one finding on a tooth or region element, with its own part, surfaces, roots, planned/executed status, colour override and note. Matched by `symbol.id` when the symbol carries provenance, otherwise by its condition; appended when nothing matches. Accepts practice-defined `conditionRegistry` ids as well as the built-ins.',\n examples: [\n {\n args: {\n id: '16',\n symbol: {\n condition: 'filled',\n surfaces: ['mesial'],\n status: 'executed',\n },\n },\n note: 'Record an executed mesial filling on tooth 16, leaving any other finding on that tooth untouched.',\n },\n {\n args: {\n id: '26',\n symbol: {\n condition: 'rootCanal',\n roots: ['palatal'],\n status: 'planned',\n },\n },\n note: \"Plan a root canal on the palatal root of tooth 26 ('palatal' is the anatomical root, not a screen side).\",\n },\n ],\n invoke: (handle, args: { id: FdiId; symbol: ToothSymbol }) => {\n handle.setSymbol(args.id, args.symbol);\n },\n },\n remove_finding: {\n safety: 'write',\n argsType: '{ id: FdiId; condition: ToothCondition }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA, condition: CONDITION_SCHEMA },\n required: ['id', 'condition'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.removeFinding',\n description:\n 'Remove a finding from a tooth — every symbol carrying that condition goes, whatever its surfaces or roots. Built-in ids only.',\n invoke: (handle, args: { id: FdiId; condition: ToothCondition }) => {\n handle.removeFinding(args.id, args.condition);\n },\n },\n clear_tooth: {\n safety: 'destructive',\n argsType: '{ id: FdiId }',\n argsSchema: {\n type: 'object',\n properties: { id: FDI_SCHEMA },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.toothScheme.actions.clearTooth',\n description: 'Clear every finding from a tooth.',\n invoke: (handle, args: { id: FdiId }) => {\n handle.clearTooth(args.id);\n },\n },\n },\n domHooks: {\n root: { attr: 'data-component', value: 'tooth-scheme' },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n item: {\n attr: 'data-fdi',\n description:\n \"Each rendered tooth `<g>` carries its FDI id as `data-fdi`, its first finding as `data-condition`, the full space-separated list as `data-conditions`, the finding count as `data-symbol-count` and the first finding's status as `data-status`; selectable special-element slots carry their id in `data-fdi` too (plus `data-special` naming the kind). Per-surface pick targets carry `data-zone`, per-root pick targets `data-root` (the anatomical root name). The `data-projection` / `data-view-mode` attributes on the root expose the side/plan/both view.\",\n },\n },\n};\n\n// Re-exported for callers building typed args against the adapter.\nexport type {\n ConditionId,\n Radiograph,\n RadiographKind,\n Root,\n Surface,\n SymbolPart,\n SymbolStatus,\n ToothCondition,\n ToothSymbol,\n};\n","/* ------------------------------------------------------------------ */\n/* ToothScheme — the consolidated AlfaDocs odontogram. */\n/* */\n/* - Image-base + SVG overlay: each tooth is a photoreal CGI render */\n/* (`<image>`, served from `assetBaseUrl`); the SVG layer on top */\n/* carries findings, selection, keyboard nav and a11y. No third-party */\n/* engine — `src/docs/08-third-party.mdx §Dental chart` rejected the */\n/* candidates (jQuery, abandoned, poor a11y). */\n/* */\n/* - Colour-not-alone: whole-tooth findings render a DISTINCT symbol */\n/* glyph image (the shape is the channel) + the tooth's accessible */\n/* name + tooltip; surface findings (caries / filled) render a */\n/* per-surface fill in the plan view, or a distinguished ring (solid */\n/* = caries, dashed = filled) + legend + tooltip in the side view. */\n/* */\n/* - One finding model: every read goes through `symbolsForTooth()`, */\n/* so a symbol scopes its OWN surfaces and roots, whole-tooth */\n/* symbols draw in BOTH projections, and a registered finding with */\n/* no artwork still charts, as a glyph badge. */\n/* */\n/* - Two projections: `side` (facial — whole-tooth findings) and */\n/* `plan` (occlusal — per-surface caries / fillings, the \"Stato */\n/* dentale\" marking). `both` lays the two facial (side) rows on the */\n/* outside with the two occlusal (plan) rows between them — upper */\n/* side, upper occlusal, lower occlusal, lower side — and brackets */\n/* the chart with tooth numbers above and below (matching the */\n/* platform odontogram). */\n/* */\n/* - Special elements: selectable quadrant / sextant / arch / whole- */\n/* mouth slots appended to the inline-end of each arch row, so a */\n/* finding can span a region (e.g. a denture on the upper arch). See */\n/* `tooth-data.ts` § Special elements. */\n/* */\n/* - Chart orientation is FIXED to clinical convention: the patient's */\n/* right sits on the viewer's left in both arches regardless of */\n/* `dir`. A mirrored chart would invert every recorded diagnosis. */\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n type ReactElement,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport * as RadixTooltip from '@radix-ui/react-tooltip';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Settings } from 'lucide-react';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { IconButton } from '../button';\nimport { Popover } from '../popover';\nimport { Select } from '../select';\nimport { Switch } from '../switch';\nimport { toothSchemeAgent } from './tooth-scheme.agent';\n\nimport {\n CONDITION_COLORS,\n STATUS_COLORS,\n STATUS_OPACITY,\n TOOTH_CONDITIONS,\n conditionColor,\n conditionGlyph,\n conditionHasArtwork,\n conditionLabel,\n conditionPart,\n conditionPlanFolder,\n conditionPlanSymbol,\n conditionSideSymbol,\n conditionSymbolUrl,\n isBuiltInCondition,\n planOverlayScale,\n planSymbolUrl,\n rootScreenSide,\n rootsForTooth,\n statusLabelKey,\n surfaceSymbolUrl,\n symbolColor,\n symbolsForTooth,\n zonesForTooth,\n zoneSurface,\n zonePath,\n FDI_TO_META,\n PERMANENT_TEETH,\n PRIMARY_TEETH,\n SPECIAL_BY_ID,\n SPECIAL_SLOT_WIDTH,\n TOOTH_HIT_PAD,\n TOOTH_ROW_GAP,\n TOOTH_SLOT_WIDTH,\n TOOTH_SLOT_HEIGHT,\n PRIMARY_TOOTH_SCALE,\n chartFromConditions,\n isSpecialElement,\n labelFor,\n layoutSpecials,\n layoutTeeth,\n specialIconUrl,\n specialsForRow,\n toothImageUrl,\n type Arch,\n type ConditionDefinition,\n type ConditionId,\n type ConditionRegistry,\n type Projection,\n type PositionedSpecial,\n type Root,\n type SpecialElement,\n type SymbolStatus,\n type ToothMeta,\n type ToothSymbol,\n type ViewMode,\n type Dentition,\n type FdiId,\n type Numbering,\n type Radiograph,\n type Surface,\n type SurfaceZone,\n type ToothChart,\n type ToothCondition,\n type ToothMode,\n type ToothState,\n} from './tooth-data';\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport interface ToothSchemeProps {\n /** Opaque instance id — emitted as `data-component-id` for the agent registry. */\n id?: string;\n /** Which teeth to render. Default `'permanent'`. */\n dentition?: Dentition;\n /** Numbering system shown on each tooth label. Default `'fdi'`. */\n numbering?: Numbering;\n /** `'interactive'` enables selection + keyboard nav; `'display'` is read-only. Default `'interactive'`. */\n mode?: ToothMode;\n /**\n * `'side'` shows the facial view (whole-tooth findings); `'plan'` shows the\n * occlusal view (per-surface caries / fillings); `'both'` lays the two facial\n * rows on the outside with the two occlusal rows between them (upper side →\n * upper occlusal → lower occlusal → lower side), bracketed by tooth numbers\n * above and below. Default `'side'`.\n */\n projection?: ViewMode;\n /**\n * Show the selectable special-element slots (quadrants, sextants, arches,\n * whole-mouth) to the inline-end of each arch row. When unset, they show in\n * `both` view and hide in the single side / plan views; pass `true` / `false`\n * to force it. They share the chart data and emit `onSelect` like a tooth.\n */\n specialElements?: boolean;\n /** Controlled chart state — the full `Record<FdiId, ToothState>`. */\n value?: ToothChart;\n /** Uncontrolled initial chart state. */\n defaultValue?: ToothChart;\n /** Fired whenever the chart changes — always emits FDI ids. */\n onChange?: (next: ToothChart) => void;\n /**\n * Fired when a tooth OR special element is focused / clicked. Special\n * elements emit their id (`Q1`, `S3`, `AS`, `general`, …).\n */\n onSelect?: (toothId: FdiId) => void;\n /** Shortcut for pre-populating conditions: `{ '16': ['caries'], '36': ['filled'] }`. */\n conditions?: Partial<Record<FdiId, ToothCondition[]>>;\n /**\n * Per-tooth radiographs (x-rays / *endorali*), keyed by FDI id — mirrors the\n * `conditions` shape. Teeth carrying at least one radiograph get a corner\n * count badge; in `radiographDisplay=\"thumbnail\"` the most-recent film also\n * fills the slot. Image urls are opaque / consumer-hosted — never bundle real\n * scans (PHI).\n */\n radiographs?: Partial<Record<FdiId, Radiograph[]>>;\n /**\n * How a tooth carrying radiographs is marked. `'badge'` (default) keeps the\n * photoreal tooth render and adds a corner count badge; `'thumbnail'` shows\n * the most-recent radiograph inset in the slot (still badged).\n */\n radiographDisplay?: 'badge' | 'thumbnail';\n /**\n * Fired when a tooth's radiograph archive is opened — i.e. a tooth is\n * activated (click / Enter / Space) in `mode=\"display\"`. Wire this to a\n * Sheet/Dialog that manages the tooth's films. Setting this makes display-mode\n * teeth focusable buttons; it is mutually exclusive with interactive\n * findings-editing (`mode=\"interactive\"` / `activeCondition`).\n *\n * EVERY tooth becomes an open-archive button — including unfilmed teeth, so the\n * user can add the first film to an empty tooth (matching a real imaging hub).\n * Filmed teeth are distinguished by the radiograph count folded into their\n * accessible name and tooltip.\n */\n onOpenRadiographs?: (toothId: FdiId) => void;\n /**\n * The finding a tooth-click applies in interactive mode (the selected\n * tool in a Findings / \"Stato dentale\" panel). Clicking a tooth toggles\n * this condition. When unset, clicking cycles caries on/off.\n *\n * A surface-part tool (caries / filled) drills into the tooth's surfaces in\n * the occlusal view; a root-part tool (root canal, post, apicectomy) drills\n * into the roots of a multi-rooted tooth in the facial view. Accepts a\n * `conditionRegistry` id as well as a built-in.\n */\n activeCondition?: ConditionId;\n /**\n * Practice-defined findings, resolved AHEAD of the built-in vocabulary field\n * by field — so an entry may re-tint or re-label a shipped finding without\n * losing its artwork, or add a wholly new one. An entry with no artwork\n * renders its `glyph` badge, which is the seam that lets a practice chart a\n * finding before a designer draws it. Labels are already-translated text:\n * the consuming app owns custom-condition copy, not the kit.\n */\n conditionRegistry?: ConditionDefinition[];\n /**\n * Base URL the photoreal tooth renders are served from. Resolves to\n * `${assetBaseUrl}/{side|plan}/{symbol}/{top|bottom}/{fdi}.webp`. Defaults\n * to the kit's bundled static path; host the `toothscheme/teeth` set\n * elsewhere (CDN) by overriding this. Trusted developer-controlled value —\n * interpolated into an SVG `<image href>` (which cannot execute scripts),\n * not user input; intentionally not runtime-validated.\n */\n assetBaseUrl?: string;\n /**\n * Show the finding-colour legend below the chart. Default `false` — findings\n * render as distinct symbol glyphs (self-describing) + tooltips, so the\n * colour key is opt-in; a consuming \"Stato dentale\" surface uses a\n * finding-type panel as its key instead.\n */\n legend?: boolean;\n /**\n * Render a built-in options affordance: a gear button that opens a popover\n * letting the END USER toggle the legend + special elements and switch\n * dentition / numbering / projection. Opt-in — when on, those become\n * user-overridable (seeded from the props); when off, the props drive the\n * chart directly. Default `false`.\n */\n controls?: boolean;\n /**\n * Where to render the `controls` gear. `undefined` (default) renders it\n * inline at the top-end of the chart. Pass a DOM element (e.g. a ref'd slot in\n * your card header) to portal the gear + its popover into that slot instead,\n * so the chart options can sit on the title line. While the slot is mounting\n * the prop will be `null`; the gear renders nothing until the element exists,\n * so it never flashes inline first. No effect unless `controls` is on.\n */\n controlsContainer?: HTMLElement | null;\n /** Accessible label override for the chart region. */\n ariaLabel?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n}\n\n/** Number-label placement for a sub-chart. */\ntype NumbersPosition = 'between' | 'above' | 'below' | 'none';\n\n/**\n * Which sub-part of a tooth the keyboard has drilled into. Surfaces and roots\n * share one state so the modal \"everything else steps out of the tab order\"\n * guard has a single source of truth.\n */\ntype Drill =\n | { fdi: FdiId; part: 'surface'; zone: SurfaceZone }\n | { fdi: FdiId; part: 'root'; root: Root };\n\n/**\n * Internal-only props (prefixed `_`) used when the component composes itself\n * into the four-row `both` view — never part of the public API.\n */\ninterface ToothSchemeInternalProps {\n /** Render a single arch (the `both` view stacks one arch per sub-chart). */\n _arch?: Arch;\n /** Number-label placement for this sub-chart. */\n _numbersPosition?: NumbersPosition;\n /** Render only the `<svg>` (no region wrapper, controls, legend, or chrome). */\n _inner?: boolean;\n /**\n * Force the SVG content width (the `both` view shares one width across all\n * four sub-charts so they scale identically and stay column-aligned —\n * otherwise rows with fewer special-element columns would scale up larger).\n */\n _contentWidth?: number;\n}\n\nexport interface ToothSchemeHandle {\n /** Programmatically focus a tooth by FDI id. */\n focusTooth: (id: FdiId) => void;\n /** Read the current chart state. */\n getChart: () => ToothChart;\n /**\n * Read the built-in findings recorded on one tooth (empty array if none).\n * Registry ids are omitted — use `getSymbols` for the full list.\n */\n getTooth: (id: FdiId) => ToothCondition[];\n /** Read the findings on one tooth as symbols, with surfaces, roots and status. */\n getSymbols: (id: FdiId) => ToothSymbol[];\n /** Read the FDI ids of every tooth carrying a given finding. */\n teethWith: (condition: ToothCondition) => FdiId[];\n /** As `teethWith`, but open to a `conditionRegistry` id. */\n teethWithSymbol: (condition: ConditionId) => FdiId[];\n /** Add a finding to a tooth (no-op if already present). Optionally mark surfaces. */\n setFinding: (\n id: FdiId,\n condition: ToothCondition,\n surfaces?: Surface[],\n ) => void;\n /**\n * Add or replace one symbol on a tooth — the surface-, root- and\n * status-aware form of `setFinding`. Matched by `symbol.id` when the symbol\n * carries provenance, else by its condition.\n */\n setSymbol: (id: FdiId, symbol: ToothSymbol) => void;\n /** Remove a finding from a tooth (no-op if absent). */\n removeFinding: (id: FdiId, condition: ToothCondition) => void;\n /** Clear every finding from a tooth. */\n clearTooth: (id: FdiId) => void;\n /** Read the radiographs attached to one tooth (empty array if none). */\n getRadiographs: (id: FdiId) => Radiograph[];\n /** Read the FDI ids of every tooth carrying at least one radiograph. */\n teethWithRadiographs: () => FdiId[];\n /** Focus a tooth and open its radiograph archive (fires `onOpenRadiographs`). */\n openRadiographs: (id: FdiId) => void;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst rootVariants = cva(\n [\n 'ds:tooth-scheme-alfadocs',\n 'ds:flex ds:flex-col',\n 'ds:gap-[var(--spacing-sm)]',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n // Block-level flex column so the SVG's w-full can grow to fill the frame.\n // min-w-fit on the SVG floors it at natural size, so narrow frames scroll\n // here rather than shrinking the per-tooth hit target below the 44px floor.\n 'ds:max-w-full ds:overflow-x-auto',\n // When the scroll container itself is the tab stop (display mode, see\n // scrollTabIndex) it needs a focus ring. Use an outline (not box-shadow):\n // forced-colors / high-contrast mode zeroes box-shadow, which would leave\n // HCM keyboard users with no visible focus. outline survives, and the\n // CanvasText fallback repaints it in the system palette.\n 'ds:outline-none',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n ].join(' '),\n);\n\n// The four `both`-view sub-charts stack in a tight column (no inter-row gap),\n// so the facial → occlusal → occlusal → facial rows read as one chart.\nconst bothStackVariants = cva(['ds:flex ds:flex-col ds:gap-0'].join(' '));\n\n// Responsive width: w-full lets the SVG grow to FILL a wider frame and h-auto\n// keeps the viewBox aspect. min-w-fit floors it at the viewBox's natural width\n// so it never scales the per-tooth tap target below the ≥44px AAA floor (WCAG\n// 2.5.5) — narrower frames scroll on the root rather than shrinking the teeth.\nconst svgVariants = cva(\n [\n 'ds:block',\n 'ds:w-full ds:min-w-fit ds:h-auto',\n 'ds:text-[var(--foreground)]',\n ].join(' '),\n);\n\n// `group` here is load-bearing — the focus-ring <rect> below uses\n// `group-focus-visible:opacity-100` to appear when the parent <g> takes\n// focus. Without this class the selector never fires and keyboard users\n// see no focus indicator (a11y-critical-fixes.mdx).\nconst toothGroupVariants = cva(\n [\n 'ds:group ds:cursor-pointer',\n 'ds:focus:outline-none',\n 'ds:transition-[fill,stroke,opacity] ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n ].join(' '),\n);\n\nconst legendVariants = cva(\n [\n 'ds:flex ds:flex-wrap ds:items-center',\n 'ds:gap-[var(--spacing-sm)]',\n 'type-meta ds:text-[var(--muted-foreground)]',\n ].join(' '),\n);\n\nconst legendItemVariants = cva(\n ['ds:inline-flex ds:items-center', 'ds:gap-[var(--spacing-xs)]'].join(' '),\n);\n\nconst liveRegionVariants = cva(['ds:sr-only'].join(' '));\n\n// Surface-zone affordance (plan view, interactive surface-picking). Invisible\n// until hovered (pointer) or focused (keyboard, drilled-in) — the marked\n// surface itself is shown by the photoreal per-surface overlay underneath.\nconst zoneVariants = cva(\n [\n 'ds:cursor-pointer ds:outline-none',\n 'ds:fill-transparent ds:stroke-transparent',\n 'ds:transition-[fill] ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n 'ds:hover:fill-[color-mix(in_srgb,var(--accent)_18%,transparent)]',\n // `:focus` as well as `:focus-visible` — a pointer drill-in moves focus\n // programmatically, so the browser's focus-visible heuristic does not match\n // and the newly focused zone would otherwise show nothing at all.\n 'ds:focus:fill-[color-mix(in_srgb,var(--accent)_22%,transparent)]',\n 'ds:focus:stroke-[var(--ring)]',\n 'ds:focus-visible:fill-[color-mix(in_srgb,var(--accent)_22%,transparent)]',\n 'ds:focus-visible:stroke-[var(--ring)]',\n 'ds:forced-colors:focus:stroke-[CanvasText]',\n 'ds:forced-colors:focus-visible:stroke-[CanvasText]',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nfunction isControlled(props: Pick<ToothSchemeProps, 'value'>): boolean {\n return props.value !== undefined;\n}\n\nfunction emptyState(): ToothState {\n return { conditions: [], surfaces: [] };\n}\n\n/** Toggle a whole-tooth finding on a symbol list (no tool → cycle caries). */\nfunction toggleSymbolCondition(\n symbols: ToothSymbol[],\n active: ConditionId | undefined,\n registry?: ConditionRegistry,\n): ToothSymbol[] {\n const condition: ConditionId = active ?? 'caries';\n const symbol: ToothSymbol = {\n condition,\n part: conditionPart(condition, registry),\n };\n // No tool selected → cycle caries on/off (legacy demo behaviour).\n if (!active) return symbols.length === 0 ? [symbol] : [];\n return symbols.some((entry) => entry.condition === condition)\n ? symbols.filter((entry) => entry.condition !== condition)\n : [...symbols, symbol];\n}\n\n/**\n * Toggle one surface or root inside the symbol carrying the active finding,\n * adding the symbol when the tooth has none. Each symbol scopes its OWN\n * surfaces / roots, so two fillings on one tooth stay distinct.\n */\nfunction toggleSymbolTarget(\n symbols: ToothSymbol[],\n condition: ConditionId,\n part: 'surface' | 'root',\n target: Surface | Root,\n): ToothSymbol[] {\n const covers = (entry: ToothSymbol): boolean =>\n part === 'surface'\n ? (entry.surfaces ?? []).includes(target as Surface)\n : (entry.roots ?? []).includes(target as Root);\n const sameCondition = (entry: ToothSymbol): boolean =>\n entry.condition === condition;\n // Un-marking edits the symbol the click actually falls in. Marking grows a\n // symbol only when it carries no provenance id — attributing a new surface to\n // someone else's care-plan entry would silently rewrite that record, so a\n // provenance-bound chart gets a new symbol instead. That is also what lets the\n // two-fillings-one-tooth shape be authored by clicking, not just by data.\n const index = symbols.findIndex(\n (entry) => sameCondition(entry) && covers(entry),\n );\n const growable = symbols.findIndex(\n (entry) => sameCondition(entry) && entry.id === undefined,\n );\n if (index < 0 && growable >= 0) {\n return toggleAt(symbols, growable, part, target);\n }\n if (index < 0) {\n const seed: ToothSymbol =\n part === 'surface'\n ? { condition, part, surfaces: [target as Surface] }\n : { condition, part, roots: [target as Root] };\n return [...symbols, seed];\n }\n return toggleAt(symbols, index, part, target);\n}\n\n/** Add or remove one surface / root inside the symbol at `index`. */\nfunction toggleAt(\n symbols: ToothSymbol[],\n index: number,\n part: 'surface' | 'root',\n target: Surface | Root,\n): ToothSymbol[] {\n const symbol = symbols[index];\n const current: (Surface | Root)[] =\n part === 'surface' ? (symbol.surfaces ?? []) : (symbol.roots ?? []);\n const next = current.includes(target)\n ? current.filter((entry) => entry !== target)\n : [...current, target];\n if (next.length === 0) return symbols.filter((_, i) => i !== index);\n const updated: ToothSymbol =\n part === 'surface'\n ? { ...symbol, part, surfaces: next as Surface[] }\n : { ...symbol, part, roots: next as Root[] };\n return symbols.map((entry, i) => (i === index ? updated : entry));\n}\n\n/**\n * Fold a symbol list back onto the legacy `conditions` + `surfaces` pair so\n * `data-condition` and consumers that predate `symbols` keep reading. Registry\n * ids are omitted — a legacy reader does not know that vocabulary.\n */\nfunction stateFromSymbols(\n symbols: ToothSymbol[],\n previous?: ToothState,\n): ToothState {\n const conditions: ToothCondition[] = [];\n const surfaces: Surface[] = [];\n for (const symbol of symbols) {\n if (\n isBuiltInCondition(symbol.condition) &&\n !conditions.includes(symbol.condition)\n ) {\n conditions.push(symbol.condition);\n }\n for (const surface of symbol.surfaces ?? []) {\n if (!surfaces.includes(surface)) surfaces.push(surface);\n }\n }\n return { ...(previous ?? emptyState()), conditions, surfaces, symbols };\n}\n\n/** Translate a special element to its accessible name. */\nfunction elementName(\n element: SpecialElement,\n t: (key: string, opts?: Record<string, unknown>) => string,\n): string {\n switch (element.labelKey) {\n case 'quadrant':\n return t('toothScheme.special.quadrant', { n: element.labelIndex });\n case 'sextant':\n return t('toothScheme.special.sextant', { n: element.labelIndex });\n case 'archUpper':\n return t('toothScheme.special.archUpper');\n case 'archLower':\n return t('toothScheme.special.archLower');\n default:\n return t('toothScheme.special.general');\n }\n}\n\n/**\n * Drill-in arrow navigation between a tooth's surface zones. 4-zone teeth map\n * each arrow straight to its zone; 5-zone teeth pivot through the occlusal\n * centre (every edge connects only to the centre, the centre to all edges).\n */\nfunction nextZone(\n zone: SurfaceZone,\n key: string,\n hasCenter: boolean,\n): SurfaceZone {\n if (!hasCenter) {\n if (key === 'ArrowUp') return 'top';\n if (key === 'ArrowDown') return 'bottom';\n if (key === 'ArrowLeft') return 'left';\n if (key === 'ArrowRight') return 'right';\n return zone;\n }\n const hub: Record<SurfaceZone, Partial<Record<string, SurfaceZone>>> = {\n top: { ArrowDown: 'center' },\n bottom: { ArrowUp: 'center' },\n left: { ArrowRight: 'center' },\n right: { ArrowLeft: 'center' },\n center: {\n ArrowUp: 'top',\n ArrowDown: 'bottom',\n ArrowLeft: 'left',\n ArrowRight: 'right',\n },\n };\n return hub[zone]?.[key] ?? zone;\n}\n\n/**\n * A tooth's roots in SCREEN order (left → centre → right). The palatal root\n * renders between the other two; mesial / distal flip across the midline, which\n * `rootScreenSide` already knows.\n */\nfunction orderedRoots(meta: ToothMeta): Root[] {\n const slot = (root: Root): number => {\n if (root === 'mesial' || root === 'distal')\n return rootScreenSide(meta, root) === 'left' ? 0 : 2;\n return 1;\n };\n return [...rootsForTooth(meta)].sort((a, b) => slot(a) - slot(b));\n}\n\n/** The roots a tooth can be drilled into — a single-rooted tooth has no choice. */\nfunction drillableRoots(meta: ToothMeta): Root[] {\n const roots = orderedRoots(meta);\n return roots.length > 1 ? roots : [];\n}\n\n/**\n * Drill-in arrow navigation between a tooth's roots. They lie in one\n * screen-ordered strip, so only the inline arrows step — there is no second\n * axis to move on.\n */\nfunction nextRoot(root: Root, key: string, roots: Root[]): Root {\n const index = roots.indexOf(root);\n if (index < 0) return root;\n if (key === 'ArrowRight') return roots[Math.min(roots.length - 1, index + 1)];\n if (key === 'ArrowLeft') return roots[Math.max(0, index - 1)];\n return root;\n}\n\ninterface SlotRect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\n/**\n * Hit strip for one root over the facial render. Roots point away from the\n * occlusal plane, so they occupy the block-start half of an upper tooth and the\n * block-end half of a lower one.\n */\n/**\n * A root's pick column. Root identity is the HORIZONTAL position — which is why\n * the column runs the full height of the slot rather than only the apical half:\n * a third of a 36-wide slot is a slim target already, and halving its height\n * again put it well under `--min-target-size`. While a tooth is drilled its\n * group is a `role=\"group\"`, so a full-height column competes with nothing.\n */\nfunction rootRect(index: number, count: number, rect: SlotRect): SlotRect {\n const w = rect.w / count;\n return { x: rect.x + index * w, y: rect.y, w, h: rect.h };\n}\n\n/* ------------------------------------------------------------------ */\n/* Legend */\n/* */\n/* Each entry shows the finding EXACTLY as it renders on the chart — a */\n/* mini tooth (the upper-right molar) carrying that finding's symbol */\n/* glyph, surface ring, or missing-X — so the key actually maps to the */\n/* scheme rather than to an abstract colour swatch. */\n/* ------------------------------------------------------------------ */\n\n/**\n * Fallback mark for a condition with no artwork in this projection — a\n * token-coloured badge carrying the registry glyph. The `--card` fill keeps the\n * text legible over the photoreal render in all four themes; the condition's\n * label rides in the tooth's accessible name, so the badge itself is decorative.\n */\nfunction GlyphMark({\n glyph,\n colour,\n cx,\n cy,\n opacity,\n testId,\n}: {\n glyph: string;\n colour: string;\n cx: number;\n cy: number;\n opacity?: number;\n testId?: string;\n}): ReactElement {\n const w = 9 + glyph.length * 5;\n return (\n <g\n transform={`translate(${cx - w / 2}, ${cy - 7})`}\n data-testid={testId}\n pointerEvents=\"none\"\n aria-hidden=\"true\"\n >\n {/* The planned dimming rides on the badge chrome only. Fading the glyph\n too would drag real text under the contrast floor (0.55 of\n `--foreground` on `--card` is ~3.3:1), and axe cannot see SVG text.\n Status still has two channels: the badge tint and the StatusDot. */}\n <rect\n width={w}\n height={14}\n rx=\"3.5\"\n fill=\"var(--card)\"\n stroke={colour}\n strokeWidth=\"1.5\"\n opacity={opacity}\n />\n <text\n x={w / 2}\n y={10}\n textAnchor=\"middle\"\n fontSize=\"9\"\n fontWeight=\"600\"\n fill=\"var(--foreground)\"\n className=\"ds:select-none\"\n >\n {glyph}\n </text>\n </g>\n );\n}\n\n/**\n * Execution-status marker: a filled disc for executed, a hollow ring for\n * planned. The shape is the second channel — the status token colour never\n * carries the distinction on its own.\n */\nfunction StatusDot({\n status,\n cx,\n cy,\n r,\n strokeWidth,\n testId,\n}: {\n status: SymbolStatus;\n cx: number;\n cy: number;\n r: number;\n strokeWidth: number;\n testId?: string;\n}): ReactElement {\n return (\n <circle\n cx={cx}\n cy={cy}\n r={r}\n fill={status === 'executed' ? STATUS_COLORS.executed : 'var(--card)'}\n stroke={STATUS_COLORS[status]}\n strokeWidth={strokeWidth}\n data-testid={testId}\n pointerEvents=\"none\"\n aria-hidden=\"true\"\n />\n );\n}\n\n/** Status rendering order — planned first, mirroring the care-plan flow. */\nconst STATUS_ORDER: SymbolStatus[] = ['planned', 'executed'];\n\n/** A 36×62 mini tooth rendering one finding, mirroring the chart's visuals. */\nfunction LegendSymbol({\n condition,\n assetBaseUrl,\n registry,\n}: {\n condition: ConditionId;\n assetBaseUrl: string;\n registry?: ConditionRegistry;\n}): ReactElement {\n const meta = FDI_TO_META['16'];\n const spec = conditionSideSymbol(condition, registry);\n const isMissing = condition === 'missing';\n const colour = conditionColor(condition, registry);\n // caries / filled carry no side artwork — the chart rings them instead.\n const isSurface =\n !spec && !isMissing && conditionHasArtwork(condition, 'side', registry);\n // Match the chart: the render is inset (scaled 0.9) so the surface ring and\n // missing-X never touch the tooth — the same fix applied to the live teeth.\n const w = 36 * 0.9;\n const h = 62 * 0.9;\n const x = (36 - w) / 2;\n const y = (62 - h) / 2;\n return (\n <svg\n width=\"22\"\n height=\"38\"\n viewBox=\"0 0 36 62\"\n aria-hidden=\"true\"\n className=\"ds:block ds:shrink-0\"\n >\n <image\n href={toothImageUrl(meta, assetBaseUrl)}\n x={x}\n y={y}\n width={w}\n height={h}\n preserveAspectRatio=\"xMidYMid meet\"\n opacity={isMissing ? 0.25 : 1}\n />\n {spec ? (\n <image\n href={conditionSymbolUrl(meta, assetBaseUrl, spec)}\n x={x}\n y={y}\n width={w}\n height={h}\n preserveAspectRatio=\"xMidYMid meet\"\n />\n ) : null}\n {isSurface ? (\n <rect\n x={3}\n y={2}\n width={30}\n height={58}\n fill=\"none\"\n stroke={colour}\n strokeWidth={2}\n strokeDasharray={condition === 'filled' ? '4 2' : undefined}\n rx={6}\n />\n ) : null}\n {isMissing ? (\n <path\n d=\"M7 9 L29 53 M29 9 L7 53\"\n stroke={CONDITION_COLORS.missing}\n strokeWidth={2}\n fill=\"none\"\n />\n ) : null}\n {!spec && !isSurface && !isMissing ? (\n <GlyphMark\n glyph={conditionGlyph(condition, registry)}\n colour={colour}\n cx={18}\n cy={31}\n />\n ) : null}\n </svg>\n );\n}\n\nfunction Legend({\n assetBaseUrl,\n registry,\n}: {\n assetBaseUrl: string;\n registry?: ConditionRegistry;\n}): ReactElement {\n const { t } = useTranslation();\n // Built-ins first, in the vocabulary's own order, then whatever the practice\n // registered — a registry entry that shadows a built-in shows once.\n const conditions: ConditionId[] = [\n ...TOOTH_CONDITIONS,\n ...(registry ?? [])\n .map((entry) => entry.id)\n .filter((id) => !isBuiltInCondition(id)),\n ];\n return (\n <section\n aria-label={t('toothScheme.legendLabel')}\n data-testid=\"tooth-scheme-legend\"\n // Matches the Card `elevated` variant exactly: --card surface, a subtle\n // --card-border, --shadow-card, and the thicker border in the accessible\n // theme. --muted-foreground on --card stays a validated pair.\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:rounded-[var(--radius-md)] ds:bg-[var(--card)] ds:border ds:border-[color:var(--card-border)] ds:p-[var(--spacing-sm)] ds:shadow-[var(--shadow-card)] ds:[.theme-accessible_&]:border-2\"\n >\n <span className=\"type-eyebrow ds:text-[color:var(--muted-foreground)]\">\n {t('toothScheme.legendLabel')}\n </span>\n <ul className={legendVariants()}>\n {conditions.map((condition) => {\n const label = conditionLabel(condition, registry);\n return (\n <li\n key={condition}\n className={legendItemVariants()}\n data-condition={condition}\n data-testid={`tooth-scheme-legend-item-${condition}`}\n >\n <LegendSymbol\n condition={condition}\n assetBaseUrl={assetBaseUrl}\n registry={registry}\n />\n <span>{label.kind === 'key' ? t(label.key) : label.text}</span>\n </li>\n );\n })}\n </ul>\n <span className=\"type-eyebrow ds:text-[color:var(--muted-foreground)]\">\n {t('toothScheme.legendStatusLabel')}\n </span>\n <ul className={legendVariants()}>\n {STATUS_ORDER.map((status) => (\n <li\n key={status}\n className={legendItemVariants()}\n data-status={status}\n data-testid={`tooth-scheme-legend-status-${status}`}\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n aria-hidden=\"true\"\n className=\"ds:block ds:shrink-0\"\n >\n <StatusDot\n status={status}\n cx={7}\n cy={7}\n r={5}\n strokeWidth={1.75}\n />\n </svg>\n <span>{t(statusLabelKey(status))}</span>\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\n// One labelled Select row inside the options popover. The label stacks ABOVE a\n// full-width Select so long option values (e.g. \"Permanent dentition\") fit on\n// one line. The visible label is `aria-hidden` (sighted-only) and duplicated as\n// the Select's `aria-label`, so screen-reader users get the name once.\nfunction OptionRow({\n label,\n value,\n options,\n onValueChange,\n container,\n}: {\n label: string;\n value: string;\n options: { value: string; label: string }[];\n onValueChange: (value: string) => void;\n container?: HTMLElement | null;\n}): ReactElement {\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <span\n aria-hidden=\"true\"\n className=\"type-label ds:text-[color:var(--muted-foreground)]\"\n >\n {label}\n </span>\n <Select\n size=\"md\"\n aria-label={label}\n value={value}\n options={options}\n onValueChange={onValueChange}\n // Keeps the listbox inside the popover's scroll container. Not needed\n // for stacking — dropdown and popover share a layer, so the listbox\n // already paints on top by portal order.\n container={container}\n />\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\n/** Sort radiographs newest-first; undated films sink to the end. */\nfunction sortByDateDesc(a: Radiograph, b: Radiograph): number {\n if (a.date === b.date) return 0;\n if (!a.date) return 1;\n if (!b.date) return -1;\n return a.date < b.date ? 1 : -1;\n}\n\nexport const ToothScheme = forwardRef<\n ToothSchemeHandle,\n ToothSchemeProps & ToothSchemeInternalProps\n>(\n (\n {\n id,\n dentition: dentitionProp = 'permanent',\n numbering: numberingProp = 'fdi',\n mode = 'interactive',\n projection: projectionProp = 'side',\n specialElements: specialElementsProp,\n value,\n defaultValue,\n onChange,\n onSelect,\n conditions,\n radiographs,\n radiographDisplay = 'badge',\n onOpenRadiographs,\n activeCondition,\n conditionRegistry,\n assetBaseUrl = '/toothscheme/teeth',\n legend: legendProp = false,\n controls = false,\n controlsContainer,\n ariaLabel,\n className,\n _arch,\n _numbersPosition = 'between',\n _inner = false,\n _contentWidth,\n },\n ref,\n ) => {\n const { t } = useTranslation();\n\n // User-facing options (the gear popover). When `controls` is on, the\n // chart's dentition / numbering / projection / legend / special elements\n // become user-overridable: internal state is seeded from the props and the\n // popover updates it. When `controls` is off, the props drive the chart\n // directly (the component stays fully controlled for consumers who don't\n // want it).\n const [uiDentition, setUiDentition] = useState<Dentition>(dentitionProp);\n const [uiNumbering, setUiNumbering] = useState<Numbering>(numberingProp);\n const [uiProjection, setUiProjection] = useState<ViewMode>(projectionProp);\n const [uiLegend, setUiLegend] = useState<boolean>(legendProp);\n const [uiSpecial, setUiSpecial] = useState<boolean | undefined>(\n specialElementsProp,\n );\n\n // Portal target for the option selects, captured from the popover content\n // so their listboxes render above the popover (not behind it).\n const [optionsPopoverEl, setOptionsPopoverEl] =\n useState<HTMLElement | null>(null);\n\n const dentition = controls ? uiDentition : dentitionProp;\n const numbering = controls ? uiNumbering : numberingProp;\n const legend = controls ? uiLegend : legendProp;\n // The View select can pick a single projection or 'both'. The single\n // projections render one chart; 'both' lays four arch-scoped sub-charts so\n // the occlusal rows sit between the facial rows.\n const viewMode: ViewMode = controls ? uiProjection : projectionProp;\n const projection: Projection = viewMode === 'plan' ? 'plan' : 'side';\n const showBoth = viewMode === 'both' && !_inner;\n // Special elements default to visible in the `both` view and hidden in the\n // single side / plan views; an explicit prop (or the gear toggle) overrides.\n const specialAuto = viewMode === 'both';\n const showSpecials = controls\n ? (uiSpecial ?? specialAuto)\n : (specialElementsProp ?? specialAuto);\n\n // The `ui*` seeds above only run once (at mount). If `controls` flips on\n // later, re-seed from the current props so the popover opens from the\n // consumer's latest values rather than the stale mount-time snapshot.\n const controlsWasOn = useRef(controls);\n useEffect(() => {\n if (controls && !controlsWasOn.current) {\n setUiDentition(dentitionProp);\n setUiNumbering(numberingProp);\n setUiProjection(projectionProp);\n setUiLegend(legendProp);\n setUiSpecial(specialElementsProp);\n }\n controlsWasOn.current = controls;\n }, [\n controls,\n dentitionProp,\n numberingProp,\n projectionProp,\n legendProp,\n specialElementsProp,\n ]);\n\n // Chart state — controlled / uncontrolled.\n const [internalChart, setInternalChart] = useState<ToothChart>(() => {\n if (value !== undefined) return value;\n if (defaultValue !== undefined) return defaultValue;\n if (conditions) return chartFromConditions(conditions);\n return {};\n });\n\n const chart: ToothChart = isControlled({ value })\n ? (value as ToothChart)\n : internalChart;\n\n // Keep uncontrolled chart in sync when `conditions` shortcut updates.\n useEffect(() => {\n if (isControlled({ value })) return;\n if (conditions === undefined) return;\n setInternalChart(chartFromConditions(conditions));\n // Intentionally depend on a stable key — swapping the entire prop\n // snapshot is the consumer's signal to reset.\n }, [conditions, value]);\n\n // Plan (occlusal) teeth are square; facial teeth are tall (crown + root).\n const slotHeight = projection === 'plan' ? 44 : TOOTH_SLOT_HEIGHT;\n\n // Layout — single-arch (a `both`-view sub-chart) or both arches.\n const layout = useMemo(\n () => layoutTeeth(dentition, slotHeight, _arch ? { arch: _arch } : {}),\n [dentition, slotHeight, _arch],\n );\n\n // Special-element slots positioned to the inline-end of each arch row.\n const specials = useMemo<PositionedSpecial[]>(() => {\n if (!showSpecials) return [];\n if (_arch) {\n // A `both`-view sub-chart: one arch row, specials at y = 0.\n return layoutSpecials(\n specialsForRow(dentition, _arch, projection),\n layout.width,\n ).specials;\n }\n // Single-projection chart: specials attach to both arch rows.\n const upper = layoutSpecials(\n specialsForRow(dentition, 'upper', projection),\n layout.width,\n ).specials;\n const lowerRowY = slotHeight + TOOTH_ROW_GAP;\n const lower = layoutSpecials(\n specialsForRow(dentition, 'lower', projection),\n layout.width,\n ).specials.map((s) => ({ ...s, y: lowerRowY }));\n return [...upper, ...lower];\n }, [showSpecials, _arch, dentition, projection, layout.width, slotHeight]);\n\n // The `both` view pins every sub-chart to the widest row's width (upper\n // facial carries the most columns: Q1, Q2, AS, Gen.) so all four scale\n // identically and stay column-aligned.\n const bothContentWidth = useMemo(() => {\n if (!showBoth) return undefined;\n if (!showSpecials) return layout.width;\n let max = layout.width;\n for (const arch of ['upper', 'lower'] as Arch[]) {\n for (const proj of ['side', 'plan'] as Projection[]) {\n const w = layoutSpecials(\n specialsForRow(dentition, arch, proj),\n layout.width,\n ).width;\n if (w > max) max = w;\n }\n }\n return max;\n }, [showBoth, showSpecials, dentition, layout.width]);\n\n const visibleIds = useMemo(\n () => [\n ...layout.teeth.map((tooth) => tooth.fdi),\n // Special slots join keyboard nav only when interactive — in display /\n // radiograph-open mode they are decorative (role=\"img\"), so the\n // radiograph-open keyboard path never reaches a region id.\n ...(mode === 'interactive' ? specials.map((s) => s.element.id) : []),\n ],\n [layout, specials, mode],\n );\n\n // Roving tabindex: which slot (tooth or special) owns `tabindex=\"0\"`.\n const firstId: FdiId | undefined = visibleIds[0];\n const [focusedId, setFocusedId] = useState<FdiId | undefined>(firstId);\n useEffect(() => {\n if (!focusedId || !visibleIds.includes(focusedId)) {\n setFocusedId(firstId);\n }\n }, [firstId, focusedId, visibleIds]);\n\n // Live-region announcement text.\n const [announcement, setAnnouncement] = useState<string>('');\n\n const svgRef = useRef<SVGSVGElement>(null);\n\n const commitChart = useCallback(\n (next: ToothChart) => {\n if (!isControlled({ value })) {\n setInternalChart(next);\n }\n onChange?.(next);\n },\n [onChange, value],\n );\n\n const focusToothById = useCallback((id: FdiId) => {\n const svg = svgRef.current;\n if (!svg) return;\n const node = svg.querySelector<SVGGElement>(`g[data-fdi=\"${id}\"]`);\n if (node) {\n node.focus();\n setFocusedId(id);\n }\n }, []);\n\n // A condition's display name — a registry entry carries its own translated\n // text, a built-in resolves to its `ui.toothScheme.condition.*` key.\n const labelOf = useCallback(\n (condition: ConditionId): string => {\n const label = conditionLabel(condition, conditionRegistry);\n return label.kind === 'key' ? t(label.key) : label.text;\n },\n [t, conditionRegistry],\n );\n\n // One symbol as text. Scope (the roots or surfaces it covers) and status are\n // folded in here so both reach the accessible name, the tooltip and the live\n // region together — never colour alone, and never two root canals on one\n // molar reading alike. A drill target passes `scoped: false`, since the\n // element the name belongs to already IS the scope.\n const symbolText = useCallback(\n (symbol: ToothSymbol, scoped = true): string => {\n const condition = labelOf(symbol.condition);\n const scope = !scoped\n ? ''\n : (symbol.roots?.length\n ? symbol.roots.map((root) => t(`toothScheme.root.${root}`))\n : (symbol.surfaces ?? []).map((surface) =>\n t(`toothScheme.surface.${surface}`),\n )\n ).join(', ');\n const status = symbol.status ? t(statusLabelKey(symbol.status)) : '';\n if (scope && status)\n return t('toothScheme.symbolWithScopeAndStatus', {\n condition,\n scope,\n status,\n });\n if (scope)\n return t('toothScheme.symbolWithScope', { condition, scope });\n if (status)\n return t('toothScheme.symbolWithStatus', { condition, status });\n return condition;\n },\n [labelOf, t],\n );\n\n // What one root / surface carries, for the drill target's own name.\n // `aria-pressed` there tracks the ARMED TOOL, so without this a finding\n // charted with a different tool is unreadable to a screen reader.\n const targetSuffix = useCallback(\n (\n symbols: ToothSymbol[],\n part: 'surface' | 'root',\n target: Surface | Root,\n ): string =>\n symbols\n .filter((symbol) =>\n part === 'surface'\n ? (symbol.surfaces ?? []).includes(target as Surface)\n : (symbol.roots ?? []).includes(target as Root),\n )\n .map((symbol) => `, ${symbolText(symbol, false)}`)\n .join(''),\n [symbolText],\n );\n\n // The announcement string for selecting / deselecting a tooth or element.\n const buildAnnouncement = useCallback(\n (id: FdiId, symbols: ToothSymbol[]): string => {\n const conditionText = symbols.map((s) => symbolText(s)).join(', ');\n if (isSpecialElement(id)) {\n const name = elementName(SPECIAL_BY_ID[id], t);\n return symbols.length > 0\n ? t('toothScheme.elementSelected', {\n name,\n conditions: conditionText,\n })\n : t('toothScheme.elementDeselected', { name });\n }\n return symbols.length > 0\n ? t('toothScheme.selected', { id, conditions: conditionText })\n : t('toothScheme.deselected', { id });\n },\n [symbolText, t],\n );\n\n // The ONE write path. Every edit builds a symbol list and folds it back\n // onto `conditions` / `surfaces`, so the rich and legacy shapes stay in\n // step and nothing reads a stale flat list.\n const writeSymbols = useCallback(\n (fdi: FdiId, symbols: ToothSymbol[]) => {\n const next: ToothChart = { ...chart };\n if (symbols.length === 0) {\n delete next[fdi];\n } else {\n next[fdi] = stateFromSymbols(symbols, chart[fdi]);\n }\n commitChart(next);\n },\n [chart, commitChart],\n );\n\n // As `writeSymbols`, plus the announcement + selection callback a user\n // edit owes. The imperative handle writes silently instead.\n const commitSymbols = useCallback(\n (fdi: FdiId, symbols: ToothSymbol[]) => {\n writeSymbols(fdi, symbols);\n setAnnouncement(buildAnnouncement(fdi, symbols));\n onSelect?.(fdi);\n },\n [buildAnnouncement, onSelect, writeSymbols],\n );\n\n /* ------------------------------------------------------------- */\n /* Drill-in picking — surfaces (plan) and roots (side) */\n /* ------------------------------------------------------------- */\n\n // Which layer the selected tool marks decides what a tooth drills into: a\n // surface tool (caries / filling) picks surfaces in the occlusal view, a\n // root tool (root canal, post, apicectomy) picks roots in the facial view.\n const activePart = activeCondition\n ? conditionPart(activeCondition, conditionRegistry)\n : undefined;\n const surfacePicking =\n projection === 'plan' &&\n mode === 'interactive' &&\n activePart === 'surface';\n const rootPicking =\n projection === 'side' && mode === 'interactive' && activePart === 'root';\n\n // Drill-in state: the tooth + surface zone or root the keyboard is\n // currently inside (null = tooth-level navigation, the default).\n const [drilled, setDrilled] = useState<Drill | null>(null);\n\n // End the drill if its picking mode turns off (tool / view change) OR the\n // drilled tooth leaves the layout (e.g. the dentition changes mid-drill) —\n // a stale drill would leave every tooth tabIndex=-1 and lock out keyboard.\n useEffect(() => {\n if (!drilled) return;\n const live = drilled.part === 'surface' ? surfacePicking : rootPicking;\n if (!live || !visibleIds.includes(drilled.fdi)) setDrilled(null);\n }, [surfacePicking, rootPicking, drilled, visibleIds]);\n\n const focusDrill = useCallback((drill: Drill) => {\n const selector =\n drill.part === 'surface'\n ? `path[data-fdi=\"${drill.fdi}\"][data-zone=\"${drill.zone}\"]`\n : `rect[data-fdi=\"${drill.fdi}\"][data-root=\"${drill.root}\"]`;\n svgRef.current?.querySelector<SVGGraphicsElement>(selector)?.focus();\n }, []);\n\n // Set by the user-driven exits (Escape) so focus returns to the tooth it\n // came from. The teardown above deliberately leaves it unset: a drill that\n // ends because a sibling palette changed tool must not pull focus back into\n // the chart and out from under the user.\n const restoreFocusTo = useRef<FdiId | null>(null);\n\n // Move DOM focus onto the drilled target when it changes; restore it to the\n // tooth only when an exit asked for it.\n useEffect(() => {\n if (drilled) {\n focusDrill(drilled);\n return;\n }\n const fdi = restoreFocusTo.current;\n restoreFocusTo.current = null;\n if (fdi) focusToothById(fdi);\n }, [drilled, focusDrill, focusToothById]);\n\n // `aria-pressed` on a zone / root reflects the ACTIVE TOOL, not any finding\n // — switching tools repaints every pressed state.\n const isTargetMarked = useCallback(\n (\n fdi: FdiId,\n part: 'surface' | 'root',\n target: Surface | Root,\n ): boolean => {\n if (!activeCondition) return false;\n return symbolsForTooth(chart[fdi], conditionRegistry).some(\n (symbol) =>\n symbol.condition === activeCondition &&\n (part === 'surface'\n ? (symbol.surfaces ?? []).includes(target as Surface)\n : (symbol.roots ?? []).includes(target as Root)),\n );\n },\n [activeCondition, chart, conditionRegistry],\n );\n\n const toggleTarget = useCallback(\n (fdi: FdiId, part: 'surface' | 'root', target: Surface | Root) => {\n if (!activeCondition) return;\n if (part === 'surface' ? !surfacePicking : !rootPicking) return;\n const symbols = symbolsForTooth(chart[fdi], conditionRegistry);\n commitSymbols(\n fdi,\n toggleSymbolTarget(symbols, activeCondition, part, target),\n );\n },\n [\n activeCondition,\n chart,\n commitSymbols,\n conditionRegistry,\n rootPicking,\n surfacePicking,\n ],\n );\n\n const drillInto = useCallback(\n (fdi: FdiId) => {\n const meta = FDI_TO_META[fdi];\n if (!meta) return;\n setFocusedId(fdi);\n if (surfacePicking) {\n setDrilled({ fdi, part: 'surface', zone: zonesForTooth(meta)[0] });\n return;\n }\n const roots = drillableRoots(meta);\n if (roots.length > 0) setDrilled({ fdi, part: 'root', root: roots[0] });\n },\n [surfacePicking],\n );\n\n const handleSurfaceKeyDown = useCallback(\n (event: KeyboardEvent<SVGPathElement>, fdi: FdiId, zone: SurfaceZone) => {\n const meta = FDI_TO_META[fdi];\n if (!meta) return;\n switch (event.key) {\n case 'ArrowUp':\n case 'ArrowDown':\n case 'ArrowLeft':\n case 'ArrowRight': {\n event.preventDefault();\n event.stopPropagation();\n const hasCenter = zonesForTooth(meta).includes('center');\n const nz = nextZone(zone, event.key, hasCenter);\n if (nz !== zone) setDrilled({ fdi, part: 'surface', zone: nz });\n return;\n }\n case ' ':\n case 'Enter': {\n event.preventDefault();\n event.stopPropagation();\n toggleTarget(fdi, 'surface', zoneSurface(meta, zone));\n return;\n }\n case 'Escape': {\n event.preventDefault();\n event.stopPropagation();\n restoreFocusTo.current = fdi;\n setDrilled(null);\n return;\n }\n default:\n return;\n }\n },\n [toggleTarget],\n );\n\n const handleRootKeyDown = useCallback(\n (event: KeyboardEvent<SVGRectElement>, fdi: FdiId, root: Root) => {\n const meta = FDI_TO_META[fdi];\n if (!meta) return;\n switch (event.key) {\n case 'ArrowUp':\n case 'ArrowDown':\n case 'ArrowLeft':\n case 'ArrowRight': {\n event.preventDefault();\n event.stopPropagation();\n const nr = nextRoot(root, event.key, drillableRoots(meta));\n if (nr !== root) setDrilled({ fdi, part: 'root', root: nr });\n return;\n }\n case ' ':\n case 'Enter': {\n event.preventDefault();\n event.stopPropagation();\n toggleTarget(fdi, 'root', root);\n return;\n }\n case 'Escape': {\n event.preventDefault();\n event.stopPropagation();\n restoreFocusTo.current = fdi;\n setDrilled(null);\n return;\n }\n default:\n return;\n }\n },\n [toggleTarget],\n );\n\n const rootRef = useRef<HTMLDivElement>(null);\n\n // Radiograph \"open archive\" affordance. In display mode, when an open\n // handler is provided, each tooth becomes a button that opens its film\n // archive — reusing the roving-tabindex + button wiring (no nested\n // interactivity), mutually exclusive with interactive findings-editing.\n const radiographOpenable =\n mode === 'display' && typeof onOpenRadiographs === 'function';\n // Teeth are keyboard-focusable in interactive mode OR radiograph-open mode.\n const teethFocusable = mode === 'interactive' || radiographOpenable;\n\n const handleOpenRadiographs = useCallback(\n (id: FdiId) => {\n setFocusedId(id);\n onSelect?.(id);\n onOpenRadiographs?.(id);\n },\n [onSelect, onOpenRadiographs],\n );\n\n const agentHandle = useMemo<ToothSchemeHandle>(\n () => ({\n focusTooth: (id: FdiId) => {\n focusToothById(id);\n },\n getChart: () => chart,\n getTooth: (id: FdiId) =>\n symbolsForTooth(chart[id], conditionRegistry)\n .map((symbol) => symbol.condition)\n .filter(isBuiltInCondition),\n getSymbols: (id: FdiId) =>\n symbolsForTooth(chart[id], conditionRegistry),\n teethWith: (condition: ToothCondition) =>\n Object.keys(chart).filter((fdi) =>\n symbolsForTooth(chart[fdi], conditionRegistry).some(\n (symbol) => symbol.condition === condition,\n ),\n ),\n teethWithSymbol: (condition: ConditionId) =>\n Object.keys(chart).filter((fdi) =>\n symbolsForTooth(chart[fdi], conditionRegistry).some(\n (symbol) => symbol.condition === condition,\n ),\n ),\n setFinding: (\n id: FdiId,\n condition: ToothCondition,\n surfaces?: Surface[],\n ) => {\n const symbols = symbolsForTooth(chart[id], conditionRegistry);\n const index = symbols.findIndex(\n (symbol) => symbol.condition === condition,\n );\n if (index >= 0 && !surfaces) return;\n const part = conditionPart(condition, conditionRegistry);\n writeSymbols(\n id,\n index >= 0\n ? symbols.map((symbol, i) =>\n i === index ? { ...symbol, surfaces } : symbol,\n )\n : [...symbols, { condition, part, surfaces }],\n );\n },\n setSymbol: (id: FdiId, symbol: ToothSymbol) => {\n const symbols = symbolsForTooth(chart[id], conditionRegistry);\n const index = symbol.id\n ? symbols.findIndex((entry) => entry.id === symbol.id)\n : symbols.findIndex(\n (entry) => entry.condition === symbol.condition,\n );\n writeSymbols(\n id,\n index >= 0\n ? symbols.map((entry, i) => (i === index ? symbol : entry))\n : [...symbols, symbol],\n );\n },\n removeFinding: (id: FdiId, condition: ToothCondition) => {\n const symbols = symbolsForTooth(chart[id], conditionRegistry);\n const next = symbols.filter(\n (symbol) => symbol.condition !== condition,\n );\n if (next.length === symbols.length) return;\n writeSymbols(id, next);\n },\n clearTooth: (id: FdiId) => {\n if (!chart[id]) return;\n const next: ToothChart = { ...chart };\n delete next[id];\n commitChart(next);\n },\n getRadiographs: (id: FdiId) => radiographs?.[id] ?? [],\n teethWithRadiographs: () =>\n Object.keys(radiographs ?? {}).filter(\n (fdi) => (radiographs?.[fdi]?.length ?? 0) > 0,\n ),\n openRadiographs: (id: FdiId) => {\n focusToothById(id);\n handleOpenRadiographs(id);\n },\n }),\n [\n chart,\n commitChart,\n conditionRegistry,\n focusToothById,\n radiographs,\n handleOpenRadiographs,\n writeSymbols,\n ],\n );\n useImperativeHandle(ref, () => agentHandle, [agentHandle]);\n // Only the outer chart registers with the agent registry; the inner\n // `both`-view sub-charts share its chart data and pass no id, so the\n // registration is a no-op for them (guarded on a truthy instanceId).\n useAgentRegistration(\n toothSchemeAgent,\n agentHandle,\n _inner ? undefined : id,\n );\n\n /* ------------------------------------------------------------- */\n /* Keyboard navigation */\n /* ------------------------------------------------------------- */\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<SVGGElement>, id: FdiId) => {\n if (!teethFocusable) return;\n // `meta` is undefined for a special-element slot — those skip the\n // tooth-only vertical / quadrant navigation but keep linear nav + activation.\n const meta = FDI_TO_META[id];\n\n // Resolve the ordered list of visible ids for Left/Right.\n const order = visibleIds;\n const currentIndex = order.indexOf(id);\n\n switch (event.key) {\n case 'ArrowRight': {\n event.preventDefault();\n const nextIndex = Math.min(order.length - 1, currentIndex + 1);\n focusToothById(order[nextIndex]);\n return;\n }\n case 'ArrowLeft': {\n event.preventDefault();\n const nextIndex = Math.max(0, currentIndex - 1);\n focusToothById(order[nextIndex]);\n return;\n }\n case 'ArrowUp':\n case 'ArrowDown': {\n event.preventDefault();\n if (!meta) return;\n // Map to the opposing arch, same FDI position where possible.\n // Permanent: 1 ↔ 4, 2 ↔ 3. Primary: 5 ↔ 8, 6 ↔ 7.\n const quadrantMap: Record<number, number> = {\n 1: 4,\n 4: 1,\n 2: 3,\n 3: 2,\n 5: 8,\n 8: 5,\n 6: 7,\n 7: 6,\n };\n const targetQuadrant = quadrantMap[meta.quadrant];\n if (!targetQuadrant) return;\n const candidate = `${targetQuadrant}${meta.positionInQuadrant}`;\n if (order.includes(candidate)) {\n focusToothById(candidate);\n }\n return;\n }\n case 'Home': {\n event.preventDefault();\n if (!meta) return;\n // First tooth in the same quadrant (visible).\n const inQuadrant = order.filter(\n (other) => FDI_TO_META[other]?.quadrant === meta.quadrant,\n );\n if (inQuadrant.length > 0) {\n focusToothById(inQuadrant[0]);\n }\n return;\n }\n case 'End': {\n event.preventDefault();\n if (!meta) return;\n const inQuadrant = order.filter(\n (other) => FDI_TO_META[other]?.quadrant === meta.quadrant,\n );\n if (inQuadrant.length > 0) {\n focusToothById(inQuadrant[inQuadrant.length - 1]);\n }\n return;\n }\n case ' ':\n case 'Enter': {\n event.preventDefault();\n // Radiograph-open mode: Enter/Space opens the tooth's film archive\n // rather than editing findings.\n if (radiographOpenable) {\n handleOpenRadiographs(id);\n return;\n }\n // In a picking mode, Enter drills into the tooth's surfaces or\n // roots rather than toggling the whole tooth (teeth only, and only\n // where there is something to choose between).\n if (\n meta &&\n (surfacePicking ||\n (rootPicking && drillableRoots(meta).length > 0))\n ) {\n drillInto(id);\n return;\n }\n commitSymbols(\n id,\n toggleSymbolCondition(\n symbolsForTooth(chart[id], conditionRegistry),\n activeCondition,\n conditionRegistry,\n ),\n );\n return;\n }\n default:\n return;\n }\n },\n [\n activeCondition,\n chart,\n commitSymbols,\n conditionRegistry,\n drillInto,\n focusToothById,\n handleOpenRadiographs,\n radiographOpenable,\n rootPicking,\n surfacePicking,\n teethFocusable,\n visibleIds,\n ],\n );\n\n const handleClick = useCallback(\n (id: FdiId) => {\n if (mode !== 'interactive') return;\n setFocusedId(id);\n commitSymbols(\n id,\n toggleSymbolCondition(\n symbolsForTooth(chart[id], conditionRegistry),\n activeCondition,\n conditionRegistry,\n ),\n );\n },\n [activeCondition, chart, commitSymbols, conditionRegistry, mode],\n );\n\n // The whole-mouth `general` element is a switch beneath the chart (not a\n // column). It carries the active finding (or caries by default) across the\n // whole mouth — on records it, off clears it.\n const generalId: FdiId = dentition === 'primary' ? 'mGeneral' : 'general';\n const generalChecked =\n symbolsForTooth(chart[generalId], conditionRegistry).length > 0;\n const toggleGeneral = useCallback(\n (checked: boolean) => {\n const condition: ConditionId = activeCondition ?? 'caries';\n commitSymbols(\n generalId,\n checked\n ? [{ condition, part: conditionPart(condition, conditionRegistry) }]\n : [],\n );\n },\n [activeCondition, commitSymbols, conditionRegistry, generalId],\n );\n\n /* ------------------------------------------------------------- */\n /* Rendering */\n /* ------------------------------------------------------------- */\n\n // Number-label headroom: `above` lifts numbers over the crowns (negative y),\n // `below` drops them under (past the slot); the single-view `between`\n // placement keeps numbers in the inter-arch gap, so it needs no extra pad.\n const topPad = _numbersPosition === 'above' ? 16 : 2;\n const bottomPad = _numbersPosition === 'below' ? 16 : 2;\n const specialsWidth =\n specials.length > 0\n ? Math.max(...specials.map((s) => s.x)) + SPECIAL_SLOT_WIDTH\n : 0;\n // `_contentWidth` (set on the four `both`-view sub-charts) pins every row to\n // one width so they scale identically; otherwise each row sizes to its own\n // content and a row with fewer special columns would render larger.\n const contentWidth = Math.max(\n _contentWidth ?? 0,\n layout.width,\n specialsWidth,\n );\n const viewBoxWidth = contentWidth + 4;\n const viewBoxHeight = layout.height + topPad + bottomPad;\n\n const baseLabel = ariaLabel ?? t('toothScheme.ariaLabel');\n\n // The root is horizontally scrollable (`overflow-x-auto`), so it needs\n // keyboard access. In interactive mode the roving-tabindex teeth supply\n // it; in display mode nothing inside is focusable, so the scroll\n // container itself becomes the tab stop (WCAG 2.1.1 / axe\n // scrollable-region-focusable).\n const scrollTabIndex = teethFocusable ? undefined : 0;\n\n // The chart `<svg>` — reused for the single-projection view (this instance)\n // and each `both`-view sub-chart (an `_inner` instance). Built only when\n // this instance renders its own teeth (i.e. NOT the `both`-view outer host).\n const chartSvg = showBoth ? null : (\n <svg\n ref={svgRef}\n viewBox={`0 ${-topPad} ${viewBoxWidth} ${viewBoxHeight}`}\n width={viewBoxWidth}\n height={viewBoxHeight}\n className={svgVariants()}\n role=\"group\"\n aria-label={baseLabel}\n // Never a tab stop itself — keyboard focus lives on the teeth\n // (interactive) or the scroll container (display). Legacy engines\n // make a labelled SVG focusable without this.\n focusable=\"false\"\n data-testid=\"tooth-scheme-svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n {layout.teeth.map((tooth) => {\n // ONE read path: legacy `conditions` + `surfaces` and the rich\n // `symbols` list both arrive here as symbols, each scoping its own\n // surfaces and roots.\n const symbols = symbolsForTooth(chart[tooth.fdi], conditionRegistry);\n const primaryCondition: ConditionId | undefined =\n symbols[0]?.condition;\n\n const anatomyLabel = t(`toothScheme.anatomy.${tooth.meta.anatomy}`);\n // EVERY symbol is named, not just the first — a tooth carrying two\n // findings used to paint two glyphs and report one.\n const conditionSuffix = symbols\n .map((symbol) => `, ${symbolText(symbol)}`)\n .join('');\n const toothRadiographs = radiographs?.[tooth.fdi] ?? [];\n const radiographCount = toothRadiographs.length;\n const hasRadiographs = radiographCount > 0;\n // Most-recent film (newest date first; undated sink last) drives\n // the thumbnail + tooltip.\n const latestRadiograph = hasRadiographs\n ? [...toothRadiographs].sort(sortByDateDesc)[0]\n : undefined;\n const showThumbnail =\n radiographDisplay === 'thumbnail' && latestRadiograph !== undefined;\n // Surface the radiograph count to AT via the accessible name so\n // it is announced, not signalled by the corner badge alone.\n const radiographSuffix = hasRadiographs\n ? `, ${t('toothScheme.radiographBadge', { count: radiographCount })}`\n : '';\n // In the `both` view the same tooth renders in a facial AND an\n // occlusal sub-chart — fold the projection into the name so a screen\n // reader can tell the two apart (a `role=\"group\"` name is not reliably\n // announced on a focused SVG descendant).\n const projectionSuffix = _inner\n ? `, ${\n projection === 'plan'\n ? t('toothScheme.view.occlusal')\n : t('toothScheme.view.side')\n }`\n : '';\n const label =\n t('toothScheme.toothLabel', {\n id: labelFor(tooth.fdi, numbering),\n anatomy: anatomyLabel,\n conditionSuffix,\n }) +\n radiographSuffix +\n projectionSuffix;\n\n const tabIndex = teethFocusable\n ? drilled\n ? -1\n : tooth.fdi === focusedId\n ? 0\n : -1\n : undefined;\n\n const isMissing = symbols.some(\n (symbol) => symbol.condition === 'missing',\n );\n // Whole-tooth findings (crown, implant, RCT…) overlay a photoreal\n // symbol render, resolved per projection so the occlusal view no\n // longer drops them. A symbol scoped to roots paints one per root.\n const symbolOverlays = symbols.flatMap((symbol, index) => {\n const spec =\n projection === 'side'\n ? conditionSideSymbol(symbol.condition, conditionRegistry)\n : conditionPlanSymbol(symbol.condition, conditionRegistry);\n if (!spec) return [];\n const roots: (Root | undefined)[] = symbol.roots?.length\n ? symbol.roots\n : [undefined];\n // `region` picks the placement of a gingival-surgery marker\n // (left / right / total / repeat); without it every one of them\n // resolves to `repeat`.\n return roots.map((root) => ({\n key: `${index}-${symbol.condition}-${root ?? 'whole'}`,\n url:\n projection === 'side'\n ? conditionSymbolUrl(tooth.meta, assetBaseUrl, spec, {\n root,\n region: symbol.region,\n })\n : planSymbolUrl(tooth.meta, assetBaseUrl, spec, {\n root,\n region: symbol.region,\n }),\n opacity: symbol.status ? STATUS_OPACITY[symbol.status] : 1,\n }));\n });\n // A finding with no artwork in this projection falls back to its\n // glyph badge — the seam that lets a practice-defined finding chart\n // before a designer draws it.\n const glyphMarks = symbols\n .filter(\n (symbol) =>\n !conditionHasArtwork(\n symbol.condition,\n projection,\n conditionRegistry,\n ),\n )\n .map((symbol, index) => ({\n key: `${symbol.condition}-${index}`,\n condition: symbol.condition,\n glyph: conditionGlyph(symbol.condition, conditionRegistry),\n colour: symbolColor(symbol, conditionRegistry),\n opacity: symbol.status ? STATUS_OPACITY[symbol.status] : 1,\n }));\n // Surface findings (caries / filled) have no side symbol — flag\n // them with a token-coloured ring in the facial view.\n const ringSymbol = symbols.find(\n (symbol) =>\n symbol.condition !== 'missing' &&\n !conditionSideSymbol(symbol.condition, conditionRegistry) &&\n conditionHasArtwork(symbol.condition, 'side', conditionRegistry),\n );\n const ringColour = ringSymbol\n ? symbolColor(ringSymbol, conditionRegistry)\n : undefined;\n // Planned vs executed: the token colour rides on a pip whose SHAPE\n // also differs, and the symbols themselves render lighter when\n // planned. One pip per distinct status on the tooth.\n const statuses = STATUS_ORDER.filter((status) =>\n symbols.some((symbol) => symbol.status === status),\n );\n\n const tooltipContent =\n (symbols.length > 0\n ? `${anatomyLabel} · ${symbols.map((s) => symbolText(s)).join(' · ')}`\n : anatomyLabel) +\n (hasRadiographs\n ? ` · ${t('toothScheme.radiographBadge', { count: radiographCount })}`\n : '');\n\n const labelText = labelFor(tooth.fdi, numbering);\n const imageUrl = toothImageUrl(\n tooth.meta,\n assetBaseUrl,\n 'default',\n projection,\n );\n // In thumbnail display the most-recent film fills the slot\n // (cropped via `slice`) in place of the photoreal render.\n const slotImageHref =\n showThumbnail && latestRadiograph\n ? (latestRadiograph.thumbnailUrl ?? latestRadiograph.url)\n : imageUrl;\n // Plan (occlusal) view: per-surface caries / filling overlays — the\n // \"Stato dentale\" surface marking. Each symbol paints only ITS OWN\n // surfaces, so a mesial filling and a distal one stay apart.\n const surfaceOverlays =\n projection === 'plan'\n ? symbols.flatMap((symbol, index) => {\n const folder = conditionPlanFolder(\n symbol.condition,\n conditionRegistry,\n );\n if (!folder) return [];\n return (symbol.surfaces ?? []).map((surface) => ({\n key: `${index}-${symbol.condition}-${surface}`,\n url: surfaceSymbolUrl(\n tooth.meta,\n assetBaseUrl,\n folder,\n surface,\n ),\n opacity: symbol.status ? STATUS_OPACITY[symbol.status] : 1,\n }));\n })\n : [];\n\n // Primary teeth reuse the permanent render scaled down. A small\n // inset on every tooth keeps the render off the slot edges so\n // the focus ring + labels never crowd or touch it.\n const imgScale =\n (tooth.meta.dentition === 'primary' ? PRIMARY_TOOTH_SCALE : 1) *\n 0.9;\n const imgW = TOOTH_SLOT_WIDTH * imgScale;\n const imgH = slotHeight * imgScale;\n const imgX = (TOOTH_SLOT_WIDTH - imgW) / 2;\n const imgY = (slotHeight - imgH) / 2;\n\n // Picking targets — surface zones (plan) or root strips (side).\n // Drilled into THIS tooth they become the focusable buttons and the\n // tooth group steps back to a container (no nested interactive).\n const surfaceDrilled =\n drilled?.part === 'surface' && drilled.fdi === tooth.fdi;\n const rootDrilled =\n drilled?.part === 'root' && drilled.fdi === tooth.fdi;\n const isDrilled = surfaceDrilled || rootDrilled;\n const toothZones = surfacePicking ? zonesForTooth(tooth.meta) : [];\n const hasCenter = toothZones.includes('center');\n // Single-rooted teeth are never drillable — there is nothing to pick.\n const toothRoots = rootPicking ? drillableRoots(tooth.meta) : [];\n // Activating this tooth opens its sub-level instead of toggling it,\n // so it must advertise `aria-expanded`, not a `aria-pressed` state it\n // never honours.\n const drillsIn = toothZones.length > 0 || toothRoots.length > 0;\n\n // Number-label y per the sub-chart's number placement.\n const numberY =\n _numbersPosition === 'above'\n ? -4\n : _numbersPosition === 'below'\n ? slotHeight + 12\n : _numbersPosition === 'none'\n ? null\n : tooth.meta.arch === 'upper'\n ? slotHeight + 12\n : -4;\n\n return (\n <RadixTooltip.Root key={tooth.fdi}>\n <RadixTooltip.Trigger asChild>\n <g\n data-fdi={tooth.fdi}\n data-anatomy={tooth.meta.anatomy}\n data-arch={tooth.meta.arch}\n data-side={tooth.meta.side}\n data-quadrant={tooth.meta.quadrant}\n data-condition={primaryCondition ?? 'none'}\n // `data-condition` keeps its first-finding semantics; the\n // symbol-aware attributes sit alongside it rather than\n // repurposing it.\n data-symbol-count={symbols.length}\n data-conditions={\n symbols.length > 0\n ? symbols.map((symbol) => symbol.condition).join(' ')\n : undefined\n }\n data-status={symbols[0]?.status}\n data-testid={`tooth-${tooth.fdi}`}\n transform={`translate(${tooth.x}, ${tooth.y})`}\n tabIndex={tabIndex}\n // SVG `<g>` has no implicit role, so `aria-label`\n // would be rejected by axe's `aria-prohibited-attr`\n // rule. Give it an explicit role: `button` in\n // interactive mode, `img` in display mode. When drilled\n // into for surface picking it becomes a `group` so its\n // focusable surface zones aren't nested in a button.\n role={isDrilled ? 'group' : teethFocusable ? 'button' : 'img'}\n aria-label={label}\n aria-pressed={\n isDrilled || drillsIn\n ? undefined\n : mode === 'interactive'\n ? primaryCondition !== undefined\n : undefined\n }\n aria-expanded={\n !isDrilled && drillsIn && teethFocusable ? false : undefined\n }\n className={toothGroupVariants()}\n onClick={\n isDrilled\n ? undefined\n : mode === 'interactive'\n ? surfacePicking || toothRoots.length > 0\n ? () => drillInto(tooth.fdi)\n : () => handleClick(tooth.fdi)\n : radiographOpenable\n ? () => handleOpenRadiographs(tooth.fdi)\n : undefined\n }\n onFocus={() => setFocusedId(tooth.fdi)}\n onKeyDown={\n isDrilled\n ? undefined\n : (event) => handleKeyDown(event, tooth.fdi)\n }\n >\n {/* Invisible ≥44px hit target (WCAG 2.5.5). */}\n <rect\n x={-TOOTH_HIT_PAD}\n y={-TOOTH_HIT_PAD}\n width={TOOTH_SLOT_WIDTH + TOOTH_HIT_PAD * 2}\n height={slotHeight + TOOTH_HIT_PAD * 2}\n fill=\"transparent\"\n />\n {/* Photoreal tooth render (side = facial, plan =\n occlusal). The upper/lower view folders are\n pre-oriented, so no mirroring is needed. Decorative —\n the parent <g> carries the accessible name. */}\n <image\n href={slotImageHref}\n x={imgX}\n y={imgY}\n width={imgW}\n height={imgH}\n preserveAspectRatio={\n showThumbnail ? 'xMidYMid slice' : 'xMidYMid meet'\n }\n opacity={isMissing && !showThumbnail ? 0.25 : 1}\n aria-hidden=\"true\"\n />\n {/* Whole-tooth symbol overlays (crown, implant, RCT,\n bridge…) in BOTH projections. The distinct glyph is\n the colour-independent channel; the group's\n accessible name names it. Width / height are forced —\n the plan canvases are not all one size, so intrinsic\n sizing would drift. */}\n {symbolOverlays.map(({ key, url, opacity }) => {\n // A handful of plan renders ship on a larger canvas, so\n // fitting them into the base rect lands them inset. Scale\n // by the ratio, about the same centre.\n const scale =\n projection === 'plan' ? planOverlayScale(url) : 1;\n const w = imgW * scale;\n const h = imgH * scale;\n return (\n <image\n key={key}\n href={url}\n x={imgX - (w - imgW) / 2}\n y={imgY - (h - imgH) / 2}\n width={w}\n height={h}\n preserveAspectRatio=\"xMidYMid meet\"\n opacity={opacity}\n aria-hidden=\"true\"\n pointerEvents=\"none\"\n />\n );\n })}\n {/* Plan view: per-surface caries / filling overlays —\n the \"Stato dentale\" surface marking. */}\n {surfaceOverlays.map(({ key, url, opacity }) => (\n <image\n key={key}\n href={url}\n x={imgX}\n y={imgY}\n width={imgW}\n height={imgH}\n preserveAspectRatio=\"xMidYMid meet\"\n opacity={opacity}\n aria-hidden=\"true\"\n pointerEvents=\"none\"\n />\n ))}\n {/* Registry findings with no artwork yet — a glyph badge\n stacked down the middle of the slot. */}\n {glyphMarks.map(\n ({ key, condition, glyph, colour, opacity }, index) => (\n <GlyphMark\n key={key}\n glyph={glyph}\n colour={colour}\n opacity={opacity}\n cx={TOOTH_SLOT_WIDTH / 2}\n cy={slotHeight / 2 + index * 16}\n testId={`tooth-${tooth.fdi}-glyph-${condition}`}\n />\n ),\n )}\n {/* Plan view: interactive surface-picking zones. Pointer\n clicks mark a surface directly; keyboard users drill\n in (Enter) then pick a zone (arrows), so the zones are\n focusable buttons only while THIS tooth is drilled. */}\n {toothZones.map((zone) => {\n const surface = zoneSurface(tooth.meta, zone);\n const marked = isTargetMarked(\n tooth.fdi,\n 'surface',\n surface,\n );\n return (\n <path\n key={zone}\n d={zonePath(\n zone,\n { x: imgX, y: imgY, w: imgW, h: imgH },\n hasCenter,\n )}\n data-fdi={tooth.fdi}\n data-zone={zone}\n data-surface={surface}\n data-testid={`tooth-${tooth.fdi}-zone-${zone}`}\n role={surfaceDrilled ? 'button' : undefined}\n tabIndex={\n surfaceDrilled\n ? drilled?.part === 'surface' &&\n drilled.zone === zone\n ? 0\n : -1\n : undefined\n }\n aria-label={\n surfaceDrilled\n ? t('toothScheme.toothLabel', {\n id: labelText,\n anatomy: t(`toothScheme.surface.${surface}`),\n conditionSuffix: targetSuffix(\n symbols,\n 'surface',\n surface,\n ),\n })\n : undefined\n }\n aria-pressed={surfaceDrilled ? marked : undefined}\n strokeWidth=\"var(--focus-ring-width)\"\n className={zoneVariants()}\n onClick={(event) => {\n event.stopPropagation();\n if (!surfaceDrilled) setFocusedId(tooth.fdi);\n toggleTarget(tooth.fdi, 'surface', surface);\n }}\n onKeyDown={\n surfaceDrilled\n ? (event) =>\n handleSurfaceKeyDown(event, tooth.fdi, zone)\n : undefined\n }\n onFocus={\n surfaceDrilled\n ? () =>\n setDrilled((d) =>\n d &&\n d.part === 'surface' &&\n d.fdi === tooth.fdi &&\n d.zone === zone\n ? d\n : { fdi: tooth.fdi, part: 'surface', zone },\n )\n : undefined\n }\n />\n );\n })}\n {/* Side view: per-root picking strips over the root half\n of the render (roots point away from the occlusal\n plane). Same contract as the surface zones — pointer\n users click a root, keyboard users drill in first. */}\n {toothRoots.map((root, index) => {\n const rect = rootRect(index, toothRoots.length, {\n x: imgX,\n y: imgY,\n w: imgW,\n h: imgH,\n });\n const marked = isTargetMarked(tooth.fdi, 'root', root);\n return (\n <rect\n key={root}\n x={rect.x}\n y={rect.y}\n width={rect.w}\n height={rect.h}\n rx=\"2\"\n data-fdi={tooth.fdi}\n data-root={root}\n data-testid={`tooth-${tooth.fdi}-root-${root}`}\n role={rootDrilled ? 'button' : undefined}\n tabIndex={\n rootDrilled\n ? drilled?.part === 'root' && drilled.root === root\n ? 0\n : -1\n : undefined\n }\n aria-label={\n rootDrilled\n ? t('toothScheme.toothLabel', {\n id: labelText,\n anatomy: t(`toothScheme.root.${root}`),\n conditionSuffix: targetSuffix(\n symbols,\n 'root',\n root,\n ),\n })\n : undefined\n }\n aria-pressed={rootDrilled ? marked : undefined}\n strokeWidth=\"var(--focus-ring-width)\"\n className={zoneVariants()}\n onClick={(event) => {\n event.stopPropagation();\n if (!rootDrilled) setFocusedId(tooth.fdi);\n toggleTarget(tooth.fdi, 'root', root);\n }}\n onKeyDown={\n rootDrilled\n ? (event) =>\n handleRootKeyDown(event, tooth.fdi, root)\n : undefined\n }\n onFocus={\n rootDrilled\n ? () =>\n setDrilled((d) =>\n d &&\n d.part === 'root' &&\n d.fdi === tooth.fdi &&\n d.root === root\n ? d\n : { fdi: tooth.fdi, part: 'root', root },\n )\n : undefined\n }\n />\n );\n })}\n {/* Side view: surface-finding ring (caries / filled)\n stands in until the plan view marks the surface. */}\n {projection === 'side' && ringColour ? (\n <rect\n x={3}\n y={2}\n width={TOOTH_SLOT_WIDTH - 6}\n height={slotHeight - 4}\n fill=\"none\"\n stroke={ringColour}\n strokeWidth=\"2\"\n // Distinguish caries (solid) from filled (dashed) by\n // line style, not colour alone (WCAG 1.4.1).\n strokeDasharray={\n ringSymbol?.condition === 'filled' ? '4 2' : undefined\n }\n rx=\"6\"\n pointerEvents=\"none\"\n />\n ) : null}\n {/* Execution-status pips — the status token colour paired\n with a shape (ring = planned, disc = executed), never\n the colour on its own. The status is also spoken in\n the tooth's accessible name and shown in the tooltip. */}\n {statuses.map((status, index) => (\n <StatusDot\n key={status}\n status={status}\n cx={5 + index * 9}\n cy={5}\n r={3.25}\n strokeWidth={1.25}\n testId={`tooth-${tooth.fdi}-status-${status}`}\n />\n ))}\n {/* Missing-tooth X glyph over the faded render. */}\n {isMissing ? (\n <path\n d={`M7 9 L${TOOTH_SLOT_WIDTH - 7} ${slotHeight - 9} M${TOOTH_SLOT_WIDTH - 7} 9 L7 ${slotHeight - 9}`}\n stroke={CONDITION_COLORS.missing}\n strokeWidth=\"2\"\n fill=\"none\"\n pointerEvents=\"none\"\n />\n ) : null}\n {/* Thumbnail-mode frame — a token border so the x-ray\n reads as a framed film rather than a tooth render. */}\n {showThumbnail ? (\n <rect\n x={imgX}\n y={imgY}\n width={imgW}\n height={imgH}\n fill=\"none\"\n stroke=\"var(--border)\"\n strokeWidth=\"1\"\n rx=\"3\"\n pointerEvents=\"none\"\n />\n ) : null}\n {/* Radiograph count badge — bottom-inline-end corner.\n Decorative (aria-hidden); the count is announced via\n the tooth's accessible name. An opaque --card chip\n keeps the count legible over the photoreal render. */}\n {hasRadiographs ? (\n <g\n data-testid={`tooth-${tooth.fdi}-radiograph-badge`}\n data-radiograph-count={radiographCount}\n transform={`translate(${TOOTH_SLOT_WIDTH - (radiographCount >= 10 ? 19 : 15)}, ${slotHeight - 13})`}\n pointerEvents=\"none\"\n aria-hidden=\"true\"\n >\n <rect\n width={radiographCount >= 10 ? 17 : 13}\n height={12}\n rx=\"3.5\"\n fill=\"var(--card)\"\n stroke=\"var(--info-foreground)\"\n strokeWidth=\"0.75\"\n />\n <text\n x={(radiographCount >= 10 ? 17 : 13) / 2}\n y={9}\n textAnchor=\"middle\"\n fontSize=\"9\"\n fontWeight=\"600\"\n fill=\"var(--info-foreground)\"\n className=\"ds:select-none\"\n >\n {radiographCount}\n </text>\n </g>\n ) : null}\n {/* Focus ring — drawn as a rect so it tracks the hit\n area. `group` on the parent <g> makes this\n group-focus-visible selector fire when a keyboard\n user focuses the tooth. In forced-colors mode the\n ring falls back to `CanvasText` so it stays visible\n when `var(--ring)` is remapped. */}\n <rect\n x={-TOOTH_HIT_PAD}\n y={-TOOTH_HIT_PAD}\n width={TOOTH_SLOT_WIDTH + TOOTH_HIT_PAD * 2}\n height={slotHeight + TOOTH_HIT_PAD * 2}\n fill=\"none\"\n stroke=\"var(--ring)\"\n strokeWidth=\"var(--focus-ring-width)\"\n className={[\n 'ds:opacity-0',\n 'ds:group-focus-visible:opacity-100',\n 'ds:forced-colors:stroke-[CanvasText]',\n ].join(' ')}\n data-testid={`tooth-${tooth.fdi}-focus-ring`}\n pointerEvents=\"none\"\n rx=\"4\"\n />\n {/* Tooth number label — placement follows the sub-chart's\n number position (`above` / `below` / between arches). */}\n {numberY !== null ? (\n <text\n x={TOOTH_SLOT_WIDTH / 2}\n y={numberY}\n textAnchor=\"middle\"\n fontSize=\"10\"\n fill=\"var(--muted-foreground)\"\n className=\"ds:select-none\"\n aria-hidden=\"true\"\n >\n {labelText}\n </text>\n ) : null}\n </g>\n </RadixTooltip.Trigger>\n <RadixTooltip.Portal>\n <RadixTooltip.Content\n side=\"top\"\n sideOffset={6}\n className=\"ds:z-[var(--z-tooltip)] ds:rounded-[var(--radius-sm)] ds:bg-[var(--foreground)] ds:text-[var(--background)] ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)] ds:pt-[calc(var(--spacing-xs)/2)] ds:pb-[calc(var(--spacing-xs)/2)] ds:text-[length:var(--font-size-xs)]\"\n >\n {tooltipContent}\n <RadixTooltip.Arrow className=\"ds:fill-[var(--foreground)]\" />\n </RadixTooltip.Content>\n </RadixTooltip.Portal>\n </RadixTooltip.Root>\n );\n })}\n\n {/* Special elements — selectable quadrant / sextant / arch / whole-mouth\n slots. A label block: outline when empty, accent-tinted with a\n condition-coloured border when a finding is recorded (fill state is\n the colour-independent channel; the finding is also in the name). */}\n {specials.map(({ element, x, y }) => {\n const elementSymbols = symbolsForTooth(\n chart[element.id],\n conditionRegistry,\n );\n const primary = elementSymbols[0];\n const cond = primary?.condition;\n const selected = cond !== undefined;\n const name = elementName(element, t);\n const conditionSuffix = elementSymbols\n .map((symbol) => `, ${symbolText(symbol)}`)\n .join('');\n const label = t('toothScheme.elementLabel', {\n name,\n conditionSuffix,\n });\n const condColour = primary\n ? symbolColor(primary, conditionRegistry)\n : undefined;\n // Quadrants / arches / general render a photoreal icon (matching the\n // platform); sextants are label-only.\n const iconUrl = specialIconUrl(element, assetBaseUrl);\n // Region slots are selectable only in interactive mode — never\n // filmable, so they stay decorative in display / radiograph-open mode.\n const elementInteractive = mode === 'interactive';\n const tabIndex = elementInteractive\n ? element.id === focusedId\n ? 0\n : -1\n : undefined;\n\n return (\n <RadixTooltip.Root key={element.id}>\n <RadixTooltip.Trigger asChild>\n <g\n data-fdi={element.id}\n data-special={element.kind}\n data-arch={element.arch}\n data-condition={cond ?? 'none'}\n data-testid={`element-${element.id}`}\n transform={`translate(${x}, ${y})`}\n tabIndex={tabIndex}\n role={elementInteractive ? 'button' : 'img'}\n aria-label={label}\n aria-pressed={elementInteractive ? selected : undefined}\n className={toothGroupVariants()}\n onClick={\n elementInteractive\n ? () => handleClick(element.id)\n : undefined\n }\n onFocus={\n elementInteractive\n ? () => setFocusedId(element.id)\n : undefined\n }\n onKeyDown={\n elementInteractive\n ? (event) => handleKeyDown(event, element.id)\n : undefined\n }\n >\n {/* Invisible ≥44px hit target. */}\n <rect\n x={-TOOTH_HIT_PAD}\n y={-TOOTH_HIT_PAD}\n width={SPECIAL_SLOT_WIDTH + TOOTH_HIT_PAD * 2}\n height={slotHeight + TOOTH_HIT_PAD * 2}\n fill=\"transparent\"\n />\n <rect\n x={0}\n y={0}\n width={SPECIAL_SLOT_WIDTH}\n height={slotHeight}\n rx={6}\n fill={selected ? 'var(--accent)' : 'var(--card)'}\n fillOpacity={selected ? 0.16 : 1}\n stroke={condColour ?? 'var(--border)'}\n strokeWidth={selected ? 2 : 1}\n />\n {iconUrl ? (\n <>\n {/* Photoreal region icon (quadrant / arch / general). */}\n <image\n href={iconUrl}\n x={3}\n y={3}\n width={SPECIAL_SLOT_WIDTH - 6}\n height={slotHeight - 16}\n preserveAspectRatio=\"xMidYMid meet\"\n aria-hidden=\"true\"\n pointerEvents=\"none\"\n />\n <text\n x={SPECIAL_SLOT_WIDTH / 2}\n y={slotHeight - 4}\n textAnchor=\"middle\"\n fontSize=\"9\"\n fontWeight=\"600\"\n fill=\"var(--muted-foreground)\"\n className=\"ds:select-none\"\n aria-hidden=\"true\"\n >\n {element.code}\n </text>\n </>\n ) : (\n <text\n x={SPECIAL_SLOT_WIDTH / 2}\n y={slotHeight / 2}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n fontSize=\"11\"\n fontWeight=\"600\"\n fill=\"var(--foreground)\"\n className=\"ds:select-none\"\n aria-hidden=\"true\"\n >\n {element.code}\n </text>\n )}\n {/* Focus ring. */}\n <rect\n x={-TOOTH_HIT_PAD}\n y={-TOOTH_HIT_PAD}\n width={SPECIAL_SLOT_WIDTH + TOOTH_HIT_PAD * 2}\n height={slotHeight + TOOTH_HIT_PAD * 2}\n fill=\"none\"\n stroke=\"var(--ring)\"\n strokeWidth=\"var(--focus-ring-width)\"\n className={[\n 'ds:opacity-0',\n 'ds:group-focus-visible:opacity-100',\n 'ds:forced-colors:stroke-[CanvasText]',\n ].join(' ')}\n data-testid={`element-${element.id}-focus-ring`}\n pointerEvents=\"none\"\n rx=\"6\"\n />\n </g>\n </RadixTooltip.Trigger>\n <RadixTooltip.Portal>\n <RadixTooltip.Content\n side=\"top\"\n sideOffset={6}\n className=\"ds:z-[var(--z-tooltip)] ds:rounded-[var(--radius-sm)] ds:bg-[var(--foreground)] ds:text-[var(--background)] ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)] ds:pt-[calc(var(--spacing-xs)/2)] ds:pb-[calc(var(--spacing-xs)/2)] ds:text-[length:var(--font-size-xs)]\"\n >\n {elementSymbols.length > 0\n ? `${name} · ${elementSymbols.map((s) => symbolText(s)).join(' · ')}`\n : name}\n <RadixTooltip.Arrow className=\"ds:fill-[var(--foreground)]\" />\n </RadixTooltip.Content>\n </RadixTooltip.Portal>\n </RadixTooltip.Root>\n );\n })}\n </svg>\n );\n\n // The sr-only live region announcing selection changes. Each chart (single\n // view or `both`-view sub-chart) owns one, so announcements stay local to\n // the row the user is editing.\n const liveRegion = (\n <div\n className={liveRegionVariants()}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n data-testid=\"tooth-scheme-live\"\n >\n {announcement}\n </div>\n );\n\n // `_inner` sub-chart: render only the svg + its live region (no region\n // wrapper / controls / legend — the outer host supplies those).\n if (_inner) {\n return (\n <RadixTooltip.Provider delayDuration={200}>\n {chartSvg}\n {liveRegion}\n </RadixTooltip.Provider>\n );\n }\n\n // The `both` view: four arch-scoped sub-charts in clinical reading order —\n // upper facial, upper occlusal, lower occlusal, lower facial — so the two\n // occlusal rows sit between the two facial rows, numbers bracketing top and\n // bottom. Each shares this chart's data (value / onChange), so an edit in\n // any row propagates everywhere.\n const archLabel = (arch: Arch) =>\n arch === 'upper'\n ? t('toothScheme.arch.upper')\n : t('toothScheme.arch.lower');\n const rowLabel = (arch: Arch, view: Projection) =>\n `${baseLabel} — ${archLabel(arch)}, ${\n view === 'plan'\n ? t('toothScheme.view.occlusal')\n : t('toothScheme.view.side')\n }`;\n const sharedSubChartProps = {\n dentition,\n numbering,\n mode,\n value: chart,\n onChange: commitChart,\n onSelect,\n activeCondition,\n assetBaseUrl,\n radiographs,\n radiographDisplay,\n onOpenRadiographs,\n conditionRegistry,\n specialElements: showSpecials,\n _inner: true as const,\n _contentWidth: bothContentWidth,\n };\n const bothView = (\n <div className={bothStackVariants()} data-testid=\"tooth-scheme-both\">\n <ToothScheme\n {...sharedSubChartProps}\n projection=\"side\"\n _arch=\"upper\"\n _numbersPosition=\"above\"\n ariaLabel={rowLabel('upper', 'side')}\n />\n <ToothScheme\n {...sharedSubChartProps}\n projection=\"plan\"\n _arch=\"upper\"\n _numbersPosition=\"none\"\n ariaLabel={rowLabel('upper', 'plan')}\n />\n <ToothScheme\n {...sharedSubChartProps}\n projection=\"plan\"\n _arch=\"lower\"\n _numbersPosition=\"none\"\n ariaLabel={rowLabel('lower', 'plan')}\n />\n <ToothScheme\n {...sharedSubChartProps}\n projection=\"side\"\n _arch=\"lower\"\n _numbersPosition=\"below\"\n ariaLabel={rowLabel('lower', 'side')}\n />\n </div>\n );\n\n // The options gear, built once so the inline and portaled placements share\n // the same popover + state wiring. Rendered inline by default; portaled into\n // `controlsContainer` (e.g. a card header) when the consumer provides one.\n const controlsNode = controls ? (\n <div\n className={\n controlsContainer != null\n ? 'ds:flex ds:justify-end'\n : 'ds:flex ds:w-full ds:justify-end'\n }\n data-testid=\"tooth-scheme-controls\"\n >\n <Popover.Root>\n <Popover.Trigger asChild>\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n icon={<Settings aria-hidden=\"true\" />}\n aria-label={t('toothScheme.options.label')}\n tooltip={t('toothScheme.options.label')}\n />\n </Popover.Trigger>\n <Popover.Content\n ref={setOptionsPopoverEl}\n align=\"end\"\n size=\"md\"\n aria-label={t('toothScheme.options.label')}\n >\n <div className=\"ds:flex ds:w-[var(--popover-size-sm)] ds:max-w-full ds:flex-col ds:gap-[var(--spacing-md)]\">\n {/* Stretch the toggle rows full-width so each control\n aligns to the inline-end edge like the selects below. */}\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:border-b ds:border-[color:var(--border)] ds:pb-[var(--spacing-sm)] ds:[&>*]:w-full ds:[&>*]:justify-between\">\n <Switch\n label={t('toothScheme.options.legend')}\n labelSide=\"start\"\n checked={legend}\n onCheckedChange={setUiLegend}\n />\n <Switch\n label={t('toothScheme.options.specialElements')}\n labelSide=\"start\"\n checked={showSpecials}\n onCheckedChange={setUiSpecial}\n />\n </div>\n <OptionRow\n container={optionsPopoverEl}\n label={t('toothScheme.options.dentition')}\n value={dentition}\n onValueChange={(v) => setUiDentition(v as Dentition)}\n options={[\n {\n value: 'permanent',\n label: t('toothScheme.dentition.permanent'),\n },\n {\n value: 'primary',\n label: t('toothScheme.dentition.primary'),\n },\n {\n value: 'mixed',\n label: t('toothScheme.dentition.mixed'),\n },\n ]}\n />\n <OptionRow\n container={optionsPopoverEl}\n label={t('toothScheme.options.numbering')}\n value={numbering}\n onValueChange={(v) => setUiNumbering(v as Numbering)}\n options={[\n {\n value: 'fdi',\n label: t('toothScheme.numbering.fdi'),\n },\n {\n value: 'universal',\n label: t('toothScheme.numbering.universal'),\n },\n {\n value: 'palmer',\n label: t('toothScheme.numbering.palmer'),\n },\n ]}\n />\n <OptionRow\n container={optionsPopoverEl}\n label={t('toothScheme.options.view')}\n value={viewMode}\n onValueChange={(v) => setUiProjection(v as ViewMode)}\n options={[\n {\n value: 'side',\n label: t('toothScheme.view.side'),\n },\n {\n value: 'plan',\n label: t('toothScheme.view.occlusal'),\n },\n {\n value: 'both',\n label: t('toothScheme.view.both'),\n },\n ]}\n />\n </div>\n </Popover.Content>\n </Popover.Root>\n </div>\n ) : null;\n\n return (\n <RadixTooltip.Provider delayDuration={200}>\n <div\n ref={rootRef}\n role=\"region\"\n aria-label={baseLabel}\n tabIndex={scrollTabIndex}\n className={[rootVariants(), className].filter(Boolean).join(' ')}\n data-component=\"tooth-scheme\"\n data-component-id={id}\n data-testid=\"tooth-scheme-root\"\n data-dentition={dentition}\n data-numbering={numbering}\n data-mode={mode}\n data-projection={projection}\n data-view-mode={viewMode}\n data-special-elements={showSpecials ? 'true' : 'false'}\n >\n {/* Options gear — inline by default; portaled into the consumer's\n `controlsContainer` slot (e.g. a card header) when one is passed.\n While that slot mounts the prop is `null`, so nothing renders here\n and the gear never flashes inline first. */}\n {controlsContainer === undefined\n ? controlsNode\n : controlsContainer\n ? createPortal(controlsNode, controlsContainer)\n : null}\n\n {showBoth ? bothView : chartSvg}\n\n {/* Whole-mouth `general` element — a switch beneath the chart, not a\n cramped icon column. Interactive-only; in display mode it shows\n only when a finding is set, as a read-only indicator. */}\n {showSpecials && (mode === 'interactive' || generalChecked) ? (\n <div\n className=\"ds:flex ds:w-full ds:items-center ds:pt-[var(--spacing-2xs)]\"\n data-testid=\"tooth-scheme-general\"\n >\n <Switch\n label={t('toothScheme.special.general')}\n labelSide=\"end\"\n checked={generalChecked}\n disabled={mode !== 'interactive'}\n onCheckedChange={toggleGeneral}\n />\n </div>\n ) : null}\n\n {legend ? (\n <Legend assetBaseUrl={assetBaseUrl} registry={conditionRegistry} />\n ) : null}\n\n {liveRegion}\n </div>\n </RadixTooltip.Provider>\n );\n },\n);\n\nToothScheme.displayName = 'ToothScheme';\n\n/* ------------------------------------------------------------------ */\n/* Re-exports */\n/* ------------------------------------------------------------------ */\n\nexport { rootVariants as toothSchemeVariants, PERMANENT_TEETH, PRIMARY_TEETH };\nexport type {\n Dentition,\n FdiId,\n Numbering,\n SpecialElement,\n ToothChart,\n ToothCondition,\n ToothMode,\n ToothState,\n} from './tooth-data';\n"],"names":["enumOf","ids","CONDITION_IDS","SURFACE_IDS","ROOT_IDS","PART_IDS","STATUS_IDS","RADIOGRAPH_KIND_IDS","FDI_SCHEMA","CONDITION_SCHEMA","CONDITION_ID_SCHEMA","SURFACE_SCHEMA","ROOT_SCHEMA","PART_SCHEMA","STATUS_SCHEMA","SYMBOL_SCHEMA","RADIOGRAPH_SCHEMA","structuralSymbol","symbol","toothSchemeAgent","handle","fdi","state","r","args","_a","rootVariants","cva","bothStackVariants","svgVariants","toothGroupVariants","legendVariants","legendItemVariants","liveRegionVariants","zoneVariants","isControlled","props","emptyState","toggleSymbolCondition","symbols","active","registry","condition","conditionPart","entry","toggleSymbolTarget","part","target","covers","sameCondition","index","growable","toggleAt","seed","current","next","_","i","updated","stateFromSymbols","previous","conditions","surfaces","isBuiltInCondition","surface","elementName","element","t","nextZone","zone","key","hasCenter","orderedRoots","meta","slot","root","rootScreenSide","rootsForTooth","b","drillableRoots","roots","nextRoot","rootRect","count","rect","w","GlyphMark","glyph","colour","cx","cy","opacity","testId","jsxs","jsx","StatusDot","status","strokeWidth","STATUS_COLORS","STATUS_ORDER","LegendSymbol","assetBaseUrl","FDI_TO_META","spec","conditionSideSymbol","isMissing","conditionColor","isSurface","conditionHasArtwork","h","x","y","toothImageUrl","conditionSymbolUrl","CONDITION_COLORS","conditionGlyph","Legend","useTranslation","TOOTH_CONDITIONS","id","label","conditionLabel","statusLabelKey","OptionRow","value","options","onValueChange","container","Select","sortByDateDesc","a","ToothScheme","forwardRef","dentitionProp","numberingProp","mode","projectionProp","specialElementsProp","defaultValue","onChange","onSelect","radiographs","radiographDisplay","onOpenRadiographs","activeCondition","conditionRegistry","legendProp","controls","controlsContainer","ariaLabel","className","_arch","_numbersPosition","_inner","_contentWidth","ref","uiDentition","setUiDentition","useState","uiNumbering","setUiNumbering","uiProjection","setUiProjection","uiLegend","setUiLegend","uiSpecial","setUiSpecial","optionsPopoverEl","setOptionsPopoverEl","dentition","numbering","legend","viewMode","projection","showBoth","specialAuto","showSpecials","controlsWasOn","useRef","useEffect","internalChart","setInternalChart","chartFromConditions","chart","slotHeight","TOOTH_SLOT_HEIGHT","layout","useMemo","layoutTeeth","specials","layoutSpecials","specialsForRow","upper","lowerRowY","TOOTH_ROW_GAP","lower","s","bothContentWidth","max","arch","proj","visibleIds","tooth","firstId","focusedId","setFocusedId","announcement","setAnnouncement","svgRef","commitChart","useCallback","focusToothById","svg","node","labelOf","symbolText","scoped","scope","targetSuffix","buildAnnouncement","conditionText","isSpecialElement","name","SPECIAL_BY_ID","writeSymbols","commitSymbols","activePart","surfacePicking","rootPicking","drilled","setDrilled","focusDrill","drill","selector","_b","restoreFocusTo","isTargetMarked","symbolsForTooth","toggleTarget","drillInto","zonesForTooth","handleSurfaceKeyDown","event","nz","zoneSurface","handleRootKeyDown","nr","rootRef","radiographOpenable","teethFocusable","handleOpenRadiographs","agentHandle","useImperativeHandle","useAgentRegistration","handleKeyDown","order","currentIndex","nextIndex","targetQuadrant","candidate","inQuadrant","other","handleClick","generalId","generalChecked","toggleGeneral","checked","topPad","bottomPad","specialsWidth","SPECIAL_SLOT_WIDTH","viewBoxWidth","viewBoxHeight","baseLabel","scrollTabIndex","chartSvg","primaryCondition","anatomyLabel","conditionSuffix","toothRadiographs","radiographCount","hasRadiographs","latestRadiograph","showThumbnail","radiographSuffix","projectionSuffix","labelFor","tabIndex","symbolOverlays","conditionPlanSymbol","planSymbolUrl","STATUS_OPACITY","glyphMarks","symbolColor","ringSymbol","ringColour","statuses","tooltipContent","labelText","imageUrl","slotImageHref","surfaceOverlays","folder","conditionPlanFolder","surfaceSymbolUrl","imgScale","PRIMARY_TOOTH_SCALE","imgW","TOOTH_SLOT_WIDTH","imgH","imgX","imgY","surfaceDrilled","rootDrilled","isDrilled","toothZones","toothRoots","drillsIn","numberY","RadixTooltip","TOOTH_HIT_PAD","url","scale","planOverlayScale","marked","zonePath","d","elementSymbols","primary","cond","selected","condColour","iconUrl","specialIconUrl","elementInteractive","Fragment","liveRegion","archLabel","rowLabel","view","sharedSubChartProps","bothView","controlsNode","Popover","IconButton","Settings","Switch","v","createPortal"],"mappings":"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"}
|