@alfadocs/ui-kit-debug 1.12.6 → 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.
Files changed (138) hide show
  1. package/dist/_chunks/{actions-cell-renderer-DnSLrgQD.js → actions-cell-renderer-ReurEy5i.js} +2 -2
  2. package/dist/_chunks/{actions-cell-renderer-DnSLrgQD.js.map → actions-cell-renderer-ReurEy5i.js.map} +1 -1
  3. package/dist/_chunks/{address-fields-CZP4Wncx.js → address-fields-CZ0pEdEI.js} +4 -4
  4. package/dist/_chunks/{address-fields-CZP4Wncx.js.map → address-fields-CZ0pEdEI.js.map} +1 -1
  5. package/dist/_chunks/{ai-prompt-input-DnbfEJnr.js → ai-prompt-input-CrHr-5H8.js} +2 -2
  6. package/dist/_chunks/{ai-prompt-input-DnbfEJnr.js.map → ai-prompt-input-CrHr-5H8.js.map} +1 -1
  7. package/dist/_chunks/{anamnesis-summary-rows-BfhxWPO3.js → anamnesis-summary-rows-CRWO8x8g.js} +4 -4
  8. package/dist/_chunks/{anamnesis-summary-rows-BfhxWPO3.js.map → anamnesis-summary-rows-CRWO8x8g.js.map} +1 -1
  9. package/dist/_chunks/{audio-recorder-EWBCNIsd.js → audio-recorder-DXG6LTtO.js} +2 -2
  10. package/dist/_chunks/{audio-recorder-EWBCNIsd.js.map → audio-recorder-DXG6LTtO.js.map} +1 -1
  11. package/dist/_chunks/{autocomplete-BrONKN8l.js → autocomplete-MpBhz-fG.js} +86 -74
  12. package/dist/_chunks/{autocomplete-BrONKN8l.js.map → autocomplete-MpBhz-fG.js.map} +1 -1
  13. package/dist/_chunks/{balance-badge-cell-7L6nzB29.js → balance-badge-cell--iQ_gtmi.js} +4 -4
  14. package/dist/_chunks/{balance-badge-cell-7L6nzB29.js.map → balance-badge-cell--iQ_gtmi.js.map} +1 -1
  15. package/dist/_chunks/{bishop-score-Cnu0xs-z.js → bishop-score-CJUVBfAu.js} +2 -2
  16. package/dist/_chunks/{bishop-score-Cnu0xs-z.js.map → bishop-score-CJUVBfAu.js.map} +1 -1
  17. package/dist/_chunks/{booking-CBHKdsZl.js → booking-DQbo6mQF.js} +609 -591
  18. package/dist/_chunks/booking-DQbo6mQF.js.map +1 -0
  19. package/dist/_chunks/{care-plan-card-aDN4oem9.js → care-plan-card-D-FMfDKH.js} +2 -2
  20. package/dist/_chunks/{care-plan-card-aDN4oem9.js.map → care-plan-card-D-FMfDKH.js.map} +1 -1
  21. package/dist/_chunks/{care-plan-entry-card-BEhANdBE.js → care-plan-entry-card-Bvw_9T-d.js} +2 -2
  22. package/dist/_chunks/{care-plan-entry-card-BEhANdBE.js.map → care-plan-entry-card-Bvw_9T-d.js.map} +1 -1
  23. package/dist/_chunks/{care-plan-header-CkpPyQqG.js → care-plan-header-B5CBE0zu.js} +2 -2
  24. package/dist/_chunks/{care-plan-header-CkpPyQqG.js.map → care-plan-header-B5CBE0zu.js.map} +1 -1
  25. package/dist/_chunks/{city-input-towzBenY.js → city-input-DaQc-Hbj.js} +2 -2
  26. package/dist/_chunks/{city-input-towzBenY.js.map → city-input-DaQc-Hbj.js.map} +1 -1
  27. package/dist/_chunks/{combobox-DiMLItyu.js → combobox-D7_NLE2Z.js} +89 -81
  28. package/dist/_chunks/{combobox-DiMLItyu.js.map → combobox-D7_NLE2Z.js.map} +1 -1
  29. package/dist/_chunks/{contact-profile-card-BMIBr5s9.js → contact-profile-card-BZqi8Hck.js} +38 -36
  30. package/dist/_chunks/{contact-profile-card-BMIBr5s9.js.map → contact-profile-card-BZqi8Hck.js.map} +1 -1
  31. package/dist/_chunks/{country-select-UEF9BEeQ.js → country-select-DzbPFktV.js} +2 -2
  32. package/dist/_chunks/{country-select-UEF9BEeQ.js.map → country-select-DzbPFktV.js.map} +1 -1
  33. package/dist/_chunks/{document-preview-oyx9RhCo.js → document-preview-CDb-n_W7.js} +2 -2
  34. package/dist/_chunks/{document-preview-oyx9RhCo.js.map → document-preview-CDb-n_W7.js.map} +1 -1
  35. package/dist/_chunks/{face-scheme-CZaKm6fG.js → face-scheme-DA2vjqaM.js} +2 -2
  36. package/dist/_chunks/{face-scheme-CZaKm6fG.js.map → face-scheme-DA2vjqaM.js.map} +1 -1
  37. package/dist/_chunks/{file-manager-C0y7HBAN.js → file-manager-UsD8e_AB.js} +2 -2
  38. package/dist/_chunks/{file-manager-C0y7HBAN.js.map → file-manager-UsD8e_AB.js.map} +1 -1
  39. package/dist/_chunks/{gestational-age-calculator-CxZelpu2.js → gestational-age-calculator-CiOQjzgx.js} +2 -2
  40. package/dist/_chunks/{gestational-age-calculator-CxZelpu2.js.map → gestational-age-calculator-CiOQjzgx.js.map} +1 -1
  41. package/dist/_chunks/key-value-pair-BIBdZBLg.js +188 -0
  42. package/dist/_chunks/key-value-pair-BIBdZBLg.js.map +1 -0
  43. package/dist/_chunks/{link-cell-renderer-CenJx-_7.js → link-cell-renderer-CIASXsVM.js} +4 -4
  44. package/dist/_chunks/{link-cell-renderer-CenJx-_7.js.map → link-cell-renderer-CIASXsVM.js.map} +1 -1
  45. package/dist/_chunks/{multi-select-DqL4o0qV.js → multi-select-DYOvx2SJ.js} +56 -48
  46. package/dist/_chunks/{multi-select-DqL4o0qV.js.map → multi-select-DYOvx2SJ.js.map} +1 -1
  47. package/dist/_chunks/{muscle-scheme-yfzP_xoJ.js → muscle-scheme-BSJsI4-I.js} +2 -2
  48. package/dist/_chunks/{muscle-scheme-yfzP_xoJ.js.map → muscle-scheme-BSJsI4-I.js.map} +1 -1
  49. package/dist/_chunks/{optical-prescription-Dj3Eh5Ok.js → optical-prescription-BvwuqTpl.js} +2 -2
  50. package/dist/_chunks/{optical-prescription-Dj3Eh5Ok.js.map → optical-prescription-BvwuqTpl.js.map} +1 -1
  51. package/dist/_chunks/{patient-details-xrqe13az.js → patient-details-BQaUzPqp.js} +5 -5
  52. package/dist/_chunks/{patient-details-xrqe13az.js.map → patient-details-BQaUzPqp.js.map} +1 -1
  53. package/dist/_chunks/{patient-search-D5ufYoRc.js → patient-search-HeEUB-_X.js} +2 -2
  54. package/dist/_chunks/{patient-search-D5ufYoRc.js.map → patient-search-HeEUB-_X.js.map} +1 -1
  55. package/dist/_chunks/{patient-summary-card-CBfuDvJ5.js → patient-summary-card-CvDxhbBR.js} +2 -2
  56. package/dist/_chunks/{patient-summary-card-CBfuDvJ5.js.map → patient-summary-card-CvDxhbBR.js.map} +1 -1
  57. package/dist/_chunks/{payment-request-card-YVCcCZ25.js → payment-request-card-lmKLwsDs.js} +2 -2
  58. package/dist/_chunks/{payment-request-card-YVCcCZ25.js.map → payment-request-card-lmKLwsDs.js.map} +1 -1
  59. package/dist/_chunks/{periodontal-chart-BatZEFar.js → periodontal-chart-B9fphroR.js} +2 -2
  60. package/dist/_chunks/{periodontal-chart-BatZEFar.js.map → periodontal-chart-B9fphroR.js.map} +1 -1
  61. package/dist/_chunks/{periodontal-chart-card-BBpY_rBc.js → periodontal-chart-card-qEZPXj83.js} +2 -2
  62. package/dist/_chunks/{periodontal-chart-card-BBpY_rBc.js.map → periodontal-chart-card-qEZPXj83.js.map} +1 -1
  63. package/dist/_chunks/{pregnancy-dating-DtToyMyc.js → pregnancy-dating-D2wchD11.js} +2 -2
  64. package/dist/_chunks/{pregnancy-dating-DtToyMyc.js.map → pregnancy-dating-D2wchD11.js.map} +1 -1
  65. package/dist/_chunks/{province-select-BDywtmL-.js → province-select-BBc7s7vR.js} +2 -2
  66. package/dist/_chunks/{province-select-BDywtmL-.js.map → province-select-BBc7s7vR.js.map} +1 -1
  67. package/dist/_chunks/{select-BW5ecXlX.js → select-Bi8zril7.js} +165 -136
  68. package/dist/_chunks/select-Bi8zril7.js.map +1 -0
  69. package/dist/_chunks/{signature-request-DVDTKLjM.js → signature-request-CUe903hj.js} +2 -2
  70. package/dist/_chunks/{signature-request-DVDTKLjM.js.map → signature-request-CUe903hj.js.map} +1 -1
  71. package/dist/_chunks/{tabs-CBb2AidH.js → tabs-DqKtTIjZ.js} +2 -2
  72. package/dist/_chunks/{tabs-CBb2AidH.js.map → tabs-DqKtTIjZ.js.map} +1 -1
  73. package/dist/_chunks/{tasks-panel-Do5SFp-j.js → tasks-panel-DPCNaRko.js} +2 -2
  74. package/dist/_chunks/{tasks-panel-Do5SFp-j.js.map → tasks-panel-DPCNaRko.js.map} +1 -1
  75. package/dist/_chunks/{tooth-scheme-WdyVymQ1.js → tooth-scheme-2IsmbE6w.js} +2 -2
  76. package/dist/_chunks/{tooth-scheme-WdyVymQ1.js.map → tooth-scheme-2IsmbE6w.js.map} +1 -1
  77. package/dist/_chunks/{unit-converter-BPumXMA6.js → unit-converter-C6jMjqL9.js} +2 -2
  78. package/dist/_chunks/{unit-converter-BPumXMA6.js.map → unit-converter-C6jMjqL9.js.map} +1 -1
  79. package/dist/_chunks/{workflow-map-DE_ribRM.js → workflow-map-wcw3t6g4.js} +2 -2
  80. package/dist/_chunks/{workflow-map-DE_ribRM.js.map → workflow-map-wcw3t6g4.js.map} +1 -1
  81. package/dist/agent-catalog.json +1 -1
  82. package/dist/components/_shared/option.d.ts +1 -0
  83. package/dist/components/_shared/option.d.ts.map +1 -1
  84. package/dist/components/address-fields/index.js +1 -1
  85. package/dist/components/ai-prompt-input/index.js +1 -1
  86. package/dist/components/audio-recorder/index.js +1 -1
  87. package/dist/components/autocomplete/autocomplete.d.ts.map +1 -1
  88. package/dist/components/autocomplete/index.js +1 -1
  89. package/dist/components/bishop-score/index.js +1 -1
  90. package/dist/components/booking/booking.d.ts.map +1 -1
  91. package/dist/components/booking/index.js +1 -1
  92. package/dist/components/care-plan-card/index.js +1 -1
  93. package/dist/components/care-plan-entry-card/index.js +1 -1
  94. package/dist/components/care-plan-header/index.js +1 -1
  95. package/dist/components/city-input/index.js +1 -1
  96. package/dist/components/combobox/combobox.d.ts.map +1 -1
  97. package/dist/components/combobox/index.js +1 -1
  98. package/dist/components/contact-profile-card/contact-profile-card.d.ts.map +1 -1
  99. package/dist/components/contact-profile-card/index.js +1 -1
  100. package/dist/components/country-select/index.js +1 -1
  101. package/dist/components/data-table/index.js +2 -2
  102. package/dist/components/document-preview/index.js +1 -1
  103. package/dist/components/face-scheme/index.js +1 -1
  104. package/dist/components/file-manager/index.js +1 -1
  105. package/dist/components/gestational-age-calculator/index.js +1 -1
  106. package/dist/components/key-value-pair/index.js +1 -1
  107. package/dist/components/key-value-pair/key-value-pair.d.ts +16 -0
  108. package/dist/components/key-value-pair/key-value-pair.d.ts.map +1 -1
  109. package/dist/components/multi-select/index.js +1 -1
  110. package/dist/components/multi-select/multi-select.d.ts.map +1 -1
  111. package/dist/components/muscle-scheme/index.js +1 -1
  112. package/dist/components/optical-prescription/index.js +1 -1
  113. package/dist/components/patient-details/index.js +1 -1
  114. package/dist/components/patient-search/index.js +1 -1
  115. package/dist/components/patient-summary-card/index.js +1 -1
  116. package/dist/components/patient-table/index.js +1 -1
  117. package/dist/components/payment-card/index.js +1 -1
  118. package/dist/components/periodontal-chart/index.js +1 -1
  119. package/dist/components/periodontal-chart-card/index.js +1 -1
  120. package/dist/components/pregnancy-dating/index.js +1 -1
  121. package/dist/components/province-select/index.js +1 -1
  122. package/dist/components/select/index.js +1 -1
  123. package/dist/components/select/select.d.ts +24 -0
  124. package/dist/components/select/select.d.ts.map +1 -1
  125. package/dist/components/skeleton-scheme/index.js +1 -1
  126. package/dist/components/tabs/index.js +1 -1
  127. package/dist/components/tasks-panel/index.js +1 -1
  128. package/dist/components/tooth-scheme/index.js +1 -1
  129. package/dist/components/unit-converter/index.js +1 -1
  130. package/dist/components/workflow/index.js +1 -1
  131. package/dist/index.js +40 -40
  132. package/dist/patterns/anamnesis/index.js +1 -1
  133. package/dist/patterns/signature-request/index.js +1 -1
  134. package/package.json +1 -1
  135. package/dist/_chunks/booking-CBHKdsZl.js.map +0 -1
  136. package/dist/_chunks/key-value-pair-BubG4fUa.js +0 -144
  137. package/dist/_chunks/key-value-pair-BubG4fUa.js.map +0 -1
  138. package/dist/_chunks/select-BW5ecXlX.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"face-scheme-CZaKm6fG.js","sources":["../../node_modules/lucide-react/dist/esm/icons/columns-3.mjs","../../node_modules/lucide-react/dist/esm/icons/mouse-pointer-2.mjs","../../node_modules/lucide-react/dist/esm/icons/pen.mjs","../../node_modules/lucide-react/dist/esm/icons/pencil-ruler.mjs","../../node_modules/lucide-react/dist/esm/icons/undo-2.mjs","../../node_modules/lucide-react/dist/esm/icons/user-round-arrow-left.mjs","../../node_modules/lucide-react/dist/esm/icons/user-round.mjs","../../src/components/face-scheme/face-scheme.agent.ts","../../src/components/face-scheme/detect-face-landmarks.ts","../../src/components/face-scheme/detect-face-yunet.ts","../../src/components/face-scheme/face-scheme-zones.ts","../../src/components/face-scheme/face-scheme-data.ts","../../src/components/face-scheme/face-scheme.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"3\", rx: \"2\", key: \"afitv7\" }],\n [\"path\", { d: \"M9 3v18\", key: \"fh3hqa\" }],\n [\"path\", { d: \"M15 3v18\", key: \"14nvp0\" }]\n];\nconst Columns3 = createLucideIcon(\"columns-3\", __iconNode);\n\nexport { __iconNode, Columns3 as default };\n//# sourceMappingURL=columns-3.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M4.037 4.688a.495.495 0 0 1 .651-.651l16 6.5a.5.5 0 0 1-.063.947l-6.124 1.58a2 2 0 0 0-1.438 1.435l-1.579 6.126a.5.5 0 0 1-.947.063z\",\n key: \"edeuup\"\n }\n ]\n];\nconst MousePointer2 = createLucideIcon(\"mouse-pointer-2\", __iconNode);\n\nexport { __iconNode, MousePointer2 as default };\n//# sourceMappingURL=mouse-pointer-2.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\",\n key: \"1a8usu\"\n }\n ]\n];\nconst Pen = createLucideIcon(\"pen\", __iconNode);\n\nexport { __iconNode, Pen as default };\n//# sourceMappingURL=pen.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n { d: \"M13 7 8.7 2.7a2.41 2.41 0 0 0-3.4 0L2.7 5.3a2.41 2.41 0 0 0 0 3.4L7 13\", key: \"orapub\" }\n ],\n [\"path\", { d: \"m8 6 2-2\", key: \"115y1s\" }],\n [\"path\", { d: \"m18 16 2-2\", key: \"ee94s4\" }],\n [\n \"path\",\n {\n d: \"m17 11 4.3 4.3c.94.94.94 2.46 0 3.4l-2.6 2.6c-.94.94-2.46.94-3.4 0L11 17\",\n key: \"cfq27r\"\n }\n ],\n [\n \"path\",\n {\n d: \"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\",\n key: \"1a8usu\"\n }\n ],\n [\"path\", { d: \"m15 5 4 4\", key: \"1mk7zo\" }]\n];\nconst PencilRuler = createLucideIcon(\"pencil-ruler\", __iconNode);\n\nexport { __iconNode, PencilRuler as default };\n//# sourceMappingURL=pencil-ruler.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M9 14 4 9l5-5\", key: \"102s5s\" }],\n [\"path\", { d: \"M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11\", key: \"f3b9sd\" }]\n];\nconst Undo2 = createLucideIcon(\"undo-2\", __iconNode);\n\nexport { __iconNode, Undo2 as default };\n//# sourceMappingURL=undo-2.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"m19 16-3 3\", key: \"lp3y45\" }],\n [\"path\", { d: \"M2 21a8 8 0 0 1 12.664-6.5\", key: \"1ap0vn\" }],\n [\"path\", { d: \"M22 19h-6l3 3\", key: \"13fjle\" }],\n [\"circle\", { cx: \"10\", cy: \"8\", r: \"5\", key: \"o932ke\" }]\n];\nconst UserRoundArrowLeft = createLucideIcon(\"user-round-arrow-left\", __iconNode);\n\nexport { __iconNode, UserRoundArrowLeft as default };\n//# sourceMappingURL=user-round-arrow-left.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"8\", r: \"5\", key: \"1hypcn\" }],\n [\"path\", { d: \"M20 21a8 8 0 0 0-16 0\", key: \"rfgkzh\" }]\n];\nconst UserRound = createLucideIcon(\"user-round\", __iconNode);\n\nexport { __iconNode, UserRound as default };\n//# sourceMappingURL=user-round.mjs.map\n","import type { AgentAdapter } from '../../agent/types';\nimport type { FaceSchemeHandle } from './face-scheme';\nimport type {\n FaceAnnotationTool,\n FaceFindingType,\n FaceViewId,\n} from './face-scheme-data';\n\nconst TOOL_SCHEMA = {\n type: 'string',\n enum: [\n 'none',\n 'marker',\n 'pen',\n 'highlighter',\n 'arrow',\n 'line',\n 'rect',\n 'ellipse',\n 'text',\n ],\n description:\n \"Drawing tool: 'none' (off), 'marker', 'pen', 'highlighter', 'arrow', 'line', 'rect', 'ellipse', or 'text'.\",\n} as const;\n\nconst ZONE_SCHEMA = {\n type: 'string',\n description:\n \"Face-zone id (e.g. 'glabella', 'nasolabialFold', 'forehead', 'mandibularAngleLeft' on the front view; 'cheekbone', 'masseter', 'chin' on a profile view).\",\n} as const;\n\nconst VIEW_SCHEMA = {\n type: 'string',\n enum: ['front', 'profile-left', 'profile-right'],\n description: \"Active view id: 'front', 'profile-left', or 'profile-right'.\",\n} as const;\n\nconst FINDING_SCHEMA = {\n enum: ['observation', 'treatment', 'concern', 'note'],\n} as const;\n\nexport const faceSchemeAgent: AgentAdapter<FaceSchemeHandle> = {\n id: 'face-scheme',\n // pick — focus a zone (transient); set_value / edit_inline — record / clear\n // findings on a zone; view_change — switch the active view (front / left /\n // right profile), since each view renders a different zone set. Registration\n // (the photo fit) is exposed only as the auto-align action.\n capabilities: ['pick', 'set_value', 'edit_inline', 'view_change'],\n state: {\n activeView: {\n // Which view is mounted — it determines which zones are in the DOM, so an\n // agent must read this before focus_zone on a profile-only zone.\n type: 'string',\n descriptionKey: 'ui.agent.faceScheme.state.activeView',\n description:\n 'Id of the currently displayed view (front / profile-left / profile-right).',\n read: (handle) => handle.getView(),\n },\n zoom: {\n type: 'number',\n descriptionKey: 'ui.agent.faceScheme.state.zoom',\n description:\n 'Current figure zoom factor (1 = the base framing; up to 8). Only meaningful when the surface enables `zoomable`.',\n read: (handle) => handle.getZoom(),\n },\n chart: {\n // A9: identifiers + finding ENUMS only — never the free-text finding\n // `note` (PHI) and never the patient-photo `src`. Notes are written but\n // never read back through the snapshot.\n type: 'Record<string, string[]>',\n descriptionKey: 'ui.agent.faceScheme.state.chart',\n description:\n 'Current face chart — the finding types recorded on each zone, keyed by zone id. Free-text notes and the patient photo are not exposed here.',\n read: (handle) =>\n Object.fromEntries(\n Object.entries(handle.getChart()).map(([zone, findings]) => [\n zone,\n findings.map((f) => f.type),\n ]),\n ),\n },\n markedZones: {\n type: 'string[]',\n descriptionKey: 'ui.agent.faceScheme.state.markedZones',\n description: 'Zone ids carrying at least one finding.',\n read: (handle) => Object.keys(handle.getChart()),\n },\n activeTool: {\n type: 'string | null',\n descriptionKey: 'ui.agent.faceScheme.state.activeTool',\n description:\n 'The active free-form drawing tool (marker / pen / highlighter / arrow / line / rect / ellipse / text), or null when none is selected.',\n read: (handle) => handle.getTool(),\n },\n annotationCounts: {\n // PHI-safe: counts by kind only — never the coordinates, and never the\n // free-text of a `text` callout.\n type: 'Record<string, number>',\n descriptionKey: 'ui.agent.faceScheme.state.annotationCounts',\n description:\n 'Count of free-form annotations on the active view, keyed by kind (marker / pen / highlighter / arrow / line / rect / ellipse / text). Never includes coordinates or the free-text of a text callout.',\n read: (handle) =>\n handle.getAnnotations().reduce<Record<string, number>>((acc, a) => {\n acc[a.kind] = (acc[a.kind] ?? 0) + 1;\n return acc;\n }, {}),\n },\n selectedAnnotation: {\n // PHI-safe: id + kind only — never the coordinates, and never the\n // free-text of a `text` callout.\n type: '{ id: string; kind: string } | null',\n descriptionKey: 'ui.agent.faceScheme.state.selectedAnnotation',\n description:\n 'The selected free-form annotation on the active view (id + kind), or null when nothing is selected. Never includes coordinates or the free-text of a text callout.',\n read: (handle) => handle.getSelectedAnnotation(),\n },\n selectedZones: {\n // PHI-safe: zone ids only — selection is UI state, findings stay in\n // `chart`.\n type: 'string[]',\n descriptionKey: 'ui.agent.faceScheme.state.selectedZones',\n description:\n 'Zone ids in the multi-selection (zoneSelect=\"multi\") — the set a bulk finding apply targets. Empty when the mode is off or nothing is selected.',\n read: (handle) => handle.getSelectedZones(),\n },\n annotationZones: {\n // PHI-safe: counts per linked zone only — never the coordinates, and\n // never the free-text of a `text` callout.\n type: 'Record<string, number>',\n descriptionKey: 'ui.agent.faceScheme.state.annotationZones',\n description:\n \"Count of free-form annotations on the active view keyed by their linked zone id ('unassigned' = outside every zone or not yet assessed). Counts only — never coordinates or text.\",\n read: (handle) =>\n handle.getAnnotations().reduce<Record<string, number>>((acc, a) => {\n const key = a.zoneId ?? 'unassigned';\n acc[key] = (acc[key] ?? 0) + 1;\n return acc;\n }, {}),\n },\n },\n actions: {\n focus_zone: {\n safety: 'read',\n argsType: '{ id: string }',\n argsSchema: {\n type: 'object',\n properties: { id: ZONE_SCHEMA },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.focusZone',\n description: 'Move focus to a specific face zone by id.',\n invoke: (handle, args: { id: string }) => {\n handle.focusZone(args.id);\n },\n },\n get_zone: {\n safety: 'read',\n argsType: '{ id: string }',\n argsSchema: {\n type: 'object',\n properties: { id: ZONE_SCHEMA },\n required: ['id'],\n },\n returns: 'string[]',\n returnsSchema: { type: 'array', items: FINDING_SCHEMA },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.getZone',\n description:\n 'Read the finding types recorded on one zone (notes are not returned).',\n invoke: (handle, args: { id: string }) =>\n handle.getZone(args.id).map((f) => f.type),\n },\n zones_with: {\n safety: 'read',\n argsType: '{ finding: FaceFindingType }',\n argsSchema: {\n type: 'object',\n properties: { finding: FINDING_SCHEMA },\n required: ['finding'],\n },\n returns: 'string[]',\n returnsSchema: { type: 'array', items: ZONE_SCHEMA },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.zonesWith',\n description: 'List the zone ids carrying a given finding type.',\n invoke: (handle, args: { finding: FaceFindingType }) =>\n handle.zonesWith(args.finding),\n },\n set_finding: {\n safety: 'write',\n argsType: '{ id: string; finding: FaceFindingType; note?: string }',\n argsSchema: {\n type: 'object',\n properties: {\n id: ZONE_SCHEMA,\n finding: FINDING_SCHEMA,\n note: { type: 'string' },\n },\n required: ['id', 'finding'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.setFinding',\n description:\n 'Record a finding on a zone, with an optional free-text note.',\n invoke: (\n handle,\n args: { id: string; finding: FaceFindingType; note?: string },\n ) => {\n handle.setFinding(args.id, args.finding, args.note);\n },\n },\n remove_finding: {\n safety: 'write',\n argsType: '{ id: string; finding: FaceFindingType }',\n argsSchema: {\n type: 'object',\n properties: { id: ZONE_SCHEMA, finding: FINDING_SCHEMA },\n required: ['id', 'finding'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.removeFinding',\n description: 'Remove a single finding from a zone.',\n invoke: (handle, args: { id: string; finding: FaceFindingType }) => {\n handle.removeFinding(args.id, args.finding);\n },\n },\n clear_zone: {\n safety: 'destructive',\n argsType: '{ id: string }',\n argsSchema: {\n type: 'object',\n properties: { id: ZONE_SCHEMA },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.clearZone',\n description: 'Clear every finding from a zone.',\n invoke: (handle, args: { id: string }) => {\n handle.clearZone(args.id);\n },\n },\n auto_align: {\n safety: 'write',\n argsType: '{}',\n argsSchema: { type: 'object', properties: {} },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.autoAlign',\n description:\n 'Run the on-device detector to align the zone overlay to the patient photo (works on the active view — front or profile). No-op if detection is disabled or no face is found.',\n invoke: (handle) => {\n void handle.detect();\n },\n },\n set_view: {\n safety: 'write',\n argsType: '{ view: FaceViewId }',\n argsSchema: {\n type: 'object',\n properties: { view: VIEW_SCHEMA },\n required: ['view'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.setView',\n description:\n \"Switch the active view ('front' / 'profile-left' / 'profile-right'). Each view renders a different zone set, so switch before focusing a zone that belongs to another view.\",\n invoke: (handle, args: { view: FaceViewId }) => {\n handle.setView(args.view);\n },\n },\n set_zoom: {\n safety: 'write',\n argsType: '{ factor: number }',\n argsSchema: {\n type: 'object',\n properties: {\n factor: { type: 'number', minimum: 1, maximum: 8 },\n },\n required: ['factor'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.setZoom',\n description:\n 'Set the figure zoom factor (1 = reset to the base framing, clamped to 1–8), anchored on the window centre. No-op unless the surface enables `zoomable`.',\n invoke: (handle, args: { factor: number }) => {\n handle.setZoom(args.factor);\n },\n },\n set_tool: {\n safety: 'write',\n argsType: \"{ tool: FaceAnnotationTool | 'none' }\",\n argsSchema: {\n type: 'object',\n properties: { tool: TOOL_SCHEMA },\n required: ['tool'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.setTool',\n description:\n \"Select the active free-form drawing tool ('none' turns drawing off; pointer then falls through to zone selection).\",\n invoke: (handle, args: { tool: string }) => {\n handle.setTool(\n args.tool === 'none' ? null : (args.tool as FaceAnnotationTool),\n );\n },\n },\n undo_annotation: {\n safety: 'write',\n argsType: '{}',\n argsSchema: { type: 'object', properties: {} },\n descriptionKey: 'ui.agent.faceScheme.actions.undoAnnotation',\n description:\n 'Remove the most-recently-added free-form annotation from the active view.',\n invoke: (handle) => {\n handle.undoAnnotation();\n },\n },\n select_annotation: {\n safety: 'read',\n argsType: '{ id: string | null }',\n argsSchema: {\n type: 'object',\n properties: {\n id: {\n type: ['string', 'null'],\n description:\n 'Annotation id on the active view (null clears the selection). Unknown ids are ignored.',\n },\n },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.selectAnnotation',\n description:\n 'Select a free-form annotation on the active view by id (null clears). Selection reveals the mark and enables its panel affordances (delete / recolour).',\n invoke: (handle, args: { id: string | null }) => {\n handle.selectAnnotation(args.id);\n },\n },\n set_annotation_zone: {\n safety: 'write',\n argsType: '{ id: string; zone: string | null }',\n argsSchema: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'Annotation id on the active view.',\n },\n zone: {\n type: ['string', 'null'],\n description: \"Zone id to link, or null to unlink ('no zone').\",\n },\n },\n required: ['id', 'zone'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.setAnnotationZone',\n description:\n 'Link a free-form annotation to a face zone by id (null unlinks it). Unknown annotation ids are ignored. New drawings are auto-linked to the zone under them; this re-assigns marks drawn outside every zone.',\n invoke: (handle, args: { id: string; zone: string | null }) => {\n handle.setAnnotationZone(args.id, args.zone);\n },\n },\n select_zones: {\n safety: 'read',\n argsType: '{ ids: string[] }',\n argsSchema: {\n type: 'object',\n properties: {\n ids: {\n type: 'array',\n items: ZONE_SCHEMA,\n description:\n 'Zone ids to select (replaces the current selection; [] clears).',\n },\n },\n required: ['ids'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.selectZones',\n description:\n 'Replace the zone multi-selection (zoneSelect=\"multi\"). Selection is UI state only — pair with set_finding_bulk to record a finding on the selected zones, or pass ids straight to set_finding_bulk instead.',\n invoke: (handle, args: { ids: string[] }) => {\n handle.setSelectedZones(args.ids);\n },\n },\n set_finding_bulk: {\n safety: 'write',\n argsType: '{ ids: string[]; finding: FaceFindingType; note?: string }',\n argsSchema: {\n type: 'object',\n properties: {\n ids: {\n type: 'array',\n items: ZONE_SCHEMA,\n description: 'Zone ids to record the finding on.',\n },\n finding: FINDING_SCHEMA,\n note: { type: 'string' },\n },\n required: ['ids', 'finding'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.setFindingBulk',\n description:\n 'Record one finding on several zones in a single chart commit (the multi-zone diagnosis path). Zones already carrying the finding are left as they are; the optional note lands only where the finding is newly added.',\n invoke: (\n handle,\n args: { ids: string[]; finding: FaceFindingType; note?: string },\n ) => {\n handle.setFindingBulk(args.ids, args.finding, args.note);\n },\n },\n clear_annotations: {\n safety: 'destructive',\n argsType: '{}',\n argsSchema: { type: 'object', properties: {} },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.clearAnnotations',\n description:\n 'Clear every free-form annotation from the active view. Zone findings are untouched.',\n invoke: (handle) => {\n handle.clearAnnotations();\n },\n },\n },\n domHooks: {\n root: { attr: 'data-component', value: 'face-scheme' },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n item: {\n attr: 'data-zone',\n description:\n 'Each clickable zone `<g>` carries its zone id as `data-zone` (plus `data-side` for the anatomical side, and `data-zone-selected=\"true\"` while in the multi-selection). Each free-form annotation `<g>` carries `data-annotation` (its id), `data-annotation-kind`, `data-annotation-zone` (its linked zone id, when linked), and `data-selected=\"true\"` while selected. The root `<div>` carries the active view id as `data-view` — only the zones for the active view are in the DOM.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* FaceScheme — on-device face-landmark detection (lazy). */\n/* */\n/* Wraps Google's MediaPipe Face Landmarker. The model + wasm runtime */\n/* are LAZY-LOADED from a CDN (overridable) only when detection actually */\n/* runs — so the kit's base bundle ships ZERO ML and FaceScheme stays */\n/* lightweight for consumers that never auto-detect. Everything runs */\n/* on-device: the patient photo and the derived landmarks never leave */\n/* the browser. The same helper is exported for consumer-side use. */\n/* */\n/* It returns canonical-anchor → photo-point pairs in the FaceScheme */\n/* view coordinate space, ready to hand to `FaceSchemeHandle.fitToLand- */\n/* marks` (or the kit feeds them internally for Auto-fit). */\n/* ------------------------------------------------------------------ */\n\nimport type { Point } from './face-scheme-data';\n\n/** Default CDN sources — override to self-host (recommended for production CSP). */\nconst DEFAULT_VISION_MODULE =\n 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.18/vision_bundle.mjs';\nconst DEFAULT_WASM_BASE =\n 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.18/wasm';\nconst DEFAULT_MODEL =\n 'https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task';\n\n/**\n * Canonical FaceScheme anchor → MediaPipe FaceMesh landmark indices.\n * Multiple indices are averaged. Sides are anatomical (the subject's right eye\n * sits on the viewer's left), matching the canonical anchor ids in the data\n * module. Indices are the stable FaceMesh topology (468/478-point).\n */\nconst ANCHOR_INDICES: Record<string, number[]> = {\n 'right-eye': [33, 133], // subject's right eye, outer + inner corners\n 'left-eye': [263, 362], // subject's left eye, outer + inner corners\n 'nose-tip': [1],\n chin: [152],\n // Midline cephalometric points — the profile views fit on these (the detector\n // tracks them on a side profile even though the contralateral side is\n // occluded). The front view ignores ids it has no landmark for.\n nasion: [168], // bridge of the nose, between the brows\n subnasale: [2], // base of the nose / top of the philtrum\n};\n\nexport interface DetectFaceLandmarksOptions {\n /** View coordinate width the points must be projected into (the SVG viewBox W). */\n viewWidth: number;\n /** View coordinate height (the SVG viewBox H). */\n viewHeight: number;\n /** ESM bundle URL for `@mediapipe/tasks-vision`. */\n visionModuleUrl?: string;\n /** Base URL for the MediaPipe wasm fileset. */\n wasmBaseUrl?: string;\n /** URL of the `face_landmarker.task` model. */\n modelAssetPath?: string;\n /** Lifecycle hook — `'loading'` while the model initialises, `'detecting'` during inference. */\n onStage?: (stage: 'loading' | 'detecting') => void;\n}\n\ninterface NormalizedLandmark {\n x: number;\n y: number;\n z: number;\n}\ninterface FaceLandmarkerResult {\n faceLandmarks: NormalizedLandmark[][];\n}\ninterface FaceLandmarkerInstance {\n detect: (image: HTMLImageElement) => FaceLandmarkerResult;\n}\ninterface VisionModule {\n FilesetResolver: { forVisionTasks: (wasmBase: string) => Promise<unknown> };\n FaceLandmarker: {\n createFromOptions: (\n fileset: unknown,\n options: {\n baseOptions: { modelAssetPath: string; delegate?: 'CPU' | 'GPU' };\n runningMode: 'IMAGE' | 'VIDEO';\n numFaces: number;\n },\n ) => Promise<FaceLandmarkerInstance>;\n };\n}\n\n// One landmarker per unique source triple, loaded once and reused.\nconst landmarkerCache = new Map<string, Promise<FaceLandmarkerInstance>>();\n\nfunction getLandmarker(\n visionModuleUrl: string,\n wasmBaseUrl: string,\n modelAssetPath: string,\n onStage?: (stage: 'loading' | 'detecting') => void,\n): Promise<FaceLandmarkerInstance> {\n const key = `${visionModuleUrl}|${wasmBaseUrl}|${modelAssetPath}`;\n const cached = landmarkerCache.get(key);\n if (cached) return cached;\n onStage?.('loading');\n // Variable specifier + @vite-ignore: nothing is bundled or pre-resolved; the\n // ESM module is fetched at call time. Cast through `unknown` — no `any`.\n const promise = (async () => {\n const mod = (await import(\n /* @vite-ignore */ visionModuleUrl\n )) as unknown as VisionModule;\n const fileset = await mod.FilesetResolver.forVisionTasks(wasmBaseUrl);\n return mod.FaceLandmarker.createFromOptions(fileset, {\n baseOptions: { modelAssetPath, delegate: 'GPU' },\n runningMode: 'IMAGE',\n numFaces: 1,\n });\n })();\n landmarkerCache.set(key, promise);\n // Don't cache a rejected init — let the next call retry.\n promise.catch(() => landmarkerCache.delete(key));\n return promise;\n}\n\nfunction loadImage(src: string): Promise<HTMLImageElement> {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.src = src;\n return img.decode().then(() => img);\n}\n\n/**\n * Detect a single face in `src` and return the FaceScheme canonical-anchor →\n * photo-point pairs, projected into the view coordinate space using the same\n * `xMidYMid slice` (cover) fit the FaceScheme `<image>` uses. Resolves `null`\n * if no face is found. Browser-only.\n */\nexport async function detectFaceLandmarks(\n src: string,\n options: DetectFaceLandmarksOptions,\n): Promise<Array<{ id: string; photo: Point }> | null> {\n if (typeof window === 'undefined' || typeof Image === 'undefined') {\n throw new Error('detectFaceLandmarks runs in the browser only.');\n }\n const {\n viewWidth,\n viewHeight,\n visionModuleUrl = DEFAULT_VISION_MODULE,\n wasmBaseUrl = DEFAULT_WASM_BASE,\n modelAssetPath = DEFAULT_MODEL,\n onStage,\n } = options;\n\n const [image, landmarker] = await Promise.all([\n loadImage(src),\n getLandmarker(visionModuleUrl, wasmBaseUrl, modelAssetPath, onStage),\n ]);\n\n onStage?.('detecting');\n const result = landmarker.detect(image);\n const face = result.faceLandmarks[0];\n if (!face || face.length === 0) return null;\n\n // Replicate the component's cover (slice) placement: the image fills the\n // viewBox, centred, cropped — map normalized landmarks → view coordinates.\n const imgW = image.naturalWidth || image.width;\n const imgH = image.naturalHeight || image.height;\n const scale = Math.max(viewWidth / imgW, viewHeight / imgH);\n const offsetX = (viewWidth - imgW * scale) / 2;\n const offsetY = (viewHeight - imgH * scale) / 2;\n const toView = (lm: NormalizedLandmark): Point => ({\n x: offsetX + lm.x * imgW * scale,\n y: offsetY + lm.y * imgH * scale,\n });\n\n const pairs: Array<{ id: string; photo: Point }> = [];\n for (const [id, indices] of Object.entries(ANCHOR_INDICES)) {\n let sx = 0;\n let sy = 0;\n let count = 0;\n for (const idx of indices) {\n const lm = face[idx];\n if (!lm) continue;\n const v = toView(lm);\n sx += v.x;\n sy += v.y;\n count++;\n }\n if (count > 0) pairs.push({ id, photo: { x: sx / count, y: sy / count } });\n }\n return pairs.length >= 3 ? pairs : null;\n}\n","/* ------------------------------------------------------------------ */\n/* FaceScheme — on-device PROFILE face detection (lazy). */\n/* */\n/* The MediaPipe FaceMesh family (see detect-face-landmarks.ts) is */\n/* trained near-frontal: on a 90° lateral profile it under-reads the */\n/* pose and hallucinates the occluded half of the face, so it can't */\n/* register the profile mesh. YuNet (OpenCV Zoo) is a WIDERFACE-trained */\n/* CNN detector that tracks the VISIBLE-side keypoints across poses, so */\n/* the kit uses it for the two profile views. */\n/* */\n/* Runtime: onnxruntime-web is LAZY-LOADED from a CDN (overridable) and */\n/* the ~232 KB model is a code-split asset fetched only when profile */\n/* auto-fit actually runs — the base bundle ships zero ML, matching the */\n/* MediaPipe wrapper. Everything runs on-device: the patient photo and */\n/* the derived keypoints never leave the browser. */\n/* */\n/* It returns YuNet's five canonical keypoints (two eyes, nose tip, two */\n/* mouth corners) projected into the FaceScheme view coordinate space. */\n/* The component picks the visible-side eye + mouth for the profile fit. */\n/* ------------------------------------------------------------------ */\n\nimport type { Point } from './face-scheme-data';\n\n/** Default CDN sources — override to self-host (recommended for production CSP). */\nconst DEFAULT_ORT_MODULE =\n 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.19.2/dist/ort.min.mjs';\nconst DEFAULT_ORT_WASM_BASE =\n 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.19.2/dist/';\n\n/** YuNet 2023mar: fixed 640×640 input, decoded over three strides. */\nconst NET_SIZE = 640;\nconst STRIDES = [8, 16, 32] as const;\n/** YuNet keypoint order → FaceScheme anchor ids (sides are the subject's). */\nconst KEYPOINT_IDS = [\n 'right-eye',\n 'left-eye',\n 'nose-tip',\n 'mouth-right',\n 'mouth-left',\n] as const;\n\nexport interface DetectFaceYuNetOptions {\n /** View coordinate width the points must be projected into (the SVG viewBox W). */\n viewWidth: number;\n /** View coordinate height (the SVG viewBox H). */\n viewHeight: number;\n /** ESM bundle URL for `onnxruntime-web`. */\n ortModuleUrl?: string;\n /** Base URL for the ORT wasm fileset. */\n ortWasmBaseUrl?: string;\n /** URL of the YuNet `.onnx` model (defaults to the kit's bundled copy). */\n modelUrl?: string;\n /** Minimum detection score (default 0.6). */\n scoreThreshold?: number;\n /** Lifecycle hook — `'loading'` while the runtime/model initialise, `'detecting'` during inference. */\n onStage?: (stage: 'loading' | 'detecting') => void;\n}\n\ninterface OrtTensor {\n data: Float32Array;\n dims: readonly number[];\n}\ninterface OrtSession {\n inputNames: string[];\n run: (feeds: Record<string, OrtTensor>) => Promise<Record<string, OrtTensor>>;\n}\ninterface OrtModule {\n env: { wasm: { wasmPaths: string; numThreads: number }; logLevel?: string };\n Tensor: new (\n type: 'float32',\n data: Float32Array,\n dims: number[],\n ) => OrtTensor;\n InferenceSession: {\n create: (\n model: Uint8Array,\n options: { executionProviders: string[] },\n ) => Promise<OrtSession>;\n };\n}\n\n// One session per unique source pair, loaded once and reused.\nconst sessionCache = new Map<\n string,\n Promise<{ ort: OrtModule; session: OrtSession }>\n>();\n\nasync function getSession(\n ortModuleUrl: string,\n ortWasmBaseUrl: string,\n modelUrl: string,\n onStage?: (stage: 'loading' | 'detecting') => void,\n): Promise<{ ort: OrtModule; session: OrtSession }> {\n const key = `${ortModuleUrl}|${ortWasmBaseUrl}|${modelUrl}`;\n const cached = sessionCache.get(key);\n if (cached) return cached;\n onStage?.('loading');\n // Variable specifier + @vite-ignore: nothing is bundled or pre-resolved; the\n // ESM runtime is fetched at call time. Cast through `unknown` — no `any`.\n const promise = (async () => {\n const ort = (await import(\n /* @vite-ignore */ ortModuleUrl\n )) as unknown as OrtModule;\n ort.env.wasm.wasmPaths = ortWasmBaseUrl;\n // Single-threaded: avoids the cross-origin-isolation (COOP/COEP) requirement\n // that SharedArrayBuffer-backed threads impose on the host page.\n ort.env.wasm.numThreads = 1;\n ort.env.logLevel = 'error';\n const model = new Uint8Array(await (await fetch(modelUrl)).arrayBuffer());\n const session = await ort.InferenceSession.create(model, {\n executionProviders: ['wasm'],\n });\n return { ort, session };\n })();\n sessionCache.set(key, promise);\n promise.catch(() => sessionCache.delete(key));\n return promise;\n}\n\nfunction loadImage(src: string): Promise<HTMLImageElement> {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.src = src;\n return img.decode().then(() => img);\n}\n\n/** Resolve the kit's bundled model URL (code-split — fetched only on demand). */\nasync function defaultModelUrl(): Promise<string> {\n const mod = (await import('./face_detection_yunet_2023mar.onnx?url')) as {\n default: string;\n };\n return mod.default;\n}\n\ninterface Candidate {\n score: number;\n keypoints: Array<[number, number]>;\n}\n\n/** Letterbox into NET_SIZE², BGR, NCHW, 0–255 (YuNet/OpenCV convention). */\nfunction preprocess(\n Tensor: OrtModule['Tensor'],\n img: HTMLImageElement,\n): { tensor: OrtTensor; scale: number; padX: number; padY: number } {\n const w = img.naturalWidth || img.width;\n const h = img.naturalHeight || img.height;\n const scale = Math.min(NET_SIZE / w, NET_SIZE / h);\n const dw = Math.round(w * scale);\n const dh = Math.round(h * scale);\n const padX = Math.floor((NET_SIZE - dw) / 2);\n const padY = Math.floor((NET_SIZE - dh) / 2);\n const canvas = document.createElement('canvas');\n canvas.width = NET_SIZE;\n canvas.height = NET_SIZE;\n const ctx = canvas.getContext('2d');\n if (!ctx) throw new Error('2D canvas context unavailable.');\n // Letterbox padding is black: a fresh canvas's default fillStyle is already\n // opaque black, so fillRect needs no colour (YuNet expects zero-padding).\n ctx.fillRect(0, 0, NET_SIZE, NET_SIZE);\n ctx.drawImage(img, padX, padY, dw, dh);\n const { data } = ctx.getImageData(0, 0, NET_SIZE, NET_SIZE);\n const n = NET_SIZE * NET_SIZE;\n const f = new Float32Array(3 * n);\n for (let i = 0; i < n; i++) {\n f[i] = data[i * 4 + 2]; // B\n f[n + i] = data[i * 4 + 1]; // G\n f[2 * n + i] = data[i * 4]; // R\n }\n return {\n tensor: new Tensor('float32', f, [1, 3, NET_SIZE, NET_SIZE]),\n scale,\n padX,\n padY,\n };\n}\n\nconst sigmoid = (x: number): number => 1 / (1 + Math.exp(-x));\n\n/** Decode YuNet's 12 outputs (cls/obj/bbox/kps × 3 strides) → keypoint sets. */\nfunction decode(\n out: Record<string, OrtTensor>,\n scoreThreshold: number,\n): Candidate | null {\n // 2023mar bakes the sigmoid in; older exports emit logits — detect + apply.\n let needSigmoid = false;\n const probe = out['cls_8'].data;\n for (let i = 0; i < Math.min(probe.length, 256); i++) {\n if (probe[i] < 0 || probe[i] > 1) {\n needSigmoid = true;\n break;\n }\n }\n let best: Candidate | null = null;\n for (const s of STRIDES) {\n const cls = out[`cls_${s}`].data;\n const obj = out[`obj_${s}`].data;\n const kps = out[`kps_${s}`].data;\n const cols = NET_SIZE / s;\n const rows = NET_SIZE / s;\n const n = cols * rows;\n for (let i = 0; i < n; i++) {\n let cv = cls[i];\n let ov = obj[i];\n if (needSigmoid) {\n cv = sigmoid(cv);\n ov = sigmoid(ov);\n }\n cv = Math.min(Math.max(cv, 0), 1);\n ov = Math.min(Math.max(ov, 0), 1);\n const score = Math.sqrt(cv * ov);\n if (score < scoreThreshold) continue;\n if (best && score <= best.score) continue;\n const c = i % cols;\n const r = Math.floor(i / cols);\n const keypoints: Array<[number, number]> = [];\n for (let j = 0; j < 5; j++) {\n keypoints.push([\n (c + kps[i * 10 + 2 * j]) * s,\n (r + kps[i * 10 + 2 * j + 1]) * s,\n ]);\n }\n best = { score, keypoints };\n }\n }\n return best;\n}\n\n/**\n * Detect a single face in `src` and return YuNet's canonical keypoint →\n * photo-point pairs, projected into the view coordinate space using the same\n * `xMidYMid slice` (cover) fit the FaceScheme `<image>` uses. Resolves `null`\n * if no face is found. Browser-only.\n */\nexport async function detectFaceYuNet(\n src: string,\n options: DetectFaceYuNetOptions,\n): Promise<Array<{ id: string; photo: Point }> | null> {\n if (typeof window === 'undefined' || typeof Image === 'undefined') {\n throw new Error('detectFaceYuNet runs in the browser only.');\n }\n const {\n viewWidth,\n viewHeight,\n ortModuleUrl = DEFAULT_ORT_MODULE,\n ortWasmBaseUrl = DEFAULT_ORT_WASM_BASE,\n modelUrl = await defaultModelUrl(),\n scoreThreshold = 0.6,\n onStage,\n } = options;\n\n const [image, { ort, session }] = await Promise.all([\n loadImage(src),\n getSession(ortModuleUrl, ortWasmBaseUrl, modelUrl, onStage),\n ]);\n\n onStage?.('detecting');\n const { tensor, scale, padX, padY } = preprocess(ort.Tensor, image);\n const result = await session.run({ [session.inputNames[0]]: tensor });\n const face = decode(result, scoreThreshold);\n if (!face) return null;\n\n // Replicate the component's cover (slice) placement of the <image>.\n const imgW = image.naturalWidth || image.width;\n const imgH = image.naturalHeight || image.height;\n const coverScale = Math.max(viewWidth / imgW, viewHeight / imgH);\n const offsetX = (viewWidth - imgW * coverScale) / 2;\n const offsetY = (viewHeight - imgH * coverScale) / 2;\n\n return face.keypoints.map(([kx, ky], j) => {\n // Un-letterbox (network space → original image px), then project to view.\n const px = (kx - padX) / scale;\n const py = (ky - padY) / scale;\n return {\n id: KEYPOINT_IDS[j],\n photo: {\n x: offsetX + px * coverScale,\n y: offsetY + py * coverScale,\n },\n };\n });\n}\n","/* Provenance — FRONT zones are AUTO-GENERATED by scratchpad/gen-zones.mjs from\n platform faceElements.js and are byte-identical to the platform FaceMap.\n PROFILE zones diverge from the platform on purpose: the platform side-profile is a\n photo-less schematic with a stylised, over-deep skull that no rigid fit can register\n onto a real photographed profile. The kit therefore reshapes the platform-authored\n profile paths with a thin-plate-spline warp pinned to anatomical landmarks (crown,\n nasion, eye, nose-tip, subnasale, lips, chin, jaw-angle, ear, back-skull, nape) so the\n mesh traces a real face for the photo overlay. Do not hand-edit the path data: re-run\n the front generator, or the profile TPS bake (scratchpad/faces/tps + bake-zones), and\n paste the output here. Centroids are the path-bounds midpoint, used to anchor finding\n markers. viewBox is the platform 0 0 808 944. */\n\nimport type { FaceLandmarkSeed, FaceZoneSeed } from './face-scheme-data';\n\nexport const FRONT_VIEWBOX = '0 0 808 944';\nexport const FRONT_PIVOT = { x: 404, y: 472 } as const;\n\nexport const FRONT_CONTOUR: FaceZoneSeed = {\n id: 'faceContour',\n labelKey: 'faceContour',\n d: 'M688.38,439.4c-9.78,0-15.37,4.04-17.86,6.47,1.31-10.99,2.5-20.62,3.49-28.2,7.55-57.89,5.03-94.39,5.03-94.39-15.15-165.92-111.73-221.46-186.21-239.39h0s-.1-.02-.1-.02c-6.18-1.49-12.21-2.72-18.02-3.73l-.96-.2c-46.02-9.51-93.5-9.51-139.52,0l-.95.2c-5.82,1.01-11.85,2.24-18.04,3.73l-.08.02h0c-74.48,17.94-171.06,73.48-186.21,239.39,0,0-2.52,36.5,5.03,94.39,1,7.68,2.2,17.45,3.53,28.61-2.25-2.35-7.91-6.88-18.26-6.88-13.97,0-29.06,16.21-20.12,63.71,8.94,47.5,17.3,80.48,18.43,97.24,1.11,16.47,24.08,47.91,41.43,38.23.9,8.33,1.42,13.17,1.42,13.17,0,0,8.81,59.15,56.63,104.46,12.62,11.95,25.84,23.46,38.49,33.94,7.14-4.56,24-16.96,29.06-35.21.9-3.24,1.73-6.33,2.52-9.29,2.46-9.17,4.59-17.1,7.4-24.46,3.44-9.01,7.62-16.28,13.25-23.04-47.54-46.57-49.82-89.3-48.75-104.93-21.75-2.47-38.06-19.4-47.37-49.37-7.27-23.39-7.77-46.39-7.79-47.36-.02-1.34.43-2.57,1.21-3.54-.47-2.21-.65-3.58-.67-3.77-.28-2.23.97-4.38,3.05-5.24.34-.14.69-.23,1.04-.29.47-3.26,2.23-10.86,8.8-18.21,10.82-12.11,28.95-17.92,53.93-17.22,41.5,1.13,55.11,17.49,59.58,28.15,1.45.85,2.49,2.34,2.68,4.14,0,.05.02.21.05.45.22.48.36,1,.42,1.56.04.41.34,3.71.16,8.68.17,6.11.1,14.39-.75,23.68-.27,2.9-.6,5.73-.98,8.49,4.1-9.94,7.68-20.29,11.15-30.32l.31-.89-10.84-54.18c-2.15-3.39-8.76-12.5-21.75-19.51-21.63-11.68-51.16-12.3-85.4-1.8-2.58.79-5.32-.61-6.19-3.16l-53.03-154.45c-.88-1.09-1.31-2.52-1.05-4.01.26-1.43,6.68-35.35,39.46-69.52,19.15-19.96,43.37-35.84,72.01-47.21,35.3-14.02,77.45-21.18,125.28-21.27h0s.98,0,.98,0c47.83.1,89.98,7.25,125.28,21.27,28.63,11.37,52.86,27.26,72.01,47.21,30.62,31.92,38.24,63.61,39.32,68.82.29.8.42,1.35.47,1.59.17.87.11,1.77-.17,2.61l-53.21,154.96c-.88,2.55-3.62,3.95-6.19,3.16-34.24-10.5-63.77-9.88-85.4,1.8-11.42,6.17-17.92,13.96-20.78,18.06l-11.25,56.25.04.11c2.95,8.52,5.98,17.28,9.34,25.81-.14-1.26-.28-2.53-.4-3.82-.53-5.79-.75-11.19-.81-15.92-1.11-9.09-.51-15.85-.45-16.44.11-1.1.59-2.08,1.3-2.85.19-.72.52-1.37.96-1.94,3.86-10.54,16.77-28.3,60.04-29.48,24.93-.69,43.04,5.1,53.85,17.2,6.53,7.3,8.3,14.85,8.78,18.13.53.04,1.05.16,1.56.37,2.08.86,3.32,3.01,3.05,5.24-.02.14-.12.93-.37,2.25,1.7.96,2.84,2.8,2.8,4.89-.02.97-.52,23.97-7.79,47.36-8.99,28.91-24.49,45.69-45.11,49.05,1.16,15.29-.68,58.78-49.42,106.1,5.35,6.56,9.36,13.63,12.68,22.33,2.81,7.36,4.94,15.28,7.4,24.45.79,2.96,1.62,6.05,2.52,9.29,5.07,18.28,21.97,30.69,29.09,35.23,12.65-10.48,25.88-21.99,38.5-33.95,47.82-45.31,56.63-104.46,56.63-104.46,0,0,.51-4.77,1.4-13,17.31,9.1,39.99-22.04,41.09-38.41,1.13-16.77,9.49-49.74,18.43-97.24,8.94-47.5-6.15-63.71-20.12-63.71Z',\n};\n\nexport const FRONT_ZONES: FaceZoneSeed[] = [\n {\n id: 'lateralNeckRight',\n labelKey: 'lateralNeckRight',\n d: 'M234.37,783.6s32.84,133.08,163.93,137.04v-48.41s-103.52,3.15-163.93-88.63Z',\n cx: 316,\n cy: 852,\n side: 'right',\n },\n {\n id: 'lateralNeckLeft',\n labelKey: 'lateralNeckLeft',\n d: 'M572.98,783.6s-32.84,133.08-163.93,137.04v-48.41s103.52,3.15,163.93-88.63Z',\n cx: 491,\n cy: 852,\n side: 'left',\n },\n {\n id: 'forehead',\n labelKey: 'forehead',\n d: 'M404,206.87s-.1,0-.14,0h-1.06s-.09,0-.14,0c-193.61.2-222.63,42.82-226.18,50.14l51.08,148.75c44.34-12.51,72.83-4.7,89.09,4.28,11.9,6.57,19.12,14.63,22.86,19.75,9.12-6.42,21.26-11.05,36.17-13.79,13.2-2.43,24.31-2.56,27.4-2.54.05,0,.1,0,.16,0h.04s.07,0,.11,0h.04c.2,0,.4,0,.64,0,3.65,0,14.33.22,26.92,2.54,14.91,2.74,27.05,7.37,36.17,13.79,3.74-5.12,10.96-13.18,22.86-19.75,16.26-8.98,44.75-16.79,89.09-4.28l51.08-148.75c-3.54-7.32-32.57-49.94-226.18-50.14Z',\n cx: 403,\n cy: 318,\n side: 'midline',\n },\n {\n id: 'glabella',\n labelKey: 'glabella',\n d: 'M403.28,472.75s.03,0,.04,0c.11,0,.22,0,.34,0,.11,0,.22,0,.34,0,.02,0,.03,0,.04,0,28.06.09,43.26,5.62,51.09,10.26l8.65-43.23c-19.58-15.79-54.78-16.31-59.89-16.33-.13,0-.27,0-.4,0h-.16s-.16,0-.16,0c-.13,0-.27,0-.4,0-5.09-.02-39.63.51-59.32,15.85l8.74,43.71c7.83-4.64,23.03-10.17,51.09-10.26Z',\n cx: 404,\n cy: 453,\n side: 'midline',\n },\n {\n id: 'nasalBase',\n labelKey: 'nasalBase',\n d: 'M403.9,608.63c-.19.02-.38.06-.58.06-34.25,0-47.76,9.72-52.65,15.19-.02.21-.05.42-.1.62,10.07,8.84,28.11,13.48,52.75,13.48.15,0,.29.03.43.04.15-.01.29-.04.43-.04,24.98,0,43.18-4.76,53.17-13.83-4.69-5.41-18.09-15.46-52.89-15.46-.2,0-.38-.04-.58-.06Z',\n cx: 404,\n cy: 623,\n side: 'midline',\n },\n {\n id: 'nasolabialFold',\n labelKey: 'nasolabialFold',\n d: 'M347.77,580.98c-2.28,3.78-4.09,6.76-5.04,9.96-1.38,4.58-3.68,15.46,1.36,25.35,7.25-7.51,23.63-17.61,59.24-17.61.2,0,.38.04.58.06.19-.02.38-.06.58-.06,35.31,0,51.71,9.93,59.05,17.42,4.92-9.84,2.63-20.61,1.27-25.17-.96-3.19-2.76-6.18-5.04-9.96-5.23-8.65-12.39-20.5-14.97-45.03-2.34-22.26,2.15-36.18,6.11-43.75-5.65-3.61-19.1-9.4-47.23-9.45-27.9.05-41.36,5.75-47.09,9.36,3.98,7.55,8.51,21.49,6.16,43.84-2.58,24.53-9.74,36.38-14.97,45.03Z',\n cx: 404,\n cy: 550,\n side: 'midline',\n },\n {\n id: 'medialCheekboneRight',\n labelKey: 'medialCheekboneRight',\n d: 'M310.99,528.29c6.75-7.41,10.08-16.87,11.7-25.19-.55.67-1.13,1.34-1.73,2.02-11.93,13.41-27.69,20.63-45.58,20.88-24.57.33-43.87-10.86-55.92-20.57,6.83,15.71,22.29,36.28,56.41,36.28,15.2,0,27.02-4.51,35.12-13.42Z',\n cx: 271,\n cy: 522,\n side: 'right',\n },\n {\n id: 'medialCheekboneLeft',\n labelKey: 'medialCheekboneLeft',\n d: 'M529.65,526c-17.89-.25-33.66-7.47-45.58-20.88-.48-.54-.94-1.08-1.39-1.62.02.49.04.99.06,1.49,1.74,7.84,5.06,16.45,11.3,23.3,8.11,8.9,19.92,13.42,35.12,13.42,34.11,0,49.57-20.57,56.41-36.28-12.05,9.71-31.35,20.9-55.92,20.57Z',\n cx: 534,\n cy: 523,\n side: 'left',\n },\n {\n id: 'lateralCheekLeft',\n labelKey: 'lateralCheekLeft',\n d: 'M540.15,593.37c-18.18-.45-32.31-6.73-43.63-16.5-1.18-.24-2.29-.88-3.12-1.88-1.11-1.34-2.16-2.75-3.18-4.2-15.93-17.11-25.66-41.5-33.74-64.38-1.86,6.64-3.07,15.9-1.75,28.49,2.35,22.31,8.58,32.62,13.58,40.91,2.44,4.04,4.74,7.85,6.06,12.26,1.9,6.35,5.16,22.19-4,36.16,7.6,9.08,23.47,31.53,26.94,63.94,25.78-26.28,36.07-50.77,40.13-67.19,3.11-12.6,3.1-22.36,2.72-27.61Z',\n cx: 497,\n cy: 597,\n side: 'left',\n },\n {\n id: 'lateralCheekRight',\n labelKey: 'lateralCheekRight',\n d: 'M350.8,505.59c-14.12,40.11-33.1,85.3-81.73,87.86-.37,5.26-.37,15,2.72,27.53,4.02,16.29,14.18,40.52,39.5,66.55,3.52-31.28,18.56-53.18,26.31-62.61-9.73-14.13-6.4-30.4-4.46-36.85,1.32-4.41,3.62-8.22,6.06-12.26,5-8.29,11.23-18.6,13.58-40.91,1.38-13.12,0-22.63-1.99-29.32Z',\n cx: 311,\n cy: 597,\n side: 'right',\n },\n {\n id: 'zygomaticArchRight',\n labelKey: 'zygomaticArchRight',\n d: 'M319.21,534.06c-.26.3-.51.61-.78.91-10.08,11.1-24.4,16.73-42.56,16.73-30.94,0-48.47-15.12-58-28.84,4.69,25.35,16.61,59.69,46.82,59.69,16.21,0,28.81-5.46,38.96-14.31.06-.09.11-.18.18-.26,7.83-9.48,12.57-21.69,15.39-33.93Z',\n cx: 269,\n cy: 553,\n side: 'right',\n },\n {\n id: 'zygomaticArchLeft',\n labelKey: 'zygomaticArchLeft',\n d: 'M542.24,582.4c31.74,0,43.29-37.91,47.48-63.47-.28.46-.57.93-.86,1.4-9.09,14.32-26.82,31.38-59.69,31.38-18.08,0-32.36-5.59-42.43-16.6,2.41,10.07,6.15,20.06,11.85,28.48,10.9,11.46,24.85,18.81,43.65,18.81Z',\n cx: 538,\n cy: 551,\n side: 'left',\n },\n {\n id: 'upperForehead',\n labelKey: 'upperForehead',\n d: 'M524.46,147.46c-34.16-13.49-75.08-20.35-121.64-20.4-46.56.05-87.49,6.91-121.64,20.4-27.26,10.76-50.3,25.76-68.48,44.56-15.39,15.91-24.67,31.94-30.13,44.09,4.92-3.6,11.3-7.4,19.61-11.17,40.86-18.52,108.25-27.96,200.32-28.07.05,0,.11,0,.16,0h.68s.68,0,.68,0c.05,0,.11,0,.16,0,92.07.1,159.46,9.55,200.32,28.07,7.48,3.39,13.39,6.81,18.08,10.08-5.52-12-14.69-27.55-29.63-43-18.18-18.8-41.22-33.79-68.48-44.56Z',\n cx: 403,\n cy: 182,\n side: 'midline',\n },\n {\n id: 'marionetteLines',\n labelKey: 'marionetteLines',\n d: 'M344.66,676.82c23.78-8.45,44.18-6.91,59.31,4.4,15.13-11.32,35.54-12.87,59.33-4.41,9.61,3.41,17.99,7.81,23.93,11.32-3.32-27.6-16.56-47.44-23.55-56.2-11.99,10.66-31.94,16.05-59.49,16.05-.15,0-.29-.03-.43-.04-.15.01-.29.04-.43.04-27.09,0-46.83-5.21-58.88-15.52-7.05,8.98-19.76,28.44-23.08,55.31,5.9-3.44,14.03-7.65,23.29-10.94Z',\n cx: 404,\n cy: 660,\n side: 'midline',\n },\n {\n id: 'lowerLip',\n labelKey: 'lowerLip',\n d: 'M487.84,709.63c-4.92,5.03-11.64,11.3-19.65,17.27-17.67,13.18-35.13,19.92-51.28,19.92-4.52,0-8.94-.53-13.23-1.6-4.29,1.06-8.71,1.6-13.23,1.6-16.15,0-33.61-6.74-51.28-19.92-7.36-5.49-13.63-11.23-18.42-16.03,1.76,38.11,15.57,71.15,82.56,71.15.33,0,.64.04.95.1.31-.06.62-.1.95-.1,67.72,0,81.09-33.76,82.62-72.39Z',\n cx: 404,\n cy: 746,\n side: 'midline',\n },\n {\n id: 'lipCommissures',\n labelKey: 'lipCommissures',\n d: 'M407.45,691.27c-.9.8-2.02,1.19-3.13,1.23-1.34.13-2.72-.26-3.8-1.22-22.23-19.67-55.63-5.3-72.53,4.24,11.5,1.38,25.87,2.57,31.61,1.13,6.72-1.68,12.32.35,18.25,2.5,6.08,2.2,13.64,4.94,25.48,4.98,11.85-.04,19.41-2.78,25.48-4.98,5.93-2.15,11.53-4.18,18.25-2.5,5.93,1.48,21.03.17,32.69-1.26-16.96-9.54-50.17-23.72-72.31-4.13Z',\n cx: 404,\n cy: 688,\n side: 'midline',\n },\n {\n id: 'upperLip',\n labelKey: 'upperLip',\n d: 'M444.65,706.36c-3.59-.9-6.73.14-12.42,2.2-6.4,2.32-15.13,5.47-28.52,5.57-.03,0-.06,0-.09,0-.09,0-.18,0-.28,0-.09,0-.18,0-.28,0-.03,0-.06,0-.09,0-13.39-.1-22.12-3.25-28.52-5.57-5.69-2.06-8.83-3.1-12.42-2.2-6.87,1.72-20.85.72-32.07-.53,15.47,14.96,44.16,37.13,72.34,29.42.46-.13.93-.16,1.39-.15.46,0,.93.03,1.4.15,28.22,7.72,56.98-14.55,72.43-29.5-11.35,1.29-25.82,2.37-32.86.61Z',\n cx: 404,\n cy: 724,\n side: 'midline',\n },\n {\n id: 'submental',\n labelKey: 'submental',\n d: 'M402.47,796.81c-31.67.12-55.93,8.97-72.11,26.31-5.47,5.87-9.06,11.79-11.35,16.53.85.63,1.68,1.27,2.5,1.95,4.99,4.16,26.68,19.07,81.31,19.07s76.32-14.91,81.31-19.07c.65-.54,1.31-1.06,1.98-1.57-2.28-4.8-5.91-10.88-11.53-16.91-16.17-17.35-40.44-26.19-72.11-26.31Z',\n cx: 403,\n cy: 829,\n side: 'midline',\n },\n {\n id: 'mandibularAngleLeft',\n labelKey: 'mandibularAngleLeft',\n d: 'M514.03,757.42c-.91-3.27-1.74-6.39-2.54-9.37-2.39-8.91-4.46-16.6-7.08-23.48-1.84-4.83-3.93-9.07-6.37-12.99-1.26,23.6-6.85,40.74-17.31,53.43-10.17,12.33-24.87,20.32-44.53,24.16,17.13,3.95,34.7,11.85,48.39,26.79,5.59,6.1,9.46,12.22,12.09,17.4,10.43-7.53,28.1-20.6,47.98-36.72-9.19-6.29-25.19-19.64-30.61-39.21Z',\n cx: 490,\n cy: 772,\n side: 'left',\n },\n {\n id: 'mandibularAngleRight',\n labelKey: 'mandibularAngleRight',\n d: 'M372.3,789.03c-19.33-3.89-33.81-11.84-43.86-24.02-10.59-12.83-16.18-30.24-17.35-54.26-2.69,4.15-4.95,8.66-6.92,13.84-2.63,6.88-4.69,14.57-7.08,23.48-.8,2.98-1.64,6.1-2.54,9.37-5.42,19.55-21.39,32.89-30.58,39.19,19.56,15.86,36.98,28.78,47.47,36.36,2.63-5.1,6.44-11.07,11.9-17.03,13.85-15.11,31.67-23.02,48.98-26.92Z',\n cx: 318,\n cy: 772,\n side: 'right',\n },\n {\n id: 'eyelidRight',\n labelKey: 'eyelidRight',\n d: 'M270.93,458.23c-50.38-1.36-52.57,26.33-52.64,27.51-.08,1.39-.72,2.61-1.69,3.46,7.87,8.21,29.3,27.23,58.63,26.79,29.72-.41,43.34-22.6,47.54-31.28-.03-.39-.05-.75-.07-1.07-1.34-6.07-8.94-24.24-51.76-25.41Z',\n cx: 270,\n cy: 487,\n side: 'right',\n },\n {\n id: 'eyelidLeft',\n labelKey: 'eyelidLeft',\n d: 'M586.21,485.71c-.08-1.27-2.3-28.82-52.55-27.45-36.35.99-47.27,14.25-50.55,21.95.08.48.1.98.05,1.49-.01.11-.16,1.63-.31,4.22,4.82,9.37,18.52,29.69,46.94,30.08,29.04.43,50.34-18.21,58.4-26.55-1.13-.87-1.91-2.2-1.98-3.73Z',\n cx: 536,\n cy: 487,\n side: 'left',\n },\n];\n\nexport const FRONT_LANDMARKS: FaceLandmarkSeed[] = [\n { id: 'right-eye', labelKey: 'rightEye', x: 268, y: 487 },\n { id: 'left-eye', labelKey: 'leftEye', x: 535, y: 487 },\n { id: 'nose-tip', labelKey: 'noseTip', x: 403, y: 620 },\n { id: 'chin', labelKey: 'chin', x: 404, y: 858 },\n];\n\n/* Side-profile zone paths (left-facing), kept for a future profile view. Not yet\n wired into FACE_VIEWS — front is the photo-mapping surface today. */\nexport const PROFILE_ZONE_PATHS: FaceZoneSeed[] = [\n {\n id: 'cheekbone',\n labelKey: 'cheekbone',\n d: 'M587.86 415.87C586.01 408.8 583.79 409.02 576.91 410.15C573.08 410.38 567.86 410.32 561.24 408.36C547.07 403.39 488.66 358.5 465.97 345.98C436.12 334.42 407.31 328.09 390.38 326.48C395.19 331.07 399.27 338.58 388.69 345.72C397.48 346.49 408.73 348.34 421.39 351.61C467.3 374.36 523.12 420.78 541.55 435.68C550.62 443.21 555.39 449.39 559.11 454.28C564.66 461.73 567.89 466.16 579.26 467.46C583.31 467.67 586.22 465.29 588.19 460.34C591.18 452.28 592.1 431.43 587.86 415.88Z',\n cx: 490,\n cy: 397,\n },\n {\n id: 'profileContour',\n labelKey: 'profileContour',\n d: 'M657.04 427.15C645.32 417.42 612.92 377.67 608.47 342.76C610.05 315.91 614.77 299.37 606.91 241.79C600.19 175.54 556.62 116.74 420.63 130.08C253.44 160.79 152.79 273.93 132.98 380.57C116.36 516.03 182.43 589.12 182.43 589.12L226.57 641.41C234.86 650.15 249.78 644.43 261.09 627.35L321.54 525.13C328.57 512.58 325.7 495.54 318.17 493.61C294.63 488.83 257.86 468.83 262.84 409.94C267.69 380.06 284 357.04 302.38 340.78C330.2 319.79 367.62 311.97 382.74 320.74C382.87 320.84 382.94 320.94 382.99 321.04C388.82 321.28 405.44 322.73 426.75 326.43C424.09 323.46 422.53 319.98 422.13 315.98C421.41 309.9 423.49 304.51 423.88 303.54C426.23 284.75 477.87 242.7 506.61 211.31L506.84 210.99C508.32 208.89 511.62 207.65 515.45 207.77C519.23 207.92 522.88 209.42 524.98 211.72L567.11 326.31C568.13 330.65 567.2 335.05 564.76 336.69C563.35 337.54 561.24 339.5 558.91 342.14C559.06 342.41 559.15 342.57 559.15 342.57L573.97 372.38C575.71 369.67 578.22 365.84 581.33 362.37C585.49 356.14 590.79 348.98 597.61 352.24C598.15 352.43 598.76 354.7 598.84 357.08C598.91 358.84 598.59 359.88 598.14 359.69C597.37 359.38 596.65 359.2 595.96 359.12C597.33 369.53 600.96 398.18 595.38 398C588.92 397.38 587.72 374.56 588.46 362.31C586.69 363.79 584.85 365.85 582.96 368.5C580.04 371.85 577.73 375.59 576.26 377.97L577.27 380.55C577.56 381.29 577.66 382.22 577.55 383.11C577.43 384 577.11 384.76 576.66 385.24L553.04 396.96C558.13 400.5 560.86 401.88 562.35 402.34C568.32 404.04 572.97 404.02 576.7 403.74C583.09 402.53 587.8 400.9 590.94 412.75C594.16 424.28 596.78 449.29 591.87 464.27C589.18 471.56 584.78 475.46 579.05 475.22C575.99 474.97 573.36 474.4 571.04 473.57C567.75 472.35 565.15 470.69 562.9 468.71C562.88 472.1 562.76 476.4 562.38 481.46C567.8 483.15 578.56 487.63 584.78 500.94C588.58 509.77 589.68 521.45 587.53 535.74C590.03 539.27 597.49 548.85 608.32 547.11C615.16 544.28 621.37 543.88 625.6 545.18C627.13 536.84 628.35 525.82 627.96 516.71C626.08 501.81 623.74 494.92 625.48 485.82C627.82 477.03 640.49 466.24 651.72 451.57C662.37 438.81 663.39 438.52 657.07 427.15Z',\n cx: 390,\n cy: 383,\n },\n {\n id: 'temple',\n labelKey: 'temple',\n d: 'M551.29 339.27C551.73 338.72 552.17 338.34 552.62 338.11C556.19 334.28 559.65 331.21 562.14 329.85C562.68 329.54 562.9 328.65 562.67 327.75L518.07 213.95C517.55 213.37 516.78 213.26 516.36 213.24C515.95 213.22 515.19 213.27 514.81 213.81L514.57 214.13C507.63 223.01 490.31 241.35 473.08 259.55C456.86 274.15 435.38 293.06 434.06 303.22L434.04 303.36L433.97 303.51C433.88 303.72 424.42 324.26 448.09 332.54C448.37 332.66 448.62 332.79 448.84 332.93C456.22 335.74 463.82 338.97 471.46 342.54C502.66 360.75 523.25 375.04 536.66 384.85C535.73 382.31 534.95 379.47 534.57 376.45C533.66 370.15 534.7 364.78 536.86 360.11C539.61 349.89 545.41 345.33 549.41 341.41C549.46 341.36 549.51 341.3 549.56 341.25C550.19 340.57 550.77 339.92 551.29 339.26Z',\n cx: 494,\n cy: 299,\n },\n {\n id: 'preauricularArea',\n labelKey: 'preauricularArea',\n d: 'M399.04 423.47C400.19 426.46 399.28 429.83 397.03 431.07L421.24 493.26C429.33 496.6 440.56 504.27 451.47 519.28C455.98 526.45 460.47 535.45 464.49 546.37C473.34 527.06 479.06 492.31 479.5 447.01C480.52 417.95 479.02 394.87 478.75 390.28C457.75 375.55 435.02 362.96 415.32 355.59C403.76 352.86 393.4 351.38 385.05 350.82C383.53 355.04 382.54 362.85 384.93 378.19C389.1 396.84 398.92 423.16 399.04 423.46Z',\n cx: 432,\n cy: 449,\n },\n {\n id: 'mandibularBody',\n labelKey: 'mandibularBody',\n d: 'M448.9 529.33C441.36 518.39 433.39 511.79 426.69 508.14L444.05 565.22L444.11 565.55C444.61 568.53 446.18 612.75 465.58 621.58C467.31 622.11 469.2 622.59 471.21 623.04C472.27 587.41 463.32 555.13 448.9 529.33Z',\n cx: 449,\n cy: 566,\n },\n {\n id: 'submentalProfile',\n labelKey: 'submentalProfile',\n d: 'M499.51 624.48C500.22 624.28 501.01 624.05 501.85 623.78C506.95 622.1 508.34 617.25 499.33 608.72C499.3 608.71 499.28 608.69 499.25 608.67C498.87 608.43 498.48 608.2 498.08 607.95C489.61 603.09 481.6 597.71 477.16 594.66C477.83 603.57 477.42 613.28 475.61 623.94C494.7 628.41 483.66 636.08 483.66 636.08C483.66 636.08 476.69 649.28 527.7 627.3C518.99 627.63 510.52 627.34 503.56 626.55C496.4 626.16 495.89 625.71 499.5 624.48Z',\n cx: 502,\n cy: 622,\n },\n {\n id: 'masseter',\n labelKey: 'masseter',\n d: 'M554.71 459.19C550.92 454.22 546.49 448.51 537.91 441.39C528.42 433.63 510.52 417.13 488.4 397.93C489.3 421.03 491.75 514.66 467.63 555.34C470.6 563.87 473.34 573.19 475.46 583.39C476.18 582.97 476.93 582.94 477.54 583.4C477.77 583.56 487.55 590.84 499.76 598.04C530.58 563.84 546.09 529.73 552.28 505.65C557.13 483.51 556.81 466.48 556.58 461.68C555.96 460.87 555.34 460.04 554.7 459.2Z',\n cx: 512,\n cy: 498,\n },\n {\n id: 'cheek',\n labelKey: 'cheek',\n d: 'M503.7 600.29L503.69 600.76C506.68 599.48 519.15 594.49 532.76 586.74C551.63 579.2 568.84 567.08 579.23 546.08C584.39 529.37 584.46 515.84 580.48 506.25C575.46 495.21 566.3 491.13 561.55 489.57C560.86 495.06 559.83 501.15 558.34 507.68C551.78 532.36 535.25 566.52 503.69 600.3Z',\n cx: 544,\n cy: 545,\n },\n {\n id: 'chin',\n labelKey: 'chin',\n d: 'M622.37 557.72C618.53 556.38 613.08 555.94 606.76 557.59C595.83 558.3 588.65 550.46 584.99 545.44C584.69 546.34 584.38 547.24 584.03 548.15C571.22 572.11 550.01 585.32 530.6 593C522.53 597.65 514.89 601.46 509.24 604.26C515.21 610.11 514.33 615.81 510.02 618.18C502.34 623.58 523.79 624.61 543.95 623.09C547.34 622.17 550.83 621.19 554.45 620.12L594.99 602.7L595.21 602.54C596.13 601.8 602.57 595.37 608.29 593.49C613.07 590.42 621.01 568.35 622.15 559.26C622.19 558.76 622.27 558.26 622.36 557.75Z',\n cx: 562,\n cy: 585,\n },\n {\n id: 'browTail',\n labelKey: 'browTail',\n d: 'M555.64 346.57C555.64 346.57 530.25 360.36 547.29 391.38L572.95 381.28L555.64 346.57Z',\n cx: 552,\n cy: 369,\n },\n];\n","/* ------------------------------------------------------------------ */\n/* FaceScheme — data module (pure, no React). */\n/* */\n/* The clinical face-zone taxonomy (aesthetic-medicine front view), */\n/* the finding vocabulary + its shared marker glyphs, and the affine */\n/* registration maths used to map the canonical zone mesh onto a real */\n/* patient photo. This module is the swap seam: the FRONT zone `d` paths */\n/* are byte-identical to the platform FaceMap; the PROFILE paths are */\n/* TPS-reshaped to trace a real face (see face-scheme-zones.ts). */\n/* */\n/* Registration is a 6-DOF affine — independent horizontal + vertical */\n/* scale, rotation, shear and translation — emitted as an SVG */\n/* `transform` matrix on the mesh group (never an inline style). The */\n/* same `solveAffine` least-squares fit serves manual landmark drag */\n/* AND a consumer-/kit-run face detector (detect-face-landmarks.ts). */\n/* ------------------------------------------------------------------ */\n\nimport type { MarkerShape, MarkerTone } from '../annotation-marker';\nimport {\n FRONT_CONTOUR,\n FRONT_LANDMARKS,\n FRONT_PIVOT,\n FRONT_VIEWBOX,\n FRONT_ZONES,\n PROFILE_ZONE_PATHS,\n} from './face-scheme-zones';\n\n/* ------------------------------------------------------------------ */\n/* Geometry vocabulary */\n/* ------------------------------------------------------------------ */\n\nexport type FaceViewId = 'front' | 'profile-left' | 'profile-right';\nexport type FaceSide = 'left' | 'right' | 'midline';\n\nexport interface Point {\n x: number;\n y: number;\n}\n\n/** Raw zone shape emitted by the generator (cx/cy/side present for clickable\n * zones, absent on the contour guide). */\nexport interface FaceZoneSeed {\n id: string;\n labelKey: string;\n d: string;\n cx?: number;\n cy?: number;\n side?: FaceSide;\n}\nexport interface FaceLandmarkSeed {\n id: string;\n labelKey: string;\n x: number;\n y: number;\n}\n\n/** A clickable face zone — a region of the canonical mesh. */\nexport interface FaceZone {\n id: string;\n /** `faceScheme.zone.<labelKey>` translation key. */\n labelKey: string;\n /** SVG path data in the view's coordinate space. */\n d: string;\n /** Path-bounds centroid — anchors the finding marker. */\n cx: number;\n cy: number;\n /** Patient-anatomical side (not reading direction). */\n side: FaceSide;\n}\n\n/** A canonical landmark anchor used to fit the mesh to a photo. */\nexport interface FaceLandmark {\n id: string;\n /** `faceScheme.landmark.<labelKey>` translation key. */\n labelKey: string;\n x: number;\n y: number;\n}\n\n/** Axis-aligned box in view user units. */\nexport interface Box {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface FaceView {\n id: FaceViewId;\n /** `faceScheme.view.<labelKey>` translation key. */\n labelKey: string;\n viewBox: string;\n /** Photoless window: measured identity-affine mesh bbox + 24-unit pad,\n pre-mirrored for the right profile. Re-measure if the mesh changes. */\n schematicViewBox: string;\n /** Raw identity-affine mesh bbox in LOCAL (un-mirrored) coords — the\n auto-framing anchor. Same measurement as schematicViewBox, no pad. */\n meshContentBox: Box;\n /** Pivot for the registration controls (the face centre). */\n pivot: Point;\n /** The face outline, drawn as a non-interactive guide. */\n contour: { id: string; labelKey: string; d: string };\n zones: FaceZone[];\n /** Canonical anchors for landmark fitting / auto-detect. */\n landmarks: FaceLandmark[];\n /** Render the mesh horizontally mirrored (right profile = mirrored left). */\n mirror?: boolean;\n}\n\n// The side-profile contour is one of the profile seeds; the rest are the\n// clickable profile zones. They carry no `side` (a profile is single-sided),\n// so default it to 'midline' for the data-side hook.\nconst PROFILE_CONTOUR =\n PROFILE_ZONE_PATHS.find((z) => z.id === 'profileContour') ?? FRONT_CONTOUR;\nconst PROFILE_ZONES: FaceZone[] = PROFILE_ZONE_PATHS.filter(\n (z) => z.id !== 'profileContour',\n).map((z) => ({\n id: z.id,\n labelKey: z.labelKey,\n d: z.d,\n cx: z.cx ?? 0,\n cy: z.cy ?? 0,\n side: z.side ?? 'midline',\n}));\n\n// Canonical profile anchors on the reshaped side-profile mesh (the face faces +x).\n// A non-collinear EYE / NOSE-TIP / MOUTH triangle — exactly the visible-side\n// keypoints the YuNet profile detector returns, which (unlike the old collinear\n// nose-tip/nasion/subnasale/chin midline points) give the affine solver a\n// well-conditioned, shear-free fit. Because the profile mesh is TPS-reshaped to\n// sit on the canonical demo face, these coordinates are the detector's keypoints\n// *on that face* — so Auto-detect resolves to ~identity and preserves the fit\n// rather than re-distorting it. They double as the manual drag handles; the right\n// profile reuses them and mirrors the rendered result. See detect-face-yunet.ts.\nconst PROFILE_LANDMARKS: FaceLandmark[] = [\n { id: 'eye', labelKey: 'eye', x: 561, y: 374 },\n { id: 'nose-tip', labelKey: 'noseTip', x: 668, y: 432 },\n { id: 'mouth', labelKey: 'mouth', x: 592, y: 532 },\n];\n\nexport const FACE_VIEWS: Record<FaceViewId, FaceView> = {\n front: {\n id: 'front',\n labelKey: 'front',\n viewBox: FRONT_VIEWBOX,\n schematicViewBox: '152 103 502 842',\n meshContentBox: { x: 176, y: 127, width: 454, height: 794 },\n pivot: FRONT_PIVOT,\n contour: FRONT_CONTOUR,\n // The generator guarantees every clickable zone carries cx/cy/side.\n zones: FRONT_ZONES as FaceZone[],\n landmarks: FRONT_LANDMARKS,\n },\n // The reshaped profile zones face +x; the right profile is the same mesh\n // mirrored. Both fit on the eye/nose-tip/mouth anchors — auto-detect and manual\n // drag/sliders all work; the right profile mirrors the fit at render time.\n 'profile-left': {\n id: 'profile-left',\n labelKey: 'profileLeft',\n viewBox: FRONT_VIEWBOX,\n schematicViewBox: '359 189 287 475',\n meshContentBox: { x: 383, y: 213, width: 239, height: 427 },\n pivot: FRONT_PIVOT,\n contour: PROFILE_CONTOUR,\n zones: PROFILE_ZONES,\n landmarks: PROFILE_LANDMARKS,\n },\n 'profile-right': {\n id: 'profile-right',\n labelKey: 'profileRight',\n viewBox: FRONT_VIEWBOX,\n schematicViewBox: '162 189 287 475',\n meshContentBox: { x: 383, y: 213, width: 239, height: 427 },\n pivot: FRONT_PIVOT,\n contour: PROFILE_CONTOUR,\n zones: PROFILE_ZONES,\n landmarks: PROFILE_LANDMARKS,\n mirror: true,\n },\n};\n\nexport const FACE_VIEW_IDS: FaceViewId[] = [\n 'front',\n 'profile-left',\n 'profile-right',\n];\n\n/* ------------------------------------------------------------------ */\n/* Finding vocabulary — generic clinical annotations. */\n/* */\n/* Deliberately practice-neutral: the consumer maps these to its own */\n/* clinical meaning. The SHAPE is the accessible channel (WCAG 1.4.1); */\n/* tone is decorative reinforcement only. */\n/* ------------------------------------------------------------------ */\n\nexport type FaceFindingType = 'observation' | 'treatment' | 'concern' | 'note';\n\nexport const FACE_FINDING_TYPES: FaceFindingType[] = [\n 'observation',\n 'treatment',\n 'concern',\n 'note',\n];\n\nexport const FACE_FINDING_MARKER: Record<\n FaceFindingType,\n { shape: MarkerShape; tone: MarkerTone }\n> = {\n observation: { shape: 'circle', tone: 'info' },\n treatment: { shape: 'square', tone: 'success' },\n concern: { shape: 'triangle', tone: 'warning' },\n note: { shape: 'diamond', tone: 'neutral' },\n};\n\nexport interface FaceFinding {\n type: FaceFindingType;\n /** Optional free-text note (PHI — never surfaced in the agent snapshot). */\n note?: string;\n}\n\n/** Findings keyed by zone id. */\nexport type FaceChart = Record<string, FaceFinding[]>;\n\n/* ------------------------------------------------------------------ */\n/* Free-form annotations — positional drawing over the photo. */\n/* */\n/* Distinct from FaceChart (zone-keyed findings): these are freehand, */\n/* POSITIONAL marks in the photo's own viewBox space. They do NOT ride */\n/* the registration affine — the photo doesn't move when the zone mesh */\n/* is re-fitted, so a mark drawn on the cheek stays on the cheek. Kept */\n/* per-view, since each view carries its own photo. Text carries PHI. */\n/* ------------------------------------------------------------------ */\n\n/** The drawing tools the annotation layer exposes. */\nexport type FaceAnnotationTool =\n | 'marker'\n | 'pen'\n | 'highlighter'\n | 'arrow'\n | 'line'\n | 'rect'\n | 'ellipse'\n | 'text';\n\n/** Toolbar order. */\nexport const FACE_ANNOTATION_TOOLS: FaceAnnotationTool[] = [\n 'marker',\n 'pen',\n 'highlighter',\n 'arrow',\n 'line',\n 'rect',\n 'ellipse',\n 'text',\n];\n\n/** Shared fields on every annotation. `tone` is decorative reinforcement of the\n * KIND (shape / stroke style is the accessible channel), never colour alone. */\ninterface FaceAnnotationBase {\n /** Stable id — the kit generates one when the consumer doesn't supply it. */\n id: string;\n tone?: MarkerTone;\n /** Linked clinical zone — a zone id, `null` = assessed outside every zone,\n * `undefined` = never assessed. Sticky: not re-assessed on mesh re-fit. */\n zoneId?: string | null;\n}\n\n/** A shape glyph dropped at an arbitrary point (NOT snapped to a zone). */\nexport interface MarkerAnnotation extends FaceAnnotationBase {\n kind: 'marker';\n x: number;\n y: number;\n shape: MarkerShape;\n}\n/** A freehand stroke — `pen` (opaque, thin) or `highlighter` (translucent, wide). */\nexport interface InkAnnotation extends FaceAnnotationBase {\n kind: 'pen' | 'highlighter';\n points: Point[];\n}\n/** A two-point vector primitive drawn by dragging. */\nexport interface ShapeAnnotation extends FaceAnnotationBase {\n kind: 'arrow' | 'line' | 'rect' | 'ellipse';\n from: Point;\n to: Point;\n}\n/** A typed callout pinned to a point. `text` is PHI — never surfaced in the\n * agent snapshot, never persisted/logged/transmitted by the kit. */\nexport interface TextAnnotation extends FaceAnnotationBase {\n kind: 'text';\n x: number;\n y: number;\n text: string;\n}\n\nexport type FaceAnnotation =\n | MarkerAnnotation\n | InkAnnotation\n | ShapeAnnotation\n | TextAnnotation;\n\n/** The distinct annotation kinds — the agent snapshot reports counts per kind. */\nexport type FaceAnnotationKind = FaceAnnotation['kind'];\n\n/** An annotation as passed to `addAnnotation` — the `id` is optional (the kit\n * generates a stable one when omitted). */\nexport type FaceAnnotationInput =\n | (Omit<MarkerAnnotation, 'id'> & { id?: string })\n | (Omit<InkAnnotation, 'id'> & { id?: string })\n | (Omit<ShapeAnnotation, 'id'> & { id?: string })\n | (Omit<TextAnnotation, 'id'> & { id?: string });\n\n/** Annotations keyed by view — each view draws over its own photo. */\nexport type FaceAnnotations = Partial<Record<FaceViewId, FaceAnnotation[]>>;\n\n/** The annotation kind each tool produces. */\nexport const ANNOTATION_TOOL_KIND: Record<\n FaceAnnotationTool,\n FaceAnnotationKind\n> = {\n marker: 'marker',\n pen: 'pen',\n highlighter: 'highlighter',\n arrow: 'arrow',\n line: 'line',\n rect: 'rect',\n ellipse: 'ellipse',\n text: 'text',\n};\n\n/** True when the tool draws by dragging between two points. */\nexport function isShapeTool(tool: FaceAnnotationTool): boolean {\n return (\n tool === 'arrow' || tool === 'line' || tool === 'rect' || tool === 'ellipse'\n );\n}\n/** True when the tool captures a freehand point stream. */\nexport function isInkTool(tool: FaceAnnotationTool): boolean {\n return tool === 'pen' || tool === 'highlighter';\n}\n/** True when the tool places a single-click annotation (marker / text). */\nexport function isPointTool(tool: FaceAnnotationTool): boolean {\n return tool === 'marker' || tool === 'text';\n}\n\n/** SVG path `d` for a freehand point list (a polyline). Pure — no React/DOM. */\nexport function inkPath(points: Point[]): string {\n if (points.length === 0) return '';\n const first = points[0]!;\n if (points.length === 1) {\n // A dot — nudge so a round-capped zero-length stroke still paints.\n return `M ${first.x} ${first.y} L ${first.x + 0.01} ${first.y}`;\n }\n let d = `M ${first.x} ${first.y}`;\n for (let i = 1; i < points.length; i++) {\n const p = points[i]!;\n d += ` L ${p.x} ${p.y}`;\n }\n return d;\n}\n\n/** SVG path `d` for a two-point shape (arrowhead drawn separately). Pure. */\nexport function shapePath(\n kind: ShapeAnnotation['kind'],\n from: Point,\n to: Point,\n): string {\n switch (kind) {\n case 'line':\n case 'arrow':\n return `M ${from.x} ${from.y} L ${to.x} ${to.y}`;\n case 'rect': {\n const x = Math.min(from.x, to.x);\n const y = Math.min(from.y, to.y);\n const w = Math.abs(to.x - from.x);\n const h = Math.abs(to.y - from.y);\n return `M ${x} ${y} h ${w} v ${h} h ${-w} Z`;\n }\n case 'ellipse': {\n const cx = (from.x + to.x) / 2;\n const cy = (from.y + to.y) / 2;\n const rx = Math.abs(to.x - from.x) / 2;\n const ry = Math.abs(to.y - from.y) / 2;\n if (rx === 0 || ry === 0)\n return `M ${from.x} ${from.y} L ${to.x} ${to.y}`;\n return `M ${cx - rx} ${cy} a ${rx} ${ry} 0 1 0 ${2 * rx} 0 a ${rx} ${ry} 0 1 0 ${-2 * rx} 0 Z`;\n }\n }\n}\n\n/** SVG path `d` for a two-barb arrowhead at `to`, pointing along from→to. Pure. */\nexport function arrowHeadPath(from: Point, to: Point, size = 16): string {\n const dx = to.x - from.x;\n const dy = to.y - from.y;\n const len = Math.hypot(dx, dy) || 1;\n const ux = dx / len;\n const uy = dy / len;\n const ang = 0.5; // ~28° barbs\n const cos = Math.cos(ang);\n const sin = Math.sin(ang);\n const b1x = to.x - size * (ux * cos - uy * sin);\n const b1y = to.y - size * (uy * cos + ux * sin);\n const b2x = to.x - size * (ux * cos + uy * sin);\n const b2y = to.y - size * (uy * cos - ux * sin);\n return `M ${to.x} ${to.y} L ${b1x} ${b1y} M ${to.x} ${to.y} L ${b2x} ${b2y}`;\n}\n\n/** Axis-aligned bounding box of an annotation, in viewBox units. Pure. */\nexport function annotationBBox(a: FaceAnnotation): {\n x: number;\n y: number;\n width: number;\n height: number;\n} {\n switch (a.kind) {\n case 'marker':\n case 'text':\n return { x: a.x, y: a.y, width: 0, height: 0 };\n case 'pen':\n case 'highlighter': {\n if (a.points.length === 0) return { x: 0, y: 0, width: 0, height: 0 };\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const p of a.points) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n }\n default: {\n const minX = Math.min(a.from.x, a.to.x);\n const minY = Math.min(a.from.y, a.to.y);\n const maxX = Math.max(a.from.x, a.to.x);\n const maxY = Math.max(a.from.y, a.to.y);\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n }\n }\n}\n\n/** Bounding-box centre of an annotation — anchors its focus outline / label. */\nexport function annotationAnchor(a: FaceAnnotation): Point {\n switch (a.kind) {\n case 'marker':\n case 'text':\n return { x: a.x, y: a.y };\n case 'pen':\n case 'highlighter': {\n if (a.points.length === 0) return { x: 0, y: 0 };\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const p of a.points) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n return { x: (minX + maxX) / 2, y: (minY + maxY) / 2 };\n }\n default:\n return { x: (a.from.x + a.to.x) / 2, y: (a.from.y + a.to.y) / 2 };\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Selection hit geometry (pure). */\n/* ------------------------------------------------------------------ */\n\n/** Stroke width of an annotation's invisible pointer hit clone, in viewBox units. */\nexport const ANN_HIT_STROKE = 28;\n/** Pointer hit radius around a point annotation (marker), in viewBox units. */\nexport const ANN_HIT_RADIUS = 26;\n\nexport type AnnotationHitGeometry =\n | { type: 'stroke'; d: string }\n | { type: 'circle'; cx: number; cy: number; r: number }\n | { type: 'rect'; x: number; y: number; width: number; height: number };\n\n/** Geometry for an annotation's transparent pointer hit target. Stroke kinds\n * get a fat clone of their own path (hit on the stroke only — a hollow rect /\n * ellipse interior stays click-through to the zones); marker gets a hit\n * circle, text an estimated glyph box. Pure. */\nexport function annotationHitGeometry(\n a: FaceAnnotation,\n textSize = 30,\n): AnnotationHitGeometry {\n switch (a.kind) {\n case 'marker':\n return { type: 'circle', cx: a.x, cy: a.y, r: ANN_HIT_RADIUS };\n case 'pen':\n case 'highlighter':\n return { type: 'stroke', d: inkPath(a.points) };\n case 'arrow':\n case 'line':\n case 'rect':\n case 'ellipse':\n return { type: 'stroke', d: shapePath(a.kind, a.from, a.to) };\n case 'text': {\n // SVG text extent is unmeasurable purely — estimate from glyph count.\n const width = Math.max(60, a.text.length * textSize * 0.62);\n return {\n type: 'rect',\n x: a.x - ANN_HIT_RADIUS,\n y: a.y - textSize * 1.2,\n width: width + ANN_HIT_RADIUS,\n height: textSize * 1.7,\n };\n }\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Registration — 6-DOF affine maths (pure). */\n/* */\n/* A `FaceAffine` is the SVG matrix(a b c d e f): x' = a·x + c·y + e, */\n/* y' = b·x + d·y + f. Applied as a `transform` ATTRIBUTE on the mesh */\n/* group, so it never becomes an inline style. */\n/* ------------------------------------------------------------------ */\n\nexport type FaceAffine = readonly [\n number,\n number,\n number,\n number,\n number,\n number,\n];\n\nexport const IDENTITY_AFFINE: FaceAffine = [1, 0, 0, 1, 0, 0];\n\n/** Per-view registration matrices. */\nexport type FaceRegistration = Partial<Record<FaceViewId, FaceAffine>>;\n\nexport function affineToString(m: FaceAffine): string {\n return `matrix(${m[0]} ${m[1]} ${m[2]} ${m[3]} ${m[4]} ${m[5]})`;\n}\n\nexport function applyAffine(m: FaceAffine, p: Point): Point {\n return {\n x: m[0] * p.x + m[2] * p.y + m[4],\n y: m[1] * p.x + m[3] * p.y + m[5],\n };\n}\n\n/** Inverse of a (non-degenerate) affine: photo space → mesh space. Pure. */\nexport function invertAffine(m: FaceAffine): FaceAffine {\n const det = m[0] * m[3] - m[1] * m[2];\n const ia = m[3] / det;\n const ib = -m[1] / det;\n const ic = -m[2] / det;\n const id = m[0] / det;\n return [ia, ib, ic, id, -(ia * m[4] + ic * m[5]), -(ib * m[4] + id * m[5])];\n}\n\n/** Share of an auto-framed window the registered mesh occupies. 0.84 is the\n * front mesh's natural canvas fill, so the front keeps its full frame and\n * the profiles (smaller canvas share) zoom in to match it. */\nexport const AUTO_FRAME_FRACTION = 0.84;\n\n/**\n * Photo window that frames the registered mesh at a consistent size — the\n * three-up \"equal heads in equal cards\" window. Transforms `meshBox` through\n * `affine` (reflecting for the mirrored right profile), then returns a\n * canvas-aspect window centred on the mesh, sized so the mesh fills\n * `fraction` of it, shifted (never shrunk) to stay inside the canvas.\n * Falls back to the full canvas when the window cannot fit or the input is\n * degenerate. Pure; a window only — never a transform, so mesh, photo and\n * annotation geometry are untouched.\n */\nexport function autoFrameViewBox(\n meshBox: Box,\n affine: FaceAffine,\n canvas: { width: number; height: number },\n opts: { mirror?: boolean; fraction?: number } = {},\n): string {\n const full = `0 0 ${canvas.width} ${canvas.height}`;\n const fraction = opts.fraction ?? AUTO_FRAME_FRACTION;\n if (fraction <= 0 || fraction > 1) return full;\n const corners = [\n { x: meshBox.x, y: meshBox.y },\n { x: meshBox.x + meshBox.width, y: meshBox.y },\n { x: meshBox.x, y: meshBox.y + meshBox.height },\n { x: meshBox.x + meshBox.width, y: meshBox.y + meshBox.height },\n ].map((p) => applyAffine(affine, p));\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const p of corners) {\n minX = Math.min(minX, p.x);\n minY = Math.min(minY, p.y);\n maxX = Math.max(maxX, p.x);\n maxY = Math.max(maxY, p.y);\n }\n if (opts.mirror) {\n const mirroredMin = canvas.width - maxX;\n maxX = canvas.width - minX;\n minX = mirroredMin;\n }\n const bw = maxX - minX;\n const bh = maxY - minY;\n if (!Number.isFinite(minX + minY + bw + bh) || bw <= 0 || bh <= 0) {\n return full;\n }\n const aspect = canvas.width / canvas.height;\n const h = Math.max(bh / fraction, bw / fraction / aspect);\n const w = h * aspect;\n if (w > canvas.width || h > canvas.height) return full;\n const x = Math.min(Math.max(minX + bw / 2 - w / 2, 0), canvas.width - w);\n const y = Math.min(Math.max(minY + bh / 2 - h / 2, 0), canvas.height - h);\n return `${Math.round(x)} ${Math.round(y)} ${Math.round(w)} ${Math.round(h)}`;\n}\n\n/* ------------------------------------------------------------------ */\n/* User zoom / pan — a window composed over the base window */\n/* ------------------------------------------------------------------ */\n\n/** User zoom state: magnification `k` (1 = base window) plus the window\n * origin as fractions of the pannable range, so it survives base-window\n * changes (auto-frame recomputes, registration commits). */\nexport interface FaceZoomState {\n k: number;\n fx: number;\n fy: number;\n}\n\nexport const FACE_ZOOM_MIN = 1;\nexport const FACE_ZOOM_MAX = 8;\nexport const FACE_ZOOM_RESET: FaceZoomState = { k: 1, fx: 0.5, fy: 0.5 };\n\nconst clamp01 = (v: number) => Math.min(Math.max(v, 0), 1);\n\n/** Parse a `\"x y w h\"` viewBox string into a Box. */\nexport function parseViewBox(vb: string): Box {\n const [x = 0, y = 0, width = 0, height = 0] = vb.split(/\\s+/).map(Number);\n return { x, y, width, height };\n}\n\n/** Stringify a Box as a rounded viewBox value. */\nexport function boxToViewBox(b: Box): string {\n return `${Math.round(b.x)} ${Math.round(b.y)} ${Math.round(b.width)} ${Math.round(b.height)}`;\n}\n\n/** The visible window for a zoom state: the base window shrunk by `k`,\n * positioned by the fractional origin. `k <= 1` returns the base. */\nexport function composeZoomWindow(base: Box, z: FaceZoomState): Box {\n if (z.k <= 1) return base;\n const width = base.width / z.k;\n const height = base.height / z.k;\n return {\n x: base.x + z.fx * (base.width - width),\n y: base.y + z.fy * (base.height - height),\n width,\n height,\n };\n}\n\n/** Zoom by `factor` keeping the user-space point `p` fixed in the window.\n * Clamped to [FACE_ZOOM_MIN, FACE_ZOOM_MAX] and to the base bounds. */\nexport function zoomWindowAround(\n base: Box,\n z: FaceZoomState,\n p: { x: number; y: number },\n factor: number,\n): FaceZoomState {\n const k = Math.min(Math.max(z.k * factor, FACE_ZOOM_MIN), FACE_ZOOM_MAX);\n if (k <= 1) return FACE_ZOOM_RESET;\n if (k === z.k || !Number.isFinite(k)) return z;\n const cur = composeZoomWindow(base, z);\n const w = base.width / k;\n const h = base.height / k;\n const u = cur.width > 0 ? clamp01((p.x - cur.x) / cur.width) : 0.5;\n const v = cur.height > 0 ? clamp01((p.y - cur.y) / cur.height) : 0.5;\n const x = p.x - u * w;\n const y = p.y - v * h;\n const rangeX = base.width - w;\n const rangeY = base.height - h;\n return {\n k,\n fx: rangeX > 0 ? clamp01((x - base.x) / rangeX) : 0.5,\n fy: rangeY > 0 ? clamp01((y - base.y) / rangeY) : 0.5,\n };\n}\n\n/** Pan the zoom window by a user-space delta (drag the content by `dx,dy`\n * moves the window the opposite way), clamped to the base bounds. */\nexport function panZoomWindow(\n base: Box,\n z: FaceZoomState,\n dx: number,\n dy: number,\n): FaceZoomState {\n if (z.k <= 1) return z;\n const cur = composeZoomWindow(base, z);\n const rangeX = base.width - cur.width;\n const rangeY = base.height - cur.height;\n return {\n k: z.k,\n fx: rangeX > 0 ? clamp01((cur.x - dx - base.x) / rangeX) : 0.5,\n fy: rangeY > 0 ? clamp01((cur.y - dy - base.y) / rangeY) : 0.5,\n };\n}\n\n/** Editable decomposition of an affine about a pivot — what the numeric\n * registration panel exposes. Angles are degrees. */\nexport interface AffineParts {\n scaleX: number;\n scaleY: number;\n /** degrees */\n rotation: number;\n /** degrees */\n shear: number;\n translateX: number;\n translateY: number;\n}\n\nconst DEG = Math.PI / 180;\n\nexport function composeAffine(parts: AffineParts, pivot: Point): FaceAffine {\n const rad = parts.rotation * DEG;\n const ca = Math.cos(rad);\n const sa = Math.sin(rad);\n const k = Math.tan(parts.shear * DEG);\n const a = parts.scaleX * ca;\n const b = parts.scaleX * sa;\n const c = parts.scaleY * (k * ca - sa);\n const d = parts.scaleY * (k * sa + ca);\n const e = parts.translateX + pivot.x - (a * pivot.x + c * pivot.y);\n const f = parts.translateY + pivot.y - (b * pivot.x + d * pivot.y);\n return [a, b, c, d, e, f];\n}\n\nexport function decomposeAffine(m: FaceAffine, pivot: Point): AffineParts {\n const [a, b, c, d, e, f] = m;\n const scaleX = Math.hypot(a, b);\n const rotation = Math.atan2(b, a) / DEG;\n const det = a * d - b * c;\n const scaleY = scaleX === 0 ? 0 : det / scaleX;\n const shear = Math.atan2(a * c + b * d, det) / DEG;\n const translateX = e - pivot.x + (a * pivot.x + c * pivot.y);\n const translateY = f - pivot.y + (b * pivot.x + d * pivot.y);\n return { scaleX, scaleY, rotation, shear, translateX, translateY };\n}\n\n/**\n * Least-squares 6-DOF affine mapping `src` → `dst` (≥3 non-collinear pairs).\n * Independent horizontal + vertical scale fall out of the fit — this is the\n * shared solver behind both manual landmark drag and face-detector auto-fit.\n * Returns the identity if the system is degenerate.\n */\nexport function solveAffine(src: Point[], dst: Point[]): FaceAffine {\n const n = Math.min(src.length, dst.length);\n if (n < 3) return IDENTITY_AFFINE;\n let Sxx = 0;\n let Sxy = 0;\n let Sx = 0;\n let Syy = 0;\n let Sy = 0;\n let bx0 = 0;\n let bx1 = 0;\n let bx2 = 0;\n let by0 = 0;\n let by1 = 0;\n let by2 = 0;\n for (let i = 0; i < n; i++) {\n const s = src[i];\n const t = dst[i];\n if (!s || !t) continue;\n Sxx += s.x * s.x;\n Sxy += s.x * s.y;\n Sx += s.x;\n Syy += s.y * s.y;\n Sy += s.y;\n bx0 += t.x * s.x;\n bx1 += t.x * s.y;\n bx2 += t.x;\n by0 += t.y * s.x;\n by1 += t.y * s.y;\n by2 += t.y;\n }\n // 3×3 normal matrix N (symmetric); solve N·[a c e]ᵀ = bx and N·[b d f]ᵀ = by.\n const det =\n Sxx * (Syy * n - Sy * Sy) -\n Sxy * (Sxy * n - Sy * Sx) +\n Sx * (Sxy * Sy - Syy * Sx);\n if (Math.abs(det) < 1e-9) return IDENTITY_AFFINE;\n // Inverse of the symmetric 3×3, reused for both right-hand sides.\n const i00 = Syy * n - Sy * Sy;\n const i01 = Sx * Sy - Sxy * n;\n const i02 = Sxy * Sy - Sx * Syy;\n const i11 = Sxx * n - Sx * Sx;\n const i12 = Sx * Sxy - Sxx * Sy;\n const i22 = Sxx * Syy - Sxy * Sxy;\n const solve = (\n r0: number,\n r1: number,\n r2: number,\n ): [number, number, number] => [\n (i00 * r0 + i01 * r1 + i02 * r2) / det,\n (i01 * r0 + i11 * r1 + i12 * r2) / det,\n (i02 * r0 + i12 * r1 + i22 * r2) / det,\n ];\n const [a, c, e] = solve(bx0, bx1, bx2);\n const [b, d, f] = solve(by0, by1, by2);\n return [a, b, c, d, e, f];\n}\n","/* ------------------------------------------------------------------ */\n/* FaceScheme — patient-photo face-zone mapping (aesthetic medicine). */\n/* */\n/* A consumer-supplied patient photo renders as the <image> base; the */\n/* clinical face-zone mesh (byte-identical to the platform FaceMap) */\n/* floats on top as transparent CLICK HOTSPOTS with a crisp 1px outline. */\n/* Because the mesh is a canonical schematic and the photo is an */\n/* arbitrary face, the mesh is REGISTERED onto the photo with a 6-DOF */\n/* affine — independent horizontal/vertical scale, rotation, shear and */\n/* offset — driven by draggable landmark points, accessible numeric */\n/* sliders, or the optional in-kit face detector (lazy-loaded). Findings */\n/* are marked with the shared AnnotationMarker glyph (SHAPE carries the */\n/* meaning, never colour alone) and ride the registration transform. */\n/* */\n/* PHI: the kit is render-only. The photo arrives as a prop and is only */\n/* ever drawn into <image href>; it is never fetched, persisted, logged, */\n/* or exposed through the agent snapshot. The detector runs on-device. */\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type KeyboardEvent,\n type MouseEvent as ReactMouseEvent,\n type PointerEvent as ReactPointerEvent,\n type ReactElement,\n} from 'react';\nimport * as RadixTooltip from '@radix-ui/react-tooltip';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { useAgentRegistration } from '../../agent/registry';\nimport {\n AnnotationMarker,\n markerPath,\n MARKER_SHAPES,\n type MarkerShape,\n type MarkerTone,\n} from '../annotation-marker';\nimport {\n ArrowUpRight,\n Camera,\n Circle as CircleIcon,\n Columns3,\n Eraser,\n Highlighter,\n MapPin,\n Minus,\n MousePointer2,\n Pen,\n PencilRuler,\n Square as SquareIcon,\n Trash2,\n Type as TypeIcon,\n Maximize2,\n Undo2,\n Upload,\n ZoomIn,\n ZoomOut,\n UserRound,\n UserRoundArrowLeft,\n} from 'lucide-react';\nimport { Button, IconButton } from '../button';\nimport { ButtonGroup } from '../button-group';\nimport { Combobox, type ComboboxOption } from '../combobox';\nimport { IconButtonGroup } from '../icon-button-group';\nimport { TextInput } from '../text-input';\nimport { Card } from '../card';\nimport { Separator } from '../separator';\nimport { Slider } from '../slider';\nimport { Switch } from '../switch';\nimport { faceSchemeAgent } from './face-scheme.agent';\nimport { detectFaceLandmarks } from './detect-face-landmarks';\nimport { detectFaceYuNet } from './detect-face-yunet';\nimport {\n FACE_VIEWS,\n FACE_VIEW_IDS,\n FACE_FINDING_MARKER,\n FACE_FINDING_TYPES,\n FACE_ANNOTATION_TOOLS,\n IDENTITY_AFFINE,\n ANN_HIT_STROKE,\n affineToString,\n applyAffine,\n autoFrameViewBox,\n arrowHeadPath,\n annotationAnchor,\n annotationBBox,\n annotationHitGeometry,\n boxToViewBox,\n composeAffine,\n composeZoomWindow,\n invertAffine,\n decomposeAffine,\n FACE_ZOOM_MAX,\n FACE_ZOOM_RESET,\n panZoomWindow,\n parseViewBox,\n zoomWindowAround,\n inkPath,\n shapePath,\n solveAffine,\n type FaceAffine,\n type FaceZoomState,\n type FaceAnnotation,\n type FaceAnnotationInput,\n type FaceAnnotationKind,\n type FaceAnnotations,\n type FaceAnnotationTool,\n type FaceChart,\n type FaceFindingType,\n type FaceRegistration,\n type FaceViewId,\n type FaceZone,\n type Point,\n} from './face-scheme-data';\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport type FaceDetectStatus =\n | 'idle'\n | 'loading'\n | 'detecting'\n | 'done'\n | 'no-face'\n | 'error';\n\nexport interface FaceDetectOptions {\n /** FRONT view (MediaPipe): base URL for the wasm fileset (defaults to the jsDelivr CDN). */\n wasmBaseUrl?: string;\n /** FRONT view (MediaPipe): URL of the `face_landmarker.task` model (defaults to Google's CDN). */\n modelAssetPath?: string;\n /** PROFILE views (YuNet): ESM bundle URL for `onnxruntime-web` (defaults to the jsDelivr CDN). */\n ortModuleUrl?: string;\n /** PROFILE views (YuNet): base URL for the ORT wasm fileset (defaults to the jsDelivr CDN). */\n ortWasmBaseUrl?: string;\n /** PROFILE views (YuNet): URL of the YuNet `.onnx` model (defaults to the kit's bundled copy). */\n yunetModelUrl?: string;\n}\n\n/**\n * Reduce YuNet's five keypoints to the profile fit triangle. On a 90° profile\n * the contralateral eye / mouth-corner are hallucinated FORWARD (toward the\n * nose), so the VISIBLE ones are the keypoints farther from the nose tip in x.\n * The resulting eye / nose-tip / mouth ids match the profile `PROFILE_LANDMARKS`.\n */\nfunction profileTriangleFromYuNet(\n pairs: Array<{ id: string; photo: Point }>,\n): Array<{ id: string; photo: Point }> | null {\n const photoOf = (id: string) => pairs.find((p) => p.id === id)?.photo;\n const nose = photoOf('nose-tip');\n const rightEye = photoOf('right-eye');\n const leftEye = photoOf('left-eye');\n const rightMouth = photoOf('mouth-right');\n const leftMouth = photoOf('mouth-left');\n if (!nose || !rightEye || !leftEye || !rightMouth || !leftMouth) return null;\n const farther = (a: Point, b: Point) =>\n Math.abs(a.x - nose.x) >= Math.abs(b.x - nose.x) ? a : b;\n return [\n { id: 'eye', photo: farther(rightEye, leftEye) },\n { id: 'nose-tip', photo: nose },\n { id: 'mouth', photo: farther(rightMouth, leftMouth) },\n ];\n}\n\nexport interface FaceSchemeProps {\n /** Opaque instance id — emitted as `data-component-id` for the agent registry. */\n id?: string;\n /**\n * Consumer-supplied patient photo for the FRONT view (shorthand for\n * `viewPhotos.front`). RASTER ONLY (object-URL / `data:image` / app CDN\n * raster) — never an `.svg`. PHI: the kit renders it into an SVG\n * `<image href>` and does nothing else (no fetch, persist, log, transmit) and\n * never exposes `src` via the agent snapshot.\n */\n patientPhoto?: { src: string; altKey?: string };\n /** Per-view photos — each view shows its own image, swapped by the switcher. */\n viewPhotos?: Partial<Record<FaceViewId, { src: string; altKey?: string }>>;\n /** Controlled active view (`front` / `profile-left` / `profile-right`). */\n view?: FaceViewId;\n /** Uncontrolled initial view (default `'front'`). */\n defaultView?: FaceViewId;\n /** Fired when the view switcher changes the active view. */\n onViewChange?: (view: FaceViewId) => void;\n /** Show the built-in view switcher tabs (default `true`). */\n showViewSwitcher?: boolean;\n /** Uncontrolled initial layout — `'all'` opens in the three-up view (every\n * face at once, focused view interactive). Default `'single'`. Only takes\n * effect with the view switcher shown, which owns the layout buttons. */\n defaultLayout?: 'single' | 'all';\n /** `'interactive'` enables zone selection, finding edits and registration; `'display'` is read-only. */\n mode?: 'interactive' | 'display';\n /** Controlled findings — `Record<zoneId, FaceFinding[]>`. */\n value?: FaceChart;\n /** Uncontrolled initial findings. */\n defaultValue?: FaceChart;\n /** Fired whenever the chart changes. */\n onChange?: (next: FaceChart) => void;\n /** Fired when a zone is activated (click / Enter / Space). */\n onSelectZone?: (zoneId: string) => void;\n /** The finding type a zone-click applies in interactive mode (toggles it). */\n activeFinding?: FaceFindingType;\n /**\n * `'multi'` turns zone activation (click / Enter / Space) into selection\n * toggling — one diagnosis can then be applied to every selected zone at\n * once from the panel's Zones section, in a single `onChange` commit.\n * `activeFinding` no longer stamps in this mode (it only pre-arms the\n * section); the selection survives view switches. Default `'off'`.\n */\n zoneSelect?: 'off' | 'multi';\n /** Controlled selected zone ids (with `zoneSelect=\"multi\"`). */\n selectedZones?: string[];\n /** Uncontrolled initial selected zone ids. */\n defaultSelectedZones?: string[];\n /** Fired when the zone selection changes. */\n onSelectedZonesChange?: (ids: string[]) => void;\n /* ---- Free-form annotations (draw directly on the photo) ---- */\n /**\n * Controlled per-view annotations — freehand marks (point-anywhere markers,\n * pen / highlighter ink, arrows / lines / boxes / ellipses, text callouts)\n * drawn in the photo's own coordinate space. Distinct from the zone-keyed\n * `value` findings, and they do NOT ride the registration transform. PHI: a\n * text annotation's `text` is rendered only — never logged, persisted,\n * transmitted, or exposed via the agent snapshot.\n */\n annotations?: FaceAnnotations;\n /** Uncontrolled initial annotations. */\n defaultAnnotations?: FaceAnnotations;\n /** Fired whenever the annotations change. */\n onAnnotationsChange?: (next: FaceAnnotations) => void;\n /**\n * Fired when the annotation selection changes (`null` = cleared). Selection\n * is pointer-mode-scoped: it clears on tool or view change, and a freshly\n * committed mark auto-selects so its panel affordances target it at once.\n */\n onAnnotationSelect?: (id: string | null) => void;\n /**\n * Show the built-in Draw section (tool select, colour, marker shape, undo,\n * clear) inside the edit panel. Requires `mode=\"interactive\"`. Default\n * `true` — pass `false` to opt a surface out of the drawing tools.\n */\n showAnnotationToolbar?: boolean;\n /**\n * Opt into figure zoom + pan: mouse-wheel / panel-button zoom on the focused\n * figure, drag-pan from empty space while zoomed, plus a Zoom row in the edit\n * panel. Requires `mode=\"interactive\"`. Default `false` (MuscleScheme parity).\n */\n zoomable?: boolean;\n /**\n * Uncontrolled initial open state of the edit panel (Zones / Draw / Fit\n * sections). Default `true`: the panel is visible everywhere; the control-bar\n * toggle only collapses it.\n */\n defaultPanelOpen?: boolean;\n /** Controlled active drawing tool — `null` = none (pointer falls through to\n * zone selection / registration). */\n activeTool?: FaceAnnotationTool | null;\n /** Uncontrolled initial tool (default `null`). */\n defaultTool?: FaceAnnotationTool | null;\n /** Fired when the active tool changes (built-in toolbar or handle). */\n onToolChange?: (tool: FaceAnnotationTool | null) => void;\n /** Initial marker shape for the marker tool (default `'circle'`). */\n defaultAnnotationShape?: MarkerShape;\n /** Initial annotation tone (default `'accent'`). */\n defaultAnnotationColor?: MarkerTone;\n /** Controlled per-view registration affine. */\n registration?: FaceRegistration;\n /** Uncontrolled initial registration. */\n defaultRegistration?: FaceRegistration;\n /** Fired whenever the registration changes. */\n onRegistrationChange?: (next: FaceRegistration) => void;\n /** `'off'` hides the fit controls; `'adjust'` shows landmark handles + numeric sliders + auto-fit. */\n registrationMode?: 'off' | 'adjust';\n /**\n * Enable the in-kit, on-device face detector for Auto-fit. The front view\n * uses MediaPipe Face Landmarker; the two profile views use YuNet (which,\n * unlike the near-frontal FaceMesh, locates a 90° profile). Both runtimes and\n * their models are lazy-loaded only when detection actually runs, so nothing\n * weighs on the base bundle. Pass options to point at self-hosted models.\n */\n autoDetect?: boolean | FaceDetectOptions;\n /** Observe the detector lifecycle. */\n onDetectStatus?: (status: FaceDetectStatus) => void;\n /**\n * Opt-in: show an on-device photo-capture affordance — a live camera\n * viewfinder (with a file-upload fallback). The captured frame is rendered\n * into the same `<image>` base and emitted via `onCapture`; it is never\n * uploaded, persisted, or logged by the kit. The camera stream is torn down\n * the instant a frame is frozen and on cancel / unmount. Independent of\n * `mode` — set it wherever the practitioner should be able to (re)take the\n * photo.\n */\n allowCapture?: boolean;\n /** Camera to request for capture (default `'user'` — a face self-portrait). */\n captureFacingMode?: 'user' | 'environment';\n /**\n * Fired when a photo is captured or chosen — a `data:` URL, its intrinsic\n * pixel size, and the view it belongs to. PHI: the consumer owns persistence;\n * the kit only renders it.\n */\n onCapture?: (photo: {\n src: string;\n width: number;\n height: number;\n view: FaceViewId;\n }) => void;\n /** Show the finding-type legend below the figure. */\n legend?: boolean;\n /** Accessible label override for the chart region. */\n ariaLabel?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n}\n\nexport interface FaceSchemeHandle {\n /** Focus a zone by id. */\n focusZone: (zoneId: string) => void;\n /** Read the current chart state. */\n getChart: () => FaceChart;\n /** Read the findings on one zone (empty array if none). */\n getZone: (zoneId: string) => FaceChart[string];\n /** Read the zone ids carrying a given finding type. */\n zonesWith: (type: FaceFindingType) => string[];\n /** Add a finding to a zone (no-op if already present). */\n setFinding: (zoneId: string, type: FaceFindingType, note?: string) => void;\n /** Remove a finding type from a zone. */\n removeFinding: (zoneId: string, type: FaceFindingType) => void;\n /** Clear every finding from a zone. */\n clearZone: (zoneId: string) => void;\n /** Read the active-view registration affine. */\n getRegistration: () => FaceAffine;\n /** Set the active-view registration affine. */\n setRegistration: (m: FaceAffine) => void;\n /** Reset the active-view registration to the identity. */\n resetRegistration: () => void;\n /** Solve + apply an affine from canonical-anchor → photo-point pairs. */\n fitToLandmarks: (pairs: { id: string; photo: Point }[]) => void;\n /** Run the on-device detector on the current photo and auto-fit. Resolves\n * `true` on a successful fit, `false` if detection is disabled / finds no face. */\n detect: () => Promise<boolean>;\n /** Start the on-device camera viewfinder (no-op if capture is disabled or the\n * camera API is unavailable — emits an error status in that case). */\n startCapture: () => void;\n /** Stop the camera viewfinder without capturing. */\n cancelCapture: () => void;\n /** Read the active view id (`front` / `profile-left` / `profile-right`). */\n getView: () => FaceViewId;\n /** Switch the active view. */\n setView: (view: FaceViewId) => void;\n /** Read the current zoom factor (1 = base window). */\n getZoom: () => number;\n /** Set the zoom factor (clamped to 1–8), anchored on the window centre. */\n setZoom: (factor: number) => void;\n /** Reset zoom and pan to the base window. */\n resetZoom: () => void;\n /** Read the active-view annotations. */\n getAnnotations: () => FaceAnnotation[];\n /** Add an annotation to the active view; returns its (generated) id. */\n addAnnotation: (annotation: FaceAnnotationInput) => string;\n /** Remove an annotation from the active view by id. */\n removeAnnotation: (id: string) => void;\n /** Remove the most-recently-added annotation on the active view. */\n undoAnnotation: () => void;\n /** Clear every annotation from the active view. */\n clearAnnotations: () => void;\n /** Read the active drawing tool (`null` = none). */\n getTool: () => FaceAnnotationTool | null;\n /** Set the active drawing tool (`null` = none). */\n setTool: (tool: FaceAnnotationTool | null) => void;\n /** Read the selected annotation (id + kind), or `null` when none. */\n getSelectedAnnotation: () => { id: string; kind: FaceAnnotationKind } | null;\n /** Select an active-view annotation by id (`null` clears; unknown ids no-op). */\n selectAnnotation: (id: string | null) => void;\n /** Link / unlink an active-view annotation to a zone (`null` = no zone). */\n setAnnotationZone: (id: string, zoneId: string | null) => void;\n /** Read the selected zone ids (`zoneSelect=\"multi\"`). */\n getSelectedZones: () => string[];\n /** Replace the zone selection (any view's zone ids). */\n setSelectedZones: (ids: string[]) => void;\n /** Clear the zone selection. */\n clearZoneSelection: () => void;\n /** Add a finding to every selected zone in ONE chart commit; the optional\n * note lands only on zones the finding is newly added to. */\n applyFindingToSelection: (type: FaceFindingType, note?: string) => void;\n /** Remove a finding type from every selected zone in ONE chart commit. */\n removeFindingFromSelection: (type: FaceFindingType) => void;\n /** Selection-independent bulk write — add a finding to each given zone in\n * ONE chart commit (the agent `set_finding_bulk` path). */\n setFindingBulk: (ids: string[], type: FaceFindingType, note?: string) => void;\n}\n\n/* ------------------------------------------------------------------ */\n/* Capture (on-device camera) — privacy-first, mirrors DocumentScanner */\n/* ------------------------------------------------------------------ */\n\nexport type FaceCaptureState = 'idle' | 'requesting' | 'streaming' | 'error';\nexport type FaceCaptureError =\n | 'permission-denied'\n | 'no-camera'\n | 'not-readable'\n | 'insecure-context'\n | 'capture-failed';\n\n/** True when getUserMedia is reachable (secure context + API present). */\nfunction mediaDevicesAvailable(): boolean {\n return (\n typeof navigator !== 'undefined' &&\n typeof navigator.mediaDevices !== 'undefined' &&\n typeof navigator.mediaDevices.getUserMedia === 'function'\n );\n}\n\n/** Map a getUserMedia rejection (a DOMException) to our error kind. */\nfunction classifyMediaError(err: unknown): FaceCaptureError {\n const name = err instanceof Error ? err.name : '';\n if (name === 'NotAllowedError' || name === 'SecurityError')\n return 'permission-denied';\n if (name === 'NotFoundError' || name === 'OverconstrainedError')\n return 'no-camera';\n if (name === 'NotReadableError' || name === 'AbortError')\n return 'not-readable';\n return 'capture-failed';\n}\n\nconst CAPTURE_ERROR_KEY: Record<FaceCaptureError, string> = {\n 'permission-denied': 'faceScheme.capture.error.permissionDenied',\n 'no-camera': 'faceScheme.capture.error.noCamera',\n 'not-readable': 'faceScheme.capture.error.notReadable',\n 'insecure-context': 'faceScheme.capture.error.insecureContext',\n 'capture-failed': 'faceScheme.capture.error.captureFailed',\n};\n\n/* ------------------------------------------------------------------ */\n/* Tone → fill class (no inline styles; tokens only) */\n/* ------------------------------------------------------------------ */\n\nconst markerToneFill: Record<MarkerTone, string> = {\n neutral: 'ds:[fill:var(--muted-foreground)]',\n info: 'ds:[fill:var(--info)]',\n success: 'ds:[fill:var(--success)]',\n warning: 'ds:[fill:var(--warning)]',\n error: 'ds:[fill:var(--destructive)]',\n accent: 'ds:[fill:var(--accent)]',\n};\n\n// Annotation strokes reuse the same tone → token map. The annotation layer is\n// NOT inside the affine group, so strokes are in plain viewBox user units and\n// scale with the photo (no non-scaling-stroke needed).\nconst annotationToneStroke: Record<MarkerTone, string> = {\n neutral: 'ds:[stroke:var(--muted-foreground)]',\n info: 'ds:[stroke:var(--info)]',\n success: 'ds:[stroke:var(--success)]',\n warning: 'ds:[stroke:var(--warning)]',\n error: 'ds:[stroke:var(--destructive)]',\n accent: 'ds:[stroke:var(--accent)]',\n};\n\n// Annotation geometry, in the 808×944 viewBox's user units (calibrated to the\n// zone-marker r≈11 scale). Plain widths — the layer is not transformed.\nconst ANN_MARKER_R = 13;\nconst ANN_PEN_WIDTH = 5;\nconst ANN_HIGHLIGHTER_WIDTH = 24;\nconst ANN_SHAPE_WIDTH = 5;\nconst ANN_ARROW_HEAD = 26;\nconst ANN_TEXT_SIZE = 30;\nconst ANN_FOCUS_PAD = 14;\n\n// A stable empty list so a view with no annotations doesn't churn identity.\nconst EMPTY_ANNOTATIONS: FaceAnnotation[] = [];\n\n// Placeholder id for the in-progress draft (never committed as-is).\nconst DRAFT_ID = '__draft__';\n\n// Bar + three-up render order — Front centred between the two profiles.\n// Data-model order (FACE_VIEW_IDS) is unchanged; this is presentation only.\nconst VIEW_RENDER_ORDER: FaceViewId[] = [\n 'profile-left',\n 'front',\n 'profile-right',\n];\n\n// The profiles share one glyph; the right one is mirrored physically — an\n// anatomical direction, so it must not re-flip under RTL (no flipIconInRtl).\nconst VIEW_ICON: Record<FaceViewId, ReactElement> = {\n 'profile-left': <UserRoundArrowLeft aria-hidden=\"true\" />,\n front: <UserRound aria-hidden=\"true\" />,\n 'profile-right': (\n <UserRoundArrowLeft aria-hidden=\"true\" className=\"ds:-scale-x-100\" />\n ),\n};\n\n/** The toolbar's tool set, including a leading \"select\" (no drawing) tool. */\ntype ToolbarValue = 'select' | FaceAnnotationTool;\n\n/** lucide icon per tool for the built-in drawing toolbar. */\nconst TOOL_ICON: Record<ToolbarValue, typeof MapPin> = {\n select: MousePointer2,\n marker: MapPin,\n pen: Pen,\n highlighter: Highlighter,\n arrow: ArrowUpRight,\n line: Minus,\n rect: SquareIcon,\n ellipse: CircleIcon,\n text: TypeIcon,\n};\n\n/** Selectable annotation tones for the built-in colour picker. */\nconst ANNOTATION_TONES: MarkerTone[] = [\n 'accent',\n 'info',\n 'success',\n 'warning',\n 'error',\n 'neutral',\n];\n\n// One fill declaration per zone resolved through compoundVariants. The outline is\n// a constant 1px (non-scaling-stroke) so it stays crisp under the registration\n// scale. To keep dense meshes (the profile jaw, the 22-zone front) legible, an\n// unmarked zone's outline sits at a low stroke-opacity at rest and rises to full\n// on hover, on keyboard focus (see the wrapper's focus-visible rule), or when the\n// zone carries a finding; the fill reveals on the same triggers.\nconst zoneVariants = cva(\n [\n 'ds:[vector-effect:non-scaling-stroke]',\n 'ds:transition-[fill-opacity,stroke-opacity] ds:[transition-duration:var(--animation-duration)]',\n 'ds:[fill:transparent] ds:[stroke:var(--accent)] ds:[stroke-width:1] ds:[stroke-opacity:0.35]',\n ].join(' '),\n {\n variants: {\n interactive: { true: 'ds:cursor-pointer', false: '' },\n marked: { true: '', false: '' },\n selected: { true: '', false: '' },\n },\n compoundVariants: [\n {\n marked: false,\n interactive: true,\n class:\n 'ds:hover:[fill:var(--accent)] ds:hover:[fill-opacity:0.14] ds:hover:[stroke-opacity:1]',\n },\n {\n marked: true,\n class:\n 'ds:[fill:var(--accent)] ds:[fill-opacity:0.18] ds:[stroke-opacity:1]',\n },\n // Multi-select membership — a heavier outline than the marked tint so the\n // two states read apart even when they coincide on one zone.\n {\n selected: true,\n class:\n 'ds:[fill:var(--accent)] ds:[fill-opacity:0.16] ds:[stroke-opacity:0.9] ds:[stroke-width:2] ds:forced-colors:[stroke:Highlight]',\n },\n ],\n defaultVariants: { interactive: false, marked: false, selected: false },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nconst SLIDER_RANGES = {\n scaleX: { min: 0.3, max: 1.8, step: 0.01 },\n scaleY: { min: 0.3, max: 1.8, step: 0.01 },\n rotation: { min: -20, max: 20, step: 0.5 },\n shear: { min: -20, max: 20, step: 0.5 },\n translateX: { min: -240, max: 240, step: 1 },\n translateY: { min: -240, max: 240, step: 1 },\n} as const;\n\ntype SliderField = keyof typeof SLIDER_RANGES;\n// Order mirrors the 6 DOF the pointer-drag fit can reach, so the keyboard path\n// has full parity with the landmark handles (size → angle/skew → position).\nconst SLIDER_FIELDS: SliderField[] = [\n 'scaleX',\n 'scaleY',\n 'rotation',\n 'shear',\n 'translateX',\n 'translateY',\n];\n\n/* ------------------------------------------------------------------ */\n/* FaceScheme */\n/* ------------------------------------------------------------------ */\n\nexport const FaceScheme = forwardRef<FaceSchemeHandle, FaceSchemeProps>(\n (\n {\n id,\n patientPhoto,\n viewPhotos,\n view: viewProp,\n defaultView = 'front',\n onViewChange,\n showViewSwitcher = true,\n defaultLayout = 'single',\n mode = 'interactive',\n value,\n defaultValue,\n onChange,\n onSelectZone,\n activeFinding,\n zoneSelect = 'off',\n selectedZones: selectedZonesProp,\n defaultSelectedZones,\n onSelectedZonesChange,\n annotations,\n defaultAnnotations,\n onAnnotationsChange,\n onAnnotationSelect,\n showAnnotationToolbar = true,\n zoomable = false,\n defaultPanelOpen = true,\n activeTool,\n defaultTool = null,\n onToolChange,\n defaultAnnotationShape = 'circle',\n defaultAnnotationColor = 'accent',\n registration,\n defaultRegistration,\n onRegistrationChange,\n registrationMode = 'off',\n autoDetect,\n onDetectStatus,\n allowCapture = false,\n captureFacingMode = 'user',\n onCapture,\n legend = false,\n ariaLabel,\n className,\n },\n ref,\n ) => {\n const { t } = useTranslation();\n const reactId = useId();\n const instanceId = id ?? reactId;\n const rootRef = useRef<HTMLDivElement>(null);\n const svgRef = useRef<SVGSVGElement>(null);\n const videoRef = useRef<HTMLVideoElement>(null);\n const streamRef = useRef<MediaStream | null>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n // The persistent Take/Retake button — focus re-homes here when the\n // streaming viewfinder (which held focus) unmounts on capture / cancel.\n const captureButtonRef = useRef<HTMLButtonElement>(null);\n const unmountedRef = useRef(false);\n\n /* ---- Active view (controlled / uncontrolled, tab-driven) ---- */\n const isViewControlled = viewProp !== undefined;\n const [internalView, setInternalView] = useState<FaceViewId>(\n viewProp ?? defaultView,\n );\n const viewId = isViewControlled ? viewProp : internalView;\n const viewIdRef = useRef<FaceViewId>(viewId);\n viewIdRef.current = viewId;\n const setView = useCallback(\n (next: FaceViewId) => {\n if (!isViewControlled) setInternalView(next);\n onViewChange?.(next);\n },\n [isViewControlled, onViewChange],\n );\n\n // Whether the edit panel (Zones / Draw / Fit sections) is shown. Open by\n // default everywhere; the PencilRuler disclosure only collapses it.\n const [panelOpen, setPanelOpen] = useState(defaultPanelOpen);\n const panelId = `${reactId}-panel`;\n\n // Layout: 'single' shows the focused view (settings beside it); 'all' is the\n // three-up view showing every face at once (settings underneath). The\n // control bar's Front/Left/Right pick a single view; All switches to 'all'.\n const [layout, setLayout] = useState<'single' | 'all'>(defaultLayout);\n\n // Whether the finding legend card (below the figure) is shown — flipped by a\n // toggle inside the settings card. Only relevant when `legend` is enabled.\n const [showLegend, setShowLegend] = useState(true);\n\n const view = FACE_VIEWS[viewId];\n const [, , vbW, vbH] = view.viewBox.split(' ').map(Number) as [\n number,\n number,\n number,\n number,\n ];\n const interactive = mode === 'interactive';\n const adjusting = interactive && registrationMode === 'adjust';\n\n /* ---- Findings state (controlled / uncontrolled) ---- */\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState<FaceChart>(defaultValue ?? {});\n const chart = isControlled ? value : internal;\n const chartRef = useRef<FaceChart>(chart);\n chartRef.current = chart;\n\n const commitChart = useCallback(\n (next: FaceChart) => {\n if (!isControlled) setInternal(next);\n onChange?.(next);\n },\n [isControlled, onChange],\n );\n\n const addFinding = useCallback(\n (zoneId: string, type: FaceFindingType, note?: string) => {\n const current = chartRef.current[zoneId] ?? [];\n if (current.some((f) => f.type === type)) return;\n commitChart({\n ...chartRef.current,\n [zoneId]: [...current, { type, note }],\n });\n },\n [commitChart],\n );\n const removeFindingFn = useCallback(\n (zoneId: string, type: FaceFindingType) => {\n const current = chartRef.current[zoneId] ?? [];\n const next = current.filter((f) => f.type !== type);\n const copy = { ...chartRef.current };\n if (next.length > 0) copy[zoneId] = next;\n else delete copy[zoneId];\n commitChart(copy);\n },\n [commitChart],\n );\n const toggleFinding = useCallback(\n (zoneId: string, type: FaceFindingType) => {\n const has = (chartRef.current[zoneId] ?? []).some(\n (f) => f.type === type,\n );\n if (has) removeFindingFn(zoneId, type);\n else addFinding(zoneId, type);\n },\n [addFinding, removeFindingFn],\n );\n\n /* ---- Zone multi-selection (zoneSelect=\"multi\") ---- */\n const zoneSelectMode = interactive && zoneSelect === 'multi';\n const isZoneSelControlled = selectedZonesProp !== undefined;\n const [internalZoneSel, setInternalZoneSel] = useState<string[]>(\n defaultSelectedZones ?? [],\n );\n const zoneSelection = isZoneSelControlled\n ? selectedZonesProp\n : internalZoneSel;\n const zoneSelectionRef = useRef<string[]>(zoneSelection);\n zoneSelectionRef.current = zoneSelection;\n const zoneSelectionSet = useMemo(\n () => new Set(zoneSelection),\n [zoneSelection],\n );\n const commitZoneSelection = useCallback(\n (ids: string[]) => {\n // Eager ref update so same-tick sequential handle / agent calls\n // compose instead of reading a stale selection.\n if (!isZoneSelControlled) zoneSelectionRef.current = ids;\n if (!isZoneSelControlled) setInternalZoneSel(ids);\n onSelectedZonesChange?.(ids);\n },\n [isZoneSelControlled, onSelectedZonesChange],\n );\n const toggleZoneSelected = useCallback(\n (zoneId: string) => {\n const cur = zoneSelectionRef.current;\n commitZoneSelection(\n cur.includes(zoneId)\n ? cur.filter((z) => z !== zoneId)\n : [...cur, zoneId],\n );\n },\n [commitZoneSelection],\n );\n const clearZoneSelectionFn = useCallback(() => {\n if (zoneSelectionRef.current.length > 0) commitZoneSelection([]);\n }, [commitZoneSelection]);\n // Optional shared note typed in the Zones section — consumed (and cleared)\n // by the next bulk apply; it never mutates findings that already exist.\n const [bulkNote, setBulkNote] = useState('');\n\n // Bulk chart writes — the whole batch lands as ONE commit so controlled\n // consumers see a single onChange (never one per zone). The shared note\n // rides only on zones the finding is newly added to.\n const setFindingBulkFn = useCallback(\n (ids: string[], type: FaceFindingType, note?: string) => {\n const next = { ...chartRef.current };\n let changed = false;\n for (const zoneId of ids) {\n const cur = next[zoneId] ?? [];\n if (cur.some((f) => f.type === type)) continue;\n next[zoneId] = [...cur, { type, note }];\n changed = true;\n }\n if (changed) commitChart(next);\n },\n [commitChart],\n );\n const removeFindingBulkFn = useCallback(\n (ids: string[], type: FaceFindingType) => {\n const next = { ...chartRef.current };\n let changed = false;\n for (const zoneId of ids) {\n const cur = next[zoneId] ?? [];\n if (!cur.some((f) => f.type === type)) continue;\n const rest = cur.filter((f) => f.type !== type);\n if (rest.length > 0) next[zoneId] = rest;\n else delete next[zoneId];\n changed = true;\n }\n if (changed) commitChart(next);\n },\n [commitChart],\n );\n\n /* ---- Registration state (controlled / uncontrolled) ---- */\n const isRegControlled = registration !== undefined;\n const [internalReg, setInternalReg] = useState<FaceRegistration>(\n defaultRegistration ?? {},\n );\n const regMap = isRegControlled ? registration : internalReg;\n const activeAffine = regMap[viewId] ?? IDENTITY_AFFINE;\n const affineRef = useRef<FaceAffine>(activeAffine);\n affineRef.current = activeAffine;\n // Mirror of the full registration map so commits never read a stale closure.\n const affineRefMap = useRef<FaceRegistration>(regMap);\n affineRefMap.current = regMap;\n\n const commitReg = useCallback(\n (m: FaceAffine) => {\n const next = { ...affineRefMap.current, [viewId]: m };\n if (!isRegControlled) setInternalReg(next);\n onRegistrationChange?.(next);\n },\n [isRegControlled, onRegistrationChange, viewId],\n );\n\n const parts = useMemo(\n () => decomposeAffine(activeAffine, view.pivot),\n [activeAffine, view.pivot],\n );\n\n // The right-profile mesh is flipped about the frame centre at render time,\n // so landmark photo points (detector output, drag targets) must be flipped\n // to / from the un-mirrored space the affine is solved in. Self-inverse.\n const mirrorPt = useCallback(\n (p: Point): Point => (view.mirror ? { x: vbW - p.x, y: p.y } : p),\n [view.mirror, vbW],\n );\n\n /* ---- Landmark handle targets (pointer fitting) ---- */\n const [targets, setTargets] = useState<Point[]>(() =>\n view.landmarks.map((lm) => mirrorPt(applyAffine(activeAffine, lm))),\n );\n // Keep handles riding the mesh when the affine changes for any reason other\n // than an in-progress drag (slider, auto-fit, reset, external prop).\n const draggingRef = useRef<number | null>(null);\n // Auto-framed three-up window, frozen for the duration of a handle drag\n // so the photo doesn't zoom underfoot while the mesh is being fitted.\n // frameNowRef carries the current window (assigned each render, since the\n // drag handlers are declared before the layout state they'd close over).\n const [frozenFrame, setFrozenFrame] = useState<string | null>(null);\n const frameNowRef = useRef<string | null>(null);\n\n /* ---- User zoom / pan (opt-in) — a window composed over the base ---- */\n const [zoomState, setZoomState] = useState<FaceZoomState>(FACE_ZOOM_RESET);\n const zoomStateRef = useRef(zoomState);\n zoomStateRef.current = zoomState;\n // Base window (full canvas / auto-frame / schematic crop) as a string;\n // assigned each render at the focused-figure site, read by handlers.\n const baseWindowRef = useRef<string>(view.viewBox);\n const panRef = useRef<{ id: number; x: number; y: number } | null>(null);\n useEffect(() => {\n if (draggingRef.current !== null) return;\n setTargets(\n view.landmarks.map((lm) => mirrorPt(applyAffine(activeAffine, lm))),\n );\n }, [activeAffine, view.landmarks, mirrorPt]);\n\n const fitFromPairs = useCallback(\n (pairs: { id: string; photo: Point }[]) => {\n const src: Point[] = [];\n const dst: Point[] = [];\n for (const pair of pairs) {\n const anchor = view.landmarks.find((l) => l.id === pair.id);\n if (!anchor) continue;\n src.push({ x: anchor.x, y: anchor.y });\n dst.push(mirrorPt(pair.photo));\n }\n if (src.length >= 3) commitReg(solveAffine(src, dst));\n },\n [commitReg, view.landmarks, mirrorPt],\n );\n\n const toSvgPoint = useCallback(\n (clientX: number, clientY: number): Point => {\n const svg = svgRef.current;\n if (!svg) return { x: 0, y: 0 };\n const pt = svg.createSVGPoint();\n pt.x = clientX;\n pt.y = clientY;\n const ctm = svg.getScreenCTM();\n if (!ctm) return { x: 0, y: 0 };\n const local = pt.matrixTransform(ctm.inverse());\n return { x: local.x, y: local.y };\n },\n [],\n );\n\n // Zoom about the current window centre; base window read via ref so the\n // stable callbacks survive base changes (auto-frame, view, registration).\n const zoomAtCentre = (z: FaceZoomState, factor: number): FaceZoomState => {\n const base = parseViewBox(baseWindowRef.current);\n const cur = composeZoomWindow(base, z);\n return zoomWindowAround(\n base,\n z,\n { x: cur.x + cur.width / 2, y: cur.y + cur.height / 2 },\n factor,\n );\n };\n const zoomAtCentreRef = useRef(zoomAtCentre);\n zoomAtCentreRef.current = zoomAtCentre;\n const zoomBy = useCallback((factor: number) => {\n setZoomState((z) => zoomAtCentreRef.current(z, factor));\n }, []);\n const setZoomTo = useCallback((factor: number) => {\n setZoomState((z) =>\n zoomAtCentreRef.current(\n z,\n Number.isFinite(factor) && factor > 0 ? factor / z.k : 1,\n ),\n );\n }, []);\n const resetZoomFn = useCallback(() => setZoomState(FACE_ZOOM_RESET), []);\n const endPan = useCallback((e: ReactPointerEvent<SVGSVGElement>) => {\n if (!panRef.current || panRef.current.id !== e.pointerId) return;\n panRef.current = null;\n try {\n e.currentTarget.releasePointerCapture(e.pointerId);\n } catch {\n /* pointer already released */\n }\n }, []);\n\n const handlePointerDown = useCallback(\n (index: number) => (e: ReactPointerEvent<SVGCircleElement>) => {\n draggingRef.current = index;\n setFrozenFrame(frameNowRef.current);\n e.currentTarget.setPointerCapture(e.pointerId);\n },\n [],\n );\n const handlePointerMove = useCallback(\n (e: ReactPointerEvent<SVGCircleElement>) => {\n const index = draggingRef.current;\n if (index === null) return;\n const p = toSvgPoint(e.clientX, e.clientY);\n const next = targets.map((tg, i) => (i === index ? p : tg));\n setTargets(next);\n const src = view.landmarks.map((lm) => ({ x: lm.x, y: lm.y }));\n // `next` are rendered (possibly mirrored) positions — solve in\n // un-mirrored space so the mirror transform lands them back correctly.\n commitReg(solveAffine(src, next.map(mirrorPt)));\n },\n [targets, toSvgPoint, view.landmarks, commitReg, mirrorPt],\n );\n const handlePointerUp = useCallback(() => {\n draggingRef.current = null;\n setFrozenFrame(null);\n }, []);\n\n /* ---- Capture (on-device camera + file fallback) ---- */\n const [captureState, setCaptureState] = useState<FaceCaptureState>('idle');\n const [captureError, setCaptureError] = useState<FaceCaptureError | null>(\n null,\n );\n // Captured frames are keyed by view — each view keeps its own photo.\n const [capturedByView, setCapturedByView] = useState<\n Partial<Record<FaceViewId, string>>\n >({});\n // Per-view photo: explicit map wins, else `patientPhoto` is the front shorthand.\n const viewPhoto =\n viewPhotos?.[viewId] ?? (viewId === 'front' ? patientPhoto : undefined);\n // The captured frame supersedes the prop photo (uncontrolled-friendly).\n const effectiveSrc = capturedByView[viewId] ?? viewPhoto?.src;\n\n /* ---- Annotations (free-form drawing over the photo) ---- */\n const isAnnotationsControlled = annotations !== undefined;\n const [internalAnnotations, setInternalAnnotations] =\n useState<FaceAnnotations>(defaultAnnotations ?? {});\n const annMap = isAnnotationsControlled ? annotations : internalAnnotations;\n const annMapRef = useRef<FaceAnnotations>(annMap);\n annMapRef.current = annMap;\n const viewAnnotations = annMap[viewId] ?? EMPTY_ANNOTATIONS;\n\n const commitAnnotations = useCallback(\n (nextForView: FaceAnnotation[]) => {\n const next: FaceAnnotations = { ...annMapRef.current };\n if (nextForView.length > 0) next[viewIdRef.current] = nextForView;\n else delete next[viewIdRef.current];\n // Eager — same-tick sequential commits (e.g. two handle adds) compose\n // instead of clobbering; the render-time sync reasserts controlled state.\n annMapRef.current = next;\n if (!isAnnotationsControlled) setInternalAnnotations(next);\n onAnnotationsChange?.(next);\n },\n [isAnnotationsControlled, onAnnotationsChange],\n );\n\n // Monotonic id source for kit-generated annotation ids.\n const annIdRef = useRef(0);\n const nextAnnId = useCallback(\n () => `${instanceId}-a${(annIdRef.current += 1)}`,\n [instanceId],\n );\n\n /* ---- Selection (pointer select mode — no active tool) ---- */\n const [selectedAnnotationId, setSelectedAnnotationId] = useState<\n string | null\n >(null);\n const selectedAnnotationIdRef = useRef<string | null>(null);\n selectedAnnotationIdRef.current = selectedAnnotationId;\n const selectAnnotationFn = useCallback(\n (next: string | null) => {\n if (selectedAnnotationIdRef.current === next) return;\n selectedAnnotationIdRef.current = next;\n setSelectedAnnotationId(next);\n onAnnotationSelect?.(next);\n },\n [onAnnotationSelect],\n );\n\n // Photo space → mesh space is the render pipeline undone: un-mirror FIRST,\n // then the inverse affine. Asks the live zone paths in reverse document\n // order (SVG topmost-wins, matching click behaviour); jsdom lacks\n // isPointInFill, so the feature-detect degrades to null (unassigned).\n const hitTestZone = useCallback(\n (photoPoint: Point): string | null => {\n const svg = svgRef.current;\n if (!svg) return null;\n const meshPt = applyAffine(\n invertAffine(affineRef.current),\n mirrorPt(photoPoint),\n );\n const paths = svg.querySelectorAll<SVGGeometryElement>(\n '[data-zone] > path:first-of-type',\n );\n if (paths.length === 0 || typeof paths[0].isPointInFill !== 'function')\n return null;\n for (let i = paths.length - 1; i >= 0; i -= 1) {\n if (paths[i].isPointInFill({ x: meshPt.x, y: meshPt.y })) {\n const zoneEl = paths[i].closest<SVGGElement>('[data-zone]');\n return zoneEl?.getAttribute('data-zone') ?? null;\n }\n }\n return null;\n },\n [mirrorPt],\n );\n\n const addAnnotationFn = useCallback(\n (input: FaceAnnotationInput): string => {\n const newId = input.id ?? nextAnnId();\n const withId = { ...input, id: newId } as FaceAnnotation;\n // Auto-link to the zone under the anchor unless the caller already\n // assessed it (zoneId null / string). Sticky from here on.\n const ann: FaceAnnotation =\n withId.zoneId === undefined\n ? { ...withId, zoneId: hitTestZone(annotationAnchor(withId)) }\n : withId;\n const list = annMapRef.current[viewIdRef.current] ?? [];\n commitAnnotations([...list, ann]);\n // A fresh mark auto-selects so the panel's selection affordances\n // (delete / recolour / zone assignment) target it immediately.\n selectAnnotationFn(newId);\n return newId;\n },\n [commitAnnotations, nextAnnId, selectAnnotationFn, hitTestZone],\n );\n const removeAnnotationFn = useCallback(\n (annId: string) => {\n const list = annMapRef.current[viewIdRef.current] ?? [];\n if (list.some((a) => a.id === annId))\n commitAnnotations(list.filter((a) => a.id !== annId));\n },\n [commitAnnotations],\n );\n const setAnnotationZoneFn = useCallback(\n (annId: string, zoneId: string | null) => {\n const list = annMapRef.current[viewIdRef.current] ?? [];\n if (list.some((a) => a.id === annId))\n commitAnnotations(\n list.map((a) => (a.id === annId ? { ...a, zoneId } : a)),\n );\n },\n [commitAnnotations],\n );\n const undoAnnotationFn = useCallback(() => {\n const list = annMapRef.current[viewIdRef.current] ?? [];\n if (list.length > 0) commitAnnotations(list.slice(0, -1));\n }, [commitAnnotations]);\n const clearAnnotationsFn = useCallback(() => {\n if ((annMapRef.current[viewIdRef.current] ?? []).length > 0)\n commitAnnotations([]);\n }, [commitAnnotations]);\n\n /* ---- Active tool (controlled / uncontrolled) — inert unless interactive ---- */\n const isToolControlled = activeTool !== undefined;\n const [internalTool, setInternalTool] = useState<FaceAnnotationTool | null>(\n defaultTool,\n );\n const rawTool = isToolControlled ? activeTool : internalTool;\n const tool = interactive ? (rawTool ?? null) : null;\n const toolRef = useRef<FaceAnnotationTool | null>(tool);\n toolRef.current = tool;\n const setToolFn = useCallback(\n (next: FaceAnnotationTool | null) => {\n if (!isToolControlled) setInternalTool(next);\n onToolChange?.(next);\n },\n [isToolControlled, onToolChange],\n );\n\n /* ---- Current annotation style (built-in toolbar state) ---- */\n const [annShape, setAnnShape] = useState<MarkerShape>(\n defaultAnnotationShape,\n );\n const [annTone, setAnnTone] = useState<MarkerTone>(defaultAnnotationColor);\n const annShapeRef = useRef(annShape);\n annShapeRef.current = annShape;\n const annToneRef = useRef(annTone);\n annToneRef.current = annTone;\n\n /* ---- In-progress draft + text editing ---- */\n const [draft, setDraft] = useState<FaceAnnotation | null>(null);\n const draftRef = useRef<FaceAnnotation | null>(null);\n draftRef.current = draft;\n const drawingRef = useRef(false);\n const [editingTextId, setEditingTextId] = useState<string | null>(null);\n const editingTextIdRef = useRef<string | null>(null);\n editingTextIdRef.current = editingTextId;\n\n // The panel hosts the text-callout editor and the selection affordances —\n // auto-open it so an edit request never targets an unmounted field.\n useEffect(() => {\n if (editingTextId !== null) setPanelOpen(true);\n }, [editingTextId]);\n useEffect(() => {\n if (selectedAnnotationId !== null) setPanelOpen(true);\n }, [selectedAnnotationId]);\n // First zone joining the multi-selection opens the panel so the Zones\n // section (count + apply buttons) is visible when it becomes actionable.\n const prevZoneSelCount = useRef(zoneSelection.length);\n useEffect(() => {\n if (prevZoneSelCount.current === 0 && zoneSelection.length > 0)\n setPanelOpen(true);\n prevZoneSelCount.current = zoneSelection.length;\n }, [zoneSelection.length]);\n\n // Selection is pointer-mode-scoped: a tool or view CHANGE drops it (a\n // commit under the same tool keeps its auto-selection); a selected mark\n // that disappears (undo / clear / controlled prop) self-heals to null.\n const prevToolRef = useRef(tool);\n const prevViewRef = useRef(viewId);\n useEffect(() => {\n if (prevToolRef.current !== tool || prevViewRef.current !== viewId) {\n prevToolRef.current = tool;\n prevViewRef.current = viewId;\n selectAnnotationFn(null);\n }\n }, [tool, viewId, selectAnnotationFn]);\n useEffect(() => {\n const selId = selectedAnnotationIdRef.current;\n if (selId !== null && !viewAnnotations.some((a) => a.id === selId))\n selectAnnotationFn(null);\n }, [viewAnnotations, selectAnnotationFn]);\n\n // The draw surface is live when a tool is selected (interactive mode only).\n const drawingEnabled = tool !== null;\n\n const beginDraw = useCallback(\n (e: ReactPointerEvent<SVGRectElement>) => {\n const active = toolRef.current;\n if (!active) return;\n e.stopPropagation();\n const p = toSvgPoint(e.clientX, e.clientY);\n if (active === 'marker') {\n addAnnotationFn({\n kind: 'marker',\n x: p.x,\n y: p.y,\n shape: annShapeRef.current,\n tone: annToneRef.current,\n });\n return;\n }\n if (active === 'text') {\n const newId = addAnnotationFn({\n kind: 'text',\n x: p.x,\n y: p.y,\n text: '',\n tone: annToneRef.current,\n });\n setEditingTextId(newId);\n return;\n }\n e.currentTarget.setPointerCapture?.(e.pointerId);\n drawingRef.current = true;\n if (active === 'pen' || active === 'highlighter') {\n setDraft({\n id: DRAFT_ID,\n kind: active,\n points: [p],\n tone: annToneRef.current,\n });\n } else if (\n active === 'arrow' ||\n active === 'line' ||\n active === 'rect' ||\n active === 'ellipse'\n ) {\n setDraft({\n id: DRAFT_ID,\n kind: active,\n from: p,\n to: p,\n tone: annToneRef.current,\n });\n }\n },\n [toSvgPoint, addAnnotationFn],\n );\n\n const moveDraw = useCallback(\n (e: ReactPointerEvent<SVGRectElement>) => {\n if (!drawingRef.current) return;\n const p = toSvgPoint(e.clientX, e.clientY);\n setDraft((prev) => {\n if (!prev) return prev;\n if (prev.kind === 'pen' || prev.kind === 'highlighter')\n return { ...prev, points: [...prev.points, p] };\n if (\n prev.kind === 'arrow' ||\n prev.kind === 'line' ||\n prev.kind === 'rect' ||\n prev.kind === 'ellipse'\n )\n return { ...prev, to: p };\n return prev;\n });\n },\n [toSvgPoint],\n );\n\n const endDraw = useCallback(\n (e: ReactPointerEvent<SVGRectElement>) => {\n if (!drawingRef.current) return;\n drawingRef.current = false;\n e.currentTarget.releasePointerCapture?.(e.pointerId);\n const d = draftRef.current;\n setDraft(null);\n if (!d) return;\n // Discard a degenerate stroke / shape (a click that never moved).\n if (d.kind === 'pen' || d.kind === 'highlighter') {\n if (d.points.length < 2) return;\n } else if (\n d.kind === 'arrow' ||\n d.kind === 'line' ||\n d.kind === 'rect' ||\n d.kind === 'ellipse'\n ) {\n if (Math.hypot(d.to.x - d.from.x, d.to.y - d.from.y) < 4) return;\n }\n // Strip the draft id — addAnnotationFn assigns a real one.\n const { id: _draftId, ...rest } = d;\n void _draftId;\n addAnnotationFn(rest as FaceAnnotationInput);\n },\n [addAnnotationFn],\n );\n\n /* ---- Text-callout editing (panel field) ---- */\n const editingText = editingTextId\n ? viewAnnotations.find((a) => a.id === editingTextId && a.kind === 'text')\n : undefined;\n const updateEditingText = useCallback(\n (nextText: string) => {\n const id = editingTextIdRef.current;\n if (!id) return;\n const list = annMapRef.current[viewIdRef.current] ?? [];\n commitAnnotations(\n list.map((a) =>\n a.id === id && a.kind === 'text' ? { ...a, text: nextText } : a,\n ),\n );\n },\n [commitAnnotations],\n );\n const finishEditingText = useCallback(() => {\n const id = editingTextIdRef.current;\n setEditingTextId(null);\n if (!id) return;\n const list = annMapRef.current[viewIdRef.current] ?? [];\n const ann = list.find((a) => a.id === id);\n if (ann && ann.kind === 'text' && ann.text.trim() === '')\n commitAnnotations(list.filter((a) => a.id !== id));\n }, [commitAnnotations]);\n\n // Stream teardown — the single most important privacy path.\n const stopStream = useCallback(() => {\n streamRef.current?.getTracks().forEach((track) => track.stop());\n streamRef.current = null;\n const video = videoRef.current;\n if (video) video.srcObject = null;\n }, []);\n\n const cancelCapture = useCallback(() => {\n stopStream();\n setCaptureState('idle');\n }, [stopStream]);\n\n // Start the camera — user gesture only, never auto on mount.\n const startCapture = useCallback(async () => {\n if (!allowCapture) return;\n if (!mediaDevicesAvailable()) {\n setCaptureError('insecure-context');\n setCaptureState('error');\n return;\n }\n setCaptureError(null);\n setCaptureState('requesting');\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n video: { facingMode: captureFacingMode },\n audio: false,\n });\n // Guard an unmount between the permission prompt and resolution.\n if (unmountedRef.current) {\n stream.getTracks().forEach((track) => track.stop());\n return;\n }\n streamRef.current = stream;\n const video = videoRef.current;\n if (video) {\n try {\n video.srcObject = stream;\n } catch {\n /* some envs reject a non-native MediaStream on srcObject; the\n stream is still held + torn down correctly */\n }\n const playResult = video.play?.();\n if (playResult && typeof playResult.catch === 'function') {\n playResult.catch(() => {\n /* autoplay can reject silently; the Capture button still works */\n });\n }\n }\n setCaptureState('streaming');\n } catch (err: unknown) {\n stopStream();\n setCaptureError(classifyMediaError(err));\n setCaptureState('error');\n }\n }, [allowCapture, captureFacingMode, stopStream]);\n\n const commitCaptured = useCallback(\n (src: string, width: number, height: number) => {\n setCapturedByView((prev) => ({ ...prev, [viewId]: src }));\n onCapture?.({ src, width, height, view: viewId });\n },\n [onCapture, viewId],\n );\n\n // Freeze the current frame onto a canvas, release the camera, emit it.\n const capturePhoto = useCallback(() => {\n const video = videoRef.current;\n const vw = video?.videoWidth || video?.clientWidth || 0;\n const vh = video?.videoHeight || video?.clientHeight || 0;\n if (!video || video.readyState < 2 || vw === 0 || vh === 0) {\n setCaptureError('capture-failed');\n setCaptureState('error');\n return;\n }\n const canvas = document.createElement('canvas');\n canvas.width = vw;\n canvas.height = vh;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n setCaptureError('capture-failed');\n setCaptureState('error');\n return;\n }\n try {\n ctx.drawImage(video, 0, 0, vw, vh);\n } catch {\n setCaptureError('capture-failed');\n setCaptureState('error');\n return;\n }\n // Release the camera the instant the frame is frozen — LED goes dark.\n stopStream();\n commitCaptured(canvas.toDataURL('image/jpeg', 0.92), vw, vh);\n setCaptureState('idle');\n }, [stopStream, commitCaptured]);\n\n // File fallback (and the desktop path where no camera is wired up).\n const onPickFile = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (!file) return;\n const reader = new FileReader();\n reader.onload = () => {\n const src = typeof reader.result === 'string' ? reader.result : '';\n if (!src) return;\n const img = new Image();\n img.onload = () =>\n commitCaptured(src, img.naturalWidth, img.naturalHeight);\n img.onerror = () => commitCaptured(src, vbW, vbH);\n img.src = src;\n };\n reader.readAsDataURL(file);\n },\n [commitCaptured, vbW, vbH],\n );\n\n // Privacy: tear the camera down on unmount, whatever the phase.\n useEffect(() => {\n unmountedRef.current = false;\n return () => {\n unmountedRef.current = true;\n streamRef.current?.getTracks().forEach((track) => track.stop());\n streamRef.current = null;\n };\n }, []);\n\n const captureStreaming = captureState === 'streaming';\n\n // When the viewfinder tears down (capture / cancel), it unmounts the button\n // that held focus — re-home focus to the persistent Take/Retake button so a\n // keyboard user isn't dropped to <body>.\n const wasStreamingRef = useRef(false);\n useEffect(() => {\n if (wasStreamingRef.current && !captureStreaming) {\n captureButtonRef.current?.focus();\n }\n wasStreamingRef.current = captureStreaming;\n }, [captureStreaming]);\n\n /* ---- Detection ---- */\n const [detectStatus, setDetectStatus] = useState<FaceDetectStatus>('idle');\n const setStatus = useCallback(\n (s: FaceDetectStatus) => {\n setDetectStatus(s);\n onDetectStatus?.(s);\n },\n [onDetectStatus],\n );\n const runDetect = useCallback(async (): Promise<boolean> => {\n if (!autoDetect || !effectiveSrc || view.landmarks.length === 0)\n return false;\n const options = typeof autoDetect === 'object' ? autoDetect : {};\n const onStage = (stage: 'loading' | 'detecting') =>\n setStatus(stage === 'detecting' ? 'detecting' : 'loading');\n try {\n setStatus('loading');\n // FRONT: MediaPipe FaceMesh (accurate, non-collinear eyes/nose/chin).\n // PROFILE: MediaPipe collapses a 90° pose, so use YuNet and fit the mesh\n // on its visible-side EYE / NOSE-TIP / MOUTH triangle.\n let pairs: Array<{ id: string; photo: Point }> | null;\n if (view.id === 'front') {\n pairs = await detectFaceLandmarks(effectiveSrc, {\n viewWidth: vbW,\n viewHeight: vbH,\n onStage,\n wasmBaseUrl: options.wasmBaseUrl,\n modelAssetPath: options.modelAssetPath,\n });\n } else {\n const raw = await detectFaceYuNet(effectiveSrc, {\n viewWidth: vbW,\n viewHeight: vbH,\n onStage,\n ortModuleUrl: options.ortModuleUrl,\n ortWasmBaseUrl: options.ortWasmBaseUrl,\n modelUrl: options.yunetModelUrl,\n });\n pairs = raw && profileTriangleFromYuNet(raw);\n }\n if (!pairs || pairs.length < 3) {\n setStatus('no-face');\n return false;\n }\n fitFromPairs(pairs);\n setStatus('done');\n return true;\n } catch {\n setStatus('error');\n return false;\n }\n }, [\n autoDetect,\n effectiveSrc,\n view.id,\n view.landmarks,\n vbW,\n vbH,\n setStatus,\n fitFromPairs,\n ]);\n\n /* ---- Imperative handle + agent registration ---- */\n const focusZoneEl = useCallback((zoneId: string) => {\n rootRef.current\n ?.querySelector<SVGGElement>(`[data-zone=\"${zoneId}\"]`)\n ?.focus();\n }, []);\n\n const handle = useMemo<FaceSchemeHandle>(\n () => ({\n focusZone: focusZoneEl,\n getChart: () => chartRef.current,\n getZone: (zoneId) => chartRef.current[zoneId] ?? [],\n zonesWith: (type) =>\n Object.entries(chartRef.current)\n .filter(([, findings]) => findings.some((f) => f.type === type))\n .map(([zoneId]) => zoneId),\n setFinding: addFinding,\n removeFinding: removeFindingFn,\n clearZone: (zoneId) => {\n if (!chartRef.current[zoneId]) return;\n const copy = { ...chartRef.current };\n delete copy[zoneId];\n commitChart(copy);\n },\n getRegistration: () => affineRef.current,\n setRegistration: (m) => commitReg(m),\n resetRegistration: () => commitReg(IDENTITY_AFFINE),\n fitToLandmarks: fitFromPairs,\n detect: runDetect,\n startCapture: () => void startCapture(),\n cancelCapture,\n getView: () => viewIdRef.current,\n getZoom: () => zoomStateRef.current.k,\n setZoom: setZoomTo,\n resetZoom: resetZoomFn,\n setView,\n getAnnotations: () => annMapRef.current[viewIdRef.current] ?? [],\n addAnnotation: addAnnotationFn,\n removeAnnotation: removeAnnotationFn,\n undoAnnotation: undoAnnotationFn,\n clearAnnotations: clearAnnotationsFn,\n getTool: () => toolRef.current,\n setTool: setToolFn,\n getSelectedAnnotation: () => {\n const selId = selectedAnnotationIdRef.current;\n if (selId === null) return null;\n const a = (annMapRef.current[viewIdRef.current] ?? []).find(\n (x) => x.id === selId,\n );\n return a ? { id: a.id, kind: a.kind } : null;\n },\n selectAnnotation: (selId) => {\n if (selId === null) {\n selectAnnotationFn(null);\n return;\n }\n const list = annMapRef.current[viewIdRef.current] ?? [];\n if (list.some((x) => x.id === selId)) selectAnnotationFn(selId);\n },\n setAnnotationZone: setAnnotationZoneFn,\n getSelectedZones: () => zoneSelectionRef.current,\n setSelectedZones: (ids) => commitZoneSelection([...ids]),\n clearZoneSelection: clearZoneSelectionFn,\n applyFindingToSelection: (type, note) =>\n setFindingBulkFn(zoneSelectionRef.current, type, note),\n removeFindingFromSelection: (type) =>\n removeFindingBulkFn(zoneSelectionRef.current, type),\n setFindingBulk: setFindingBulkFn,\n }),\n [\n focusZoneEl,\n addFinding,\n removeFindingFn,\n commitChart,\n commitReg,\n fitFromPairs,\n runDetect,\n startCapture,\n cancelCapture,\n setView,\n addAnnotationFn,\n removeAnnotationFn,\n undoAnnotationFn,\n clearAnnotationsFn,\n setToolFn,\n selectAnnotationFn,\n setAnnotationZoneFn,\n commitZoneSelection,\n clearZoneSelectionFn,\n setFindingBulkFn,\n removeFindingBulkFn,\n setZoomTo,\n resetZoomFn,\n ],\n );\n useImperativeHandle(ref, () => handle, [handle]);\n useAgentRegistration(faceSchemeAgent, handle, instanceId);\n\n /* ---- Zone label ---- */\n const zoneLabel = useCallback(\n (zone: FaceZone): string => {\n const name = t(`faceScheme.zone.${zone.labelKey}`);\n const findings = chartRef.current[zone.id] ?? [];\n if (findings.length === 0) return name;\n const findingNames = findings\n .map((f) => t(`faceScheme.finding.${f.type}`))\n .join(', ');\n return t('faceScheme.zoneWithFindings', {\n zone: name,\n findings: findingNames,\n });\n },\n [t],\n );\n\n const handleActivate = useCallback(\n (zone: FaceZone) => {\n onSelectZone?.(zone.id);\n // Multi-select: activation toggles membership and never stamps —\n // `activeFinding` only pre-arms the panel's Zones section.\n if (zoneSelectMode) toggleZoneSelected(zone.id);\n else if (interactive && activeFinding)\n toggleFinding(zone.id, activeFinding);\n },\n [\n interactive,\n zoneSelectMode,\n toggleZoneSelected,\n activeFinding,\n toggleFinding,\n onSelectZone,\n ],\n );\n\n const photoAlt = viewPhoto?.altKey\n ? t(viewPhoto.altKey)\n : t('faceScheme.photo.defaultAlt');\n\n // Right profile = left mesh mirrored horizontally about the frame centre.\n const meshTransform = view.mirror\n ? `translate(${vbW} 0) scale(-1 1) ${affineToString(activeAffine)}`\n : affineToString(activeAffine);\n\n const updatePart = useCallback(\n (field: SliderField, val: number) => {\n commitReg(composeAffine({ ...parts, [field]: val }, view.pivot));\n },\n [commitReg, parts, view.pivot],\n );\n\n // Auto-detect runs wherever the active view has fit landmarks (all three\n // views do — the front uses eye/nose/chin, the profiles use midline\n // cephalometric points the detector tracks even on a 90° profile).\n const detectEnabled =\n Boolean(autoDetect) && Boolean(effectiveSrc) && view.landmarks.length > 0;\n // Capture is its own opt-in — available regardless of `mode` so the\n // practitioner can (re)take the photo on any surface that allows it.\n const captureEnabled = allowCapture;\n\n /* ---- Render ---- */\n const hasViewSwitcher = showViewSwitcher && FACE_VIEW_IDS.length > 1;\n // The edit panel (Draw section + Fit overlay section, one Card) sits beside\n // the figure on wide viewports in the single-view layout, and stacks\n // underneath in the three-up layout (where the figures already fill the\n // row). The joined control bar (view buttons + capture + the panel toggle)\n // rides above the figure and never counts toward the side panel.\n const annotationToolbarEnabled = interactive && showAnnotationToolbar;\n const effectiveZoomable = interactive && zoomable;\n const panelAvailable =\n zoneSelectMode ||\n annotationToolbarEnabled ||\n adjusting ||\n effectiveZoomable;\n const hasSidePanel = panelOpen && panelAvailable;\n // Three-up (all views at once) is only reachable when the switcher is on.\n const isThreeUp = layout === 'all' && hasViewSwitcher;\n\n // User zoom resets on view switch, on toggling the capability, and when\n // the camera viewfinder takes over the figure.\n useEffect(() => {\n setZoomState(FACE_ZOOM_RESET);\n }, [viewId, effectiveZoomable]);\n useEffect(() => {\n if (captureStreaming) setZoomState(FACE_ZOOM_RESET);\n }, [captureStreaming]);\n\n // Wheel zoom — non-passive so preventDefault stops page scroll; anchored\n // on the pointer. Re-attached after layout/view remounts of the svg node.\n useEffect(() => {\n const svg = svgRef.current;\n if (!svg || !effectiveZoomable) return;\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n const p = toSvgPoint(e.clientX, e.clientY);\n setZoomState((z) =>\n zoomWindowAround(\n parseViewBox(baseWindowRef.current),\n z,\n p,\n e.deltaY < 0 ? 1.15 : 1 / 1.15,\n ),\n );\n };\n svg.addEventListener('wheel', onWheel, { passive: false });\n return () => svg.removeEventListener('wheel', onWheel);\n }, [effectiveZoomable, toSvgPoint, isThreeUp, viewId, captureStreaming]);\n // The panel sits beside the figure only in the single-view layout; in\n // three-up it always drops underneath the (full-width) figure row.\n const sideBeside = hasSidePanel && !isThreeUp;\n // Single-view + panel: keep the figure and the panel as a tight, centred\n // pair (the figure column is sized to the photo, not stretched flex-1, so\n // the panel sits immediately beside the photo rather than floating off at\n // the far right). `items-stretch` makes the panel match the figure's height.\n const containerClass = sideBeside\n ? 'ds:flex ds:flex-col ds:gap-[var(--spacing-md)] ds:lg:flex-row ds:lg:items-stretch ds:lg:justify-center'\n : 'ds:flex ds:flex-col ds:gap-[var(--spacing-md)]';\n const figureColClass = sideBeside\n ? 'ds:flex ds:w-full ds:min-w-0 ds:flex-col ds:gap-[var(--spacing-sm)] ds:lg:w-[28rem] ds:lg:shrink-0'\n : 'ds:flex ds:w-full ds:min-w-0 ds:flex-col ds:gap-[var(--spacing-sm)]';\n const sidePanelClass = sideBeside\n ? 'ds:flex ds:w-full ds:flex-col ds:gap-[var(--spacing-md)] ds:lg:w-[28rem] ds:lg:shrink-0 ds:lg:self-stretch'\n : 'ds:flex ds:w-full ds:flex-col ds:gap-[var(--spacing-md)]';\n // Twin-card geometry: beside the figure the panel matches its height —\n // `h-0 min-h-full` stops panel content growing the row; the body scrolls.\n const panelCardClass = sideBeside\n ? 'ds:lg:h-0 ds:lg:min-h-full'\n : undefined;\n const panelBodyClass = sideBeside\n ? 'ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:lg:min-h-0 ds:lg:flex-1 ds:lg:overflow-y-auto'\n : 'ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]';\n\n // The control bar renders when it has any content: the view buttons (when\n // the switcher is on), the capture buttons (when opted in), or the panel\n // toggle (whenever the edit panel has at least one section to show).\n const showViewButtons = hasViewSwitcher;\n const barHasContent = showViewButtons || captureEnabled || panelAvailable;\n\n // Disclosure toggle for the edit panel — rides in the control bar (outside\n // the Card it shows/hides). Keyed so it can sit in the bar's flat child\n // array beside the view / capture buttons.\n const panelToggle = panelAvailable ? (\n <IconButton\n key=\"panel\"\n size=\"sm\"\n icon={<PencilRuler aria-hidden=\"true\" />}\n aria-label={t('faceScheme.panel.toggle')}\n aria-expanded={panelOpen}\n aria-controls={panelOpen ? panelId : undefined}\n data-overflow-pin\n onClick={() => setPanelOpen((open) => !open)}\n />\n ) : null;\n\n // Draw section of the edit panel — tool select (incl. a leading\n // \"select\"/no-tool), colour, marker shape (marker tool only), the\n // text-callout editor, and undo / clear. Each picker group carries a small\n // visible label (aria-labelledby, not aria-label) and hugs its content\n // (self-start) instead of stretching to the card width.\n const toolbarValue: ToolbarValue = tool ?? 'select';\n const drawLabelId = `${reactId}-draw`;\n const fitLabelId = `${reactId}-fit`;\n const zoomLabelId = `${reactId}-zoom`;\n const toolLabelId = `${reactId}-tools`;\n const toneLabelId = `${reactId}-tones`;\n const shapeLabelId = `${reactId}-shapes`;\n const zoneRowLabelId = `${reactId}-ann-zone`;\n const selectedAnnotation =\n selectedAnnotationId !== null\n ? viewAnnotations.find((a) => a.id === selectedAnnotationId)\n : undefined;\n const zoneOptions: ComboboxOption[] = view.zones.map((z) => ({\n value: z.id,\n label: t(`faceScheme.zone.${z.labelKey}`),\n }));\n const panelLabelClass =\n 'ds:text-[length:var(--font-size-xs)] ds:font-medium ds:text-[var(--muted-foreground)]';\n const zonesLabelId = `${reactId}-zones`;\n const zonesApplyLabelId = `${reactId}-zones-apply`;\n // Zones section of the edit panel — the multi-select flow: a live count of\n // the selected zones, one batched toggle per finding type (not-all-have →\n // add to every selected zone; all-have → remove from all), an optional\n // shared note for the newly-added findings, and clear-selection.\n const zonesSection = zoneSelectMode ? (\n <div\n data-testid=\"face-scheme-zones\"\n role=\"group\"\n aria-labelledby={zonesLabelId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <span id={zonesLabelId} className={panelLabelClass}>\n {t('faceScheme.zonesPanel.label')}\n </span>\n <p className=\"ds:m-0 ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)]\">\n {t('faceScheme.zonesPanel.hint')}\n </p>\n <span\n aria-live=\"polite\"\n className=\"ds:text-[length:var(--font-size-xs)] ds:text-[var(--foreground)]\"\n >\n {t('faceScheme.zonesPanel.selectedTotal', {\n n: zoneSelection.length,\n })}\n </span>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span id={zonesApplyLabelId} className={panelLabelClass}>\n {t('faceScheme.zonesPanel.applyLabel')}\n </span>\n <div\n role=\"group\"\n aria-labelledby={zonesApplyLabelId}\n className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-xs)]\"\n >\n {FACE_FINDING_TYPES.map((type) => {\n const m = FACE_FINDING_MARKER[type];\n const allHave =\n zoneSelection.length > 0 &&\n zoneSelection.every((zid) =>\n (chart[zid] ?? []).some((f) => f.type === type),\n );\n return (\n <Button\n key={type}\n size=\"sm\"\n intent=\"outline\"\n aria-pressed={allHave}\n disabled={zoneSelection.length === 0}\n startIcon={\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d={markerPath(m.shape, 12, 12, 9)}\n className={markerToneFill[m.tone]}\n />\n </svg>\n }\n onClick={() => {\n if (allHave) {\n removeFindingBulkFn(zoneSelectionRef.current, type);\n } else {\n const note = bulkNote.trim();\n setFindingBulkFn(\n zoneSelectionRef.current,\n type,\n note === '' ? undefined : note,\n );\n setBulkNote('');\n }\n }}\n >\n {t(`faceScheme.finding.${type}`)}\n </Button>\n );\n })}\n </div>\n </div>\n <TextInput\n aria-label={t('faceScheme.zonesPanel.noteLabel')}\n placeholder={t('faceScheme.zonesPanel.notePlaceholder')}\n value={bulkNote}\n onChange={(e) => setBulkNote(e.target.value)}\n />\n <Button\n size=\"sm\"\n intent=\"outline\"\n className=\"ds:self-start\"\n onClick={clearZoneSelectionFn}\n disabled={zoneSelection.length === 0}\n >\n {t('faceScheme.zonesPanel.clearSelection')}\n </Button>\n </div>\n ) : null;\n const drawSection = annotationToolbarEnabled ? (\n <div\n data-testid=\"face-scheme-toolbar\"\n role=\"group\"\n aria-labelledby={drawLabelId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <span id={drawLabelId} className={panelLabelClass}>\n {t('faceScheme.panel.draw')}\n </span>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span id={toolLabelId} className={panelLabelClass}>\n {t('faceScheme.annotate.toolLabel')}\n </span>\n <IconButtonGroup\n role=\"radiogroup\"\n mode=\"toggle-single\"\n size=\"sm\"\n aria-labelledby={toolLabelId}\n className=\"ds:self-start\"\n value={toolbarValue}\n onValueChange={(v) =>\n setToolFn(v === 'select' ? null : (v as FaceAnnotationTool))\n }\n >\n {(['select', ...FACE_ANNOTATION_TOOLS] as ToolbarValue[]).map(\n (tv) => {\n const Icon = TOOL_ICON[tv];\n return (\n <IconButton\n key={tv}\n value={tv}\n icon={<Icon aria-hidden=\"true\" />}\n aria-label={t(`faceScheme.annotate.tool.${tv}`)}\n />\n );\n },\n )}\n </IconButtonGroup>\n </div>\n\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span id={toneLabelId} className={panelLabelClass}>\n {t('faceScheme.annotate.colorLabel')}\n </span>\n <IconButtonGroup\n role=\"radiogroup\"\n mode=\"toggle-single\"\n size=\"sm\"\n aria-labelledby={toneLabelId}\n className=\"ds:self-start\"\n value={annTone}\n onValueChange={(v) => {\n const nextTone = v as MarkerTone;\n setAnnTone(nextTone);\n // The picker doubles as the selected mark's tone editor.\n const selId = selectedAnnotationIdRef.current;\n if (selId !== null) {\n const list = annMapRef.current[viewIdRef.current] ?? [];\n if (list.some((x) => x.id === selId))\n commitAnnotations(\n list.map((x) =>\n x.id === selId ? { ...x, tone: nextTone } : x,\n ),\n );\n }\n }}\n >\n {ANNOTATION_TONES.map((toneOpt) => (\n <IconButton\n key={toneOpt}\n value={toneOpt}\n icon={\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <circle\n cx={8}\n cy={8}\n r={6}\n className={markerToneFill[toneOpt]}\n />\n </svg>\n }\n aria-label={t(`faceScheme.annotate.tone.${toneOpt}`)}\n />\n ))}\n </IconButtonGroup>\n </div>\n\n {tool === 'marker' && (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span id={shapeLabelId} className={panelLabelClass}>\n {t('faceScheme.annotate.shapeLabel')}\n </span>\n <IconButtonGroup\n role=\"radiogroup\"\n mode=\"toggle-single\"\n size=\"sm\"\n aria-labelledby={shapeLabelId}\n className=\"ds:self-start\"\n value={annShape}\n onValueChange={(v) => setAnnShape(v as MarkerShape)}\n >\n {MARKER_SHAPES.map((shapeOpt) => (\n <IconButton\n key={shapeOpt}\n value={shapeOpt}\n icon={\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d={markerPath(shapeOpt, 12, 12, 9)}\n className=\"ds:[fill:currentColor]\"\n />\n </svg>\n }\n aria-label={t(`annotationMarker.shape.${shapeOpt}`)}\n />\n ))}\n </IconButtonGroup>\n </div>\n )}\n\n {editingText && editingText.kind === 'text' && (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <TextInput\n aria-label={t('faceScheme.annotate.textLabel')}\n placeholder={t('faceScheme.annotate.textPlaceholder')}\n value={editingText.text}\n // eslint-disable-next-line jsx-a11y/no-autofocus -- focuses the text-callout editor so the note can be typed immediately after the marker is placed\n autoFocus\n onChange={(e) => updateEditingText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === 'Escape') {\n e.preventDefault();\n finishEditingText();\n }\n }}\n />\n <Button size=\"sm\" intent=\"primary\" onClick={finishEditingText}>\n {t('faceScheme.annotate.textDone')}\n </Button>\n </div>\n )}\n\n {selectedAnnotation && (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span id={zoneRowLabelId} className={panelLabelClass}>\n {t('faceScheme.annotate.zoneLabel')}\n </span>\n <span\n aria-live=\"polite\"\n className=\"ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)] ds:empty:hidden\"\n >\n {selectedAnnotation.zoneId === null\n ? t('faceScheme.annotate.outsideZonesHint')\n : null}\n </span>\n <Combobox\n size=\"sm\"\n options={zoneOptions}\n value={selectedAnnotation.zoneId ?? ''}\n clearable\n placeholder={\n selectedAnnotation.zoneId == null\n ? t('faceScheme.annotate.zoneNone')\n : t('faceScheme.annotate.zonePlaceholder')\n }\n aria-label={t('faceScheme.annotate.zoneLabel')}\n onValueChange={(v) =>\n setAnnotationZoneFn(selectedAnnotation.id, v === '' ? null : v)\n }\n />\n </div>\n )}\n\n <div className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-xs)]\">\n <Button\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Eraser aria-hidden=\"true\" />}\n onClick={() => {\n const selId = selectedAnnotationIdRef.current;\n if (selId !== null) removeAnnotationFn(selId);\n }}\n disabled={selectedAnnotationId === null}\n >\n {t('faceScheme.annotate.deleteSelected')}\n </Button>\n <Button\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Undo2 aria-hidden=\"true\" />}\n onClick={undoAnnotationFn}\n disabled={viewAnnotations.length === 0}\n >\n {t('faceScheme.annotate.undo')}\n </Button>\n <Button\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Trash2 aria-hidden=\"true\" />}\n onClick={clearAnnotationsFn}\n disabled={viewAnnotations.length === 0}\n >\n {t('faceScheme.annotate.clear')}\n </Button>\n </div>\n </div>\n ) : null;\n\n // Accessible name for a committed annotation (text folds in its content;\n // a linked zone folds in its name).\n const annotationLabel = (a: FaceAnnotation): string => {\n const base =\n a.kind === 'text'\n ? a.text.trim()\n ? t('faceScheme.annotate.labelText', { text: a.text })\n : t('faceScheme.annotate.kind.text')\n : t(`faceScheme.annotate.kind.${a.kind}`);\n if (!a.zoneId) return base;\n const zone = view.zones.find((z) => z.id === a.zoneId);\n if (!zone) return base;\n return t('faceScheme.annotate.labelWithZone', {\n label: base,\n zone: t(`faceScheme.zone.${zone.labelKey}`),\n });\n };\n\n // The SVG visual for one annotation (committed or draft). Colour rides a\n // token class; all other stroke props are SVG presentation attributes (not\n // inline styles) in the photo's own viewBox units.\n const renderAnnotationVisual = (a: FaceAnnotation) => {\n const tone: MarkerTone = a.tone ?? 'accent';\n switch (a.kind) {\n case 'marker':\n return (\n <path\n d={markerPath(a.shape, a.x, a.y, ANN_MARKER_R)}\n className={markerToneFill[tone]}\n pointerEvents=\"none\"\n />\n );\n case 'pen':\n case 'highlighter':\n return (\n <path\n d={inkPath(a.points)}\n fill=\"none\"\n strokeWidth={\n a.kind === 'highlighter' ? ANN_HIGHLIGHTER_WIDTH : ANN_PEN_WIDTH\n }\n strokeOpacity={a.kind === 'highlighter' ? 0.35 : 1}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={annotationToneStroke[tone]}\n pointerEvents=\"none\"\n />\n );\n case 'arrow':\n return (\n <g className={annotationToneStroke[tone]} pointerEvents=\"none\">\n <path\n d={shapePath('arrow', a.from, a.to)}\n fill=\"none\"\n strokeWidth={ANN_SHAPE_WIDTH}\n strokeLinecap=\"round\"\n />\n <path\n d={arrowHeadPath(a.from, a.to, ANN_ARROW_HEAD)}\n fill=\"none\"\n strokeWidth={ANN_SHAPE_WIDTH}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n );\n case 'line':\n case 'rect':\n case 'ellipse':\n return (\n <path\n d={shapePath(a.kind, a.from, a.to)}\n fill=\"none\"\n strokeWidth={ANN_SHAPE_WIDTH}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={annotationToneStroke[tone]}\n pointerEvents=\"none\"\n />\n );\n case 'text':\n if (!a.text.trim())\n // Empty (being placed) — a small crosshair placeholder.\n return (\n <path\n d={`M ${a.x - 10} ${a.y} H ${a.x + 10} M ${a.x} ${a.y - 10} V ${a.y + 10}`}\n strokeWidth={ANN_SHAPE_WIDTH}\n strokeLinecap=\"round\"\n className={annotationToneStroke[tone]}\n pointerEvents=\"none\"\n />\n );\n return (\n <text\n x={a.x}\n y={a.y}\n fontSize={ANN_TEXT_SIZE}\n paintOrder=\"stroke\"\n strokeWidth={6}\n strokeLinejoin=\"round\"\n className={`${markerToneFill[tone]} ds:[stroke:var(--background)] ds:[font-family:var(--font-sans)] ds:[font-weight:500]`}\n pointerEvents=\"none\"\n >\n {a.text}\n </text>\n );\n }\n };\n\n // Transparent pointer hit target — an SVG <g> is only hit through its\n // children and every visual child is pointer-events:none, so each committed\n // mark gets a fat invisible stroke clone (stroke kinds — hollow interiors\n // stay click-through) or a fill target (marker / text). jsdom cannot\n // hit-test SVG; tests assert this contract structurally.\n const renderAnnotationHit = (a: FaceAnnotation) => {\n const hit = annotationHitGeometry(a, ANN_TEXT_SIZE);\n switch (hit.type) {\n case 'stroke':\n return (\n <path\n data-annotation-hit=\"\"\n d={hit.d}\n fill=\"none\"\n stroke=\"transparent\"\n strokeWidth={ANN_HIT_STROKE}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n pointerEvents=\"stroke\"\n className=\"ds:cursor-pointer\"\n />\n );\n case 'circle':\n return (\n <circle\n data-annotation-hit=\"\"\n cx={hit.cx}\n cy={hit.cy}\n r={hit.r}\n fill=\"transparent\"\n pointerEvents=\"fill\"\n className=\"ds:cursor-pointer\"\n />\n );\n case 'rect':\n return (\n <rect\n data-annotation-hit=\"\"\n x={hit.x}\n y={hit.y}\n width={hit.width}\n height={hit.height}\n fill=\"transparent\"\n pointerEvents=\"fill\"\n className=\"ds:cursor-pointer\"\n />\n );\n }\n };\n\n // Auto-framed window for the focused three-up photo tile: mesh-normalised\n // so all three heads read at matching size in equal cards. A handle drag\n // renders the frozen window captured at drag start instead.\n const focusedFrame =\n isThreeUp && effectiveSrc\n ? autoFrameViewBox(\n view.meshContentBox,\n activeAffine,\n { width: vbW, height: vbH },\n { mirror: view.mirror },\n )\n : null;\n frameNowRef.current = focusedFrame;\n\n // Base window for the focused figure (photo frame / schematic crop / full\n // canvas), with the user zoom window composed over it when zoomed in.\n const baseWindow = effectiveSrc\n ? (frozenFrame ?? focusedFrame ?? view.viewBox)\n : isThreeUp || !adjusting\n ? view.schematicViewBox\n : view.viewBox;\n baseWindowRef.current = baseWindow;\n const zoomedIn = effectiveZoomable && zoomState.k > 1;\n const zoomedWindow = zoomedIn\n ? boxToViewBox(composeZoomWindow(parseViewBox(baseWindow), zoomState))\n : baseWindow;\n const panEligible = zoomedIn && tool === null;\n\n // The registered SVG figure, parameterised by view. The focused view\n // (`vid === viewId`) renders the full interactive figure (handles + draw\n // surface + draft + pointer handlers, driven by the active-view state); any\n // other view — only shown in the three-up layout — renders a read-only,\n // clickable preview that focuses the view when activated (no handles, draw\n // surface, or draft; its SVG is aria-hidden behind the labelled button).\n const renderFigure = (vid: FaceViewId) => {\n if (vid !== viewId) {\n const v = FACE_VIEWS[vid];\n const previewPhoto =\n viewPhotos?.[vid] ?? (vid === 'front' ? patientPhoto : undefined);\n const previewSrc = capturedByView[vid] ?? previewPhoto?.src;\n const previewAffine = regMap[vid] ?? IDENTITY_AFFINE;\n const previewMesh = v.mirror\n ? `translate(${vbW} 0) scale(-1 1) ${affineToString(previewAffine)}`\n : affineToString(previewAffine);\n const previewAnnotations = annMap[vid] ?? EMPTY_ANNOTATIONS;\n return (\n <Card variant=\"elevated\" interactive asChild>\n <button\n type=\"button\"\n data-testid=\"face-scheme-preview\"\n data-view-preview={vid}\n aria-label={t(`faceScheme.view.${v.labelKey}`)}\n onClick={() => setView(vid)}\n className=\"ds:mx-auto ds:block ds:w-full ds:min-w-0 ds:max-w-[28rem] ds:appearance-none ds:p-0 ds:transition-opacity ds:[transition-duration:var(--animation-duration)] ds:hover:opacity-90\"\n >\n <svg\n viewBox={\n previewSrc\n ? autoFrameViewBox(\n v.meshContentBox,\n previewAffine,\n { width: vbW, height: vbH },\n { mirror: v.mirror },\n )\n : v.schematicViewBox\n }\n aria-hidden=\"true\"\n className=\"ds:block ds:h-auto ds:w-full\"\n >\n {previewSrc && (\n <image\n href={previewSrc}\n x={0}\n y={0}\n width={vbW}\n height={vbH}\n preserveAspectRatio=\"xMidYMid slice\"\n />\n )}\n {/* Registered mesh — read-only zones (no interaction/tooltip). */}\n <g transform={previewMesh}>\n {v.zones.map((zone) => {\n const findings = chart[zone.id] ?? [];\n const marked = findings.length > 0;\n return (\n <g key={zone.id}>\n <path\n d={zone.d}\n className={zoneVariants({\n interactive: false,\n marked,\n // Cross-view selection stays visible on the\n // three-up previews (decorative, aria-hidden svg).\n selected:\n zoneSelectMode && zoneSelectionSet.has(zone.id),\n })}\n />\n {findings.map((f, i) => {\n const m = FACE_FINDING_MARKER[f.type];\n const offset = (i - (findings.length - 1) / 2) * 26;\n return (\n <path\n key={f.type}\n d={markerPath(\n m.shape,\n zone.cx + offset,\n zone.cy,\n 11,\n )}\n className={markerToneFill[m.tone]}\n />\n );\n })}\n </g>\n );\n })}\n </g>\n {/* Committed annotations — visual only (no focus targets). */}\n <g>\n {previewAnnotations.map((a) => (\n <g key={a.id}>{renderAnnotationVisual(a)}</g>\n ))}\n </g>\n </svg>\n </button>\n </Card>\n );\n }\n return (\n <RadixTooltip.Provider delayDuration={200}>\n <Card\n variant=\"elevated\"\n data-testid=\"face-scheme-figure\"\n data-focused={isThreeUp ? 'true' : undefined}\n className={\n isThreeUp\n ? // Accent border marks the active tile in the three-up row\n // (2px width doubles as the non-colour cue; ~3.2:1 ≥ 3:1).\n 'ds:mx-auto ds:w-full ds:max-w-[28rem] ds:border-2 ds:border-[color:var(--accent)] ds:forced-colors:border-[Highlight]'\n : 'ds:mx-auto ds:w-full ds:max-w-[28rem]'\n }\n >\n <svg\n ref={svgRef}\n data-testid=\"face-scheme-svg\"\n viewBox={zoomedWindow}\n role=\"group\"\n aria-label={t(`faceScheme.view.${view.labelKey}`)}\n className={\n panEligible\n ? 'ds:block ds:h-auto ds:w-full ds:touch-none ds:cursor-grab'\n : 'ds:block ds:h-auto ds:w-full ds:touch-none'\n }\n onPointerDown={\n interactive\n ? (e: ReactPointerEvent<SVGSVGElement>) => {\n const el = e.target as Element;\n // Pointer-down anywhere off a mark clears the selection.\n if (\n selectedAnnotationIdRef.current !== null &&\n !el.closest?.('[data-annotation]')\n )\n selectAnnotationFn(null);\n // Pan from empty space while zoomed in with no tool\n // active; interactive children keep their clicks.\n if (\n panEligible &&\n !el.closest?.(\n '[data-zone],[data-annotation],[data-annotation-hit],[data-testid=\"face-scheme-handles\"]',\n )\n ) {\n panRef.current = {\n id: e.pointerId,\n x: e.clientX,\n y: e.clientY,\n };\n try {\n e.currentTarget.setPointerCapture(e.pointerId);\n } catch {\n /* capture is an enhancement — pan works without it */\n }\n }\n }\n : undefined\n }\n onPointerMove={\n effectiveZoomable\n ? (e: ReactPointerEvent<SVGSVGElement>) => {\n const pan = panRef.current;\n if (!pan || pan.id !== e.pointerId) return;\n const rect = e.currentTarget.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return;\n const base = parseViewBox(baseWindowRef.current);\n const cur = composeZoomWindow(base, zoomStateRef.current);\n const dx = ((e.clientX - pan.x) * cur.width) / rect.width;\n const dy =\n ((e.clientY - pan.y) * cur.height) / rect.height;\n panRef.current = {\n id: pan.id,\n x: e.clientX,\n y: e.clientY,\n };\n setZoomState((z) => panZoomWindow(base, z, dx, dy));\n }\n : undefined\n }\n onPointerUp={effectiveZoomable ? endPan : undefined}\n onPointerCancel={effectiveZoomable ? endPan : undefined}\n onKeyDown={\n zoneSelectMode\n ? (e: KeyboardEvent<SVGSVGElement>) => {\n // A mark's own Escape stops propagation, so reaching\n // here means only the zone selection is left to clear.\n if (e.key === 'Escape') clearZoneSelectionFn();\n }\n : undefined\n }\n >\n {effectiveSrc && (\n <image\n href={effectiveSrc}\n x={0}\n y={0}\n width={vbW}\n height={vbH}\n preserveAspectRatio=\"xMidYMid slice\"\n role=\"img\"\n aria-label={photoAlt}\n />\n )}\n\n {/* Registered mesh — the affine maps the canonical zones onto the photo. */}\n <g transform={meshTransform}>\n {view.zones.map((zone) => {\n const findings = chart[zone.id] ?? [];\n const marked = findings.length > 0;\n const zoneSelected =\n zoneSelectMode && zoneSelectionSet.has(zone.id);\n return (\n <RadixTooltip.Root key={zone.id}>\n <RadixTooltip.Trigger asChild>\n <g\n data-zone={zone.id}\n data-side={zone.side}\n data-zone-selected={zoneSelected ? 'true' : undefined}\n role={interactive || onSelectZone ? 'button' : 'img'}\n aria-label={zoneLabel(zone)}\n // One meaning per mode: multi-select → pressed =\n // selected; stamp mode → pressed = carries the armed\n // finding.\n aria-pressed={\n zoneSelectMode\n ? zoneSelected\n : interactive && activeFinding\n ? marked\n : undefined\n }\n // Suppress the UA focus box on the <g>; draw the ring on the\n // zone path itself. forced-colors re-asserts a system stroke.\n className=\"ds:outline-none ds:[&:focus-visible>*:first-child]:[stroke:var(--ring)] ds:[&:focus-visible>*:first-child]:[stroke-width:var(--focus-ring-width)] ds:[&:focus-visible>*:first-child]:[stroke-opacity:1] ds:forced-colors:[&:focus-visible>*:first-child]:[stroke:CanvasText]\"\n tabIndex={interactive || onSelectZone ? 0 : -1}\n onClick={() => handleActivate(zone)}\n onKeyDown={(e: KeyboardEvent<SVGGElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleActivate(zone);\n } else if (e.key === 'Escape' && zoneSelectMode) {\n clearZoneSelectionFn();\n }\n }}\n >\n <path\n d={zone.d}\n className={zoneVariants({\n interactive,\n marked,\n selected: zoneSelected,\n })}\n />\n {findings.map((f, i) => {\n const m = FACE_FINDING_MARKER[f.type];\n const offset = (i - (findings.length - 1) / 2) * 26;\n return (\n <path\n key={f.type}\n d={markerPath(\n m.shape,\n zone.cx + offset,\n zone.cy,\n 11,\n )}\n aria-hidden=\"true\"\n className={markerToneFill[m.tone]}\n />\n );\n })}\n </g>\n </RadixTooltip.Trigger>\n <RadixTooltip.Portal>\n <RadixTooltip.Content\n sideOffset={4}\n className=\"ds:z-50 ds:rounded-[var(--radius-sm)] ds:bg-[var(--popover)] ds:px-2 ds:py-1 ds:text-[length:var(--font-size-xs)] ds:text-[var(--popover-foreground)] ds:shadow-[var(--shadow-md)]\"\n >\n {zoneLabel(zone)}\n <RadixTooltip.Arrow className=\"ds:[fill:var(--popover)]\" />\n </RadixTooltip.Content>\n </RadixTooltip.Portal>\n </RadixTooltip.Root>\n );\n })}\n </g>\n\n {/* Free-form annotation layer — in the photo's own viewBox space,\n OUTSIDE the mesh transform, so marks stay pinned to the photo when\n the zone overlay is re-fitted. */}\n <g data-testid=\"face-scheme-annotations\">\n {viewAnnotations.map((a) => {\n const bbox = annotationBBox(a);\n const selected = selectedAnnotationId === a.id;\n return (\n <g\n key={a.id}\n data-annotation={a.id}\n data-annotation-kind={a.kind}\n data-annotation-zone={a.zoneId ?? undefined}\n data-selected={selected ? 'true' : undefined}\n role={interactive ? 'button' : 'img'}\n aria-label={annotationLabel(a)}\n aria-pressed={interactive ? selected : undefined}\n tabIndex={interactive ? 0 : -1}\n className=\"ds:outline-none ds:[&:focus-visible>*:first-child]:[stroke-opacity:1] ds:[&[data-selected=true]>*:first-child]:[stroke-opacity:1] ds:[&[data-selected=true]>*:first-child]:[stroke-dasharray:6_4] ds:forced-colors:[&:focus-visible>*:first-child]:[stroke:CanvasText] ds:forced-colors:[&[data-selected=true]>*:first-child]:[stroke:CanvasText]\"\n onClick={\n interactive && tool === null\n ? (e: ReactMouseEvent<SVGGElement>) => {\n e.currentTarget.focus();\n if (selectedAnnotationIdRef.current === a.id) {\n // Second activation: text opens its editor,\n // anything else toggles the selection off.\n if (a.kind === 'text') setEditingTextId(a.id);\n else selectAnnotationFn(null);\n } else {\n selectAnnotationFn(a.id);\n }\n }\n : undefined\n }\n onKeyDown={(e: KeyboardEvent<SVGGElement>) => {\n if (!interactive) return;\n if (e.key === 'Delete' || e.key === 'Backspace') {\n e.preventDefault();\n removeAnnotationFn(a.id);\n } else if (e.key === 'Escape') {\n // Wins the first Escape; with nothing selected it\n // bubbles on to the svg's zone-selection clearing.\n if (selectedAnnotationIdRef.current !== null) {\n e.stopPropagation();\n selectAnnotationFn(null);\n }\n } else if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n if (a.kind === 'text') setEditingTextId(a.id);\n else if (selectedAnnotationIdRef.current === a.id)\n selectAnnotationFn(null);\n else selectAnnotationFn(a.id);\n }\n }}\n >\n {/* ring (first child) — solid on :focus-visible, dashed when selected */}\n <rect\n x={bbox.x - ANN_FOCUS_PAD}\n y={bbox.y - ANN_FOCUS_PAD}\n width={bbox.width + ANN_FOCUS_PAD * 2}\n height={bbox.height + ANN_FOCUS_PAD * 2}\n rx={8}\n fill=\"none\"\n pointerEvents=\"none\"\n className=\"ds:[stroke:var(--ring)] ds:[stroke-width:var(--focus-ring-width)] ds:[stroke-opacity:0] ds:[vector-effect:non-scaling-stroke]\"\n />\n {renderAnnotationVisual(a)}\n {interactive && tool === null && renderAnnotationHit(a)}\n </g>\n );\n })}\n {draft && (\n <g aria-hidden=\"true\" data-testid=\"face-scheme-draft\">\n {renderAnnotationVisual(draft)}\n </g>\n )}\n </g>\n\n {/* Pointer draw surface — a transparent full-viewBox capture rect, on\n top so it intercepts drawing; pointer-events off (falls through to\n the zones / annotations below) when no tool is selected. Keyboard\n users annotate via the zone flow, so this is aria-hidden (a\n pointer-only enhancement). */}\n <rect\n data-testid=\"face-scheme-draw-surface\"\n x={0}\n y={0}\n width={vbW}\n height={vbH}\n fill=\"transparent\"\n aria-hidden=\"true\"\n className={\n drawingEnabled\n ? 'ds:cursor-crosshair ds:touch-none'\n : 'ds:[pointer-events:none]'\n }\n onPointerDown={drawingEnabled ? beginDraw : undefined}\n onPointerMove={drawingEnabled ? moveDraw : undefined}\n onPointerUp={drawingEnabled ? endDraw : undefined}\n onPointerCancel={drawingEnabled ? endDraw : undefined}\n />\n\n {/* Landmark handles — pointer-only fitting affordance (the numeric\n sliders below are the accessible, keyboard-operable equivalent).\n Hidden while a draw tool is active (fitting + drawing are\n mutually exclusive pointer modes). */}\n {adjusting && effectiveSrc && tool === null && (\n <g aria-hidden=\"true\" data-testid=\"face-scheme-handles\">\n {view.landmarks.map((lm, i) => {\n const tg =\n targets[i] ?? mirrorPt(applyAffine(activeAffine, lm));\n return (\n <g key={lm.id}>\n <circle\n cx={tg.x}\n cy={tg.y}\n r={13}\n data-handle={lm.id}\n onPointerDown={handlePointerDown(i)}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n className=\"ds:[fill:var(--background)] ds:[fill-opacity:0.9] ds:[stroke:var(--accent)] ds:[stroke-width:2.5] ds:[vector-effect:non-scaling-stroke] ds:cursor-grab ds:touch-none\"\n />\n <path\n d={`M ${tg.x - 5} ${tg.y} H ${tg.x + 5} M ${tg.x} ${tg.y - 5} V ${tg.y + 5}`}\n className=\"ds:[stroke:var(--accent)] ds:[stroke-width:2] ds:[vector-effect:non-scaling-stroke]\"\n pointerEvents=\"none\"\n />\n </g>\n );\n })}\n </g>\n )}\n </svg>\n </Card>\n </RadixTooltip.Provider>\n );\n };\n\n // Flat child list for the joined control bar — view buttons, then the\n // capture pair, then the fit-settings gear. Built as an array (not inline\n // conditionals) so the ButtonGroup's roving tabindex never lands on a\n // skipped/null child (the first real button always owns tabIndex 0).\n const barChildren: ReactElement[] = [];\n if (showViewButtons) {\n for (const vid of VIEW_RENDER_ORDER) {\n const selected = layout === 'single' && viewId === vid;\n barChildren.push(\n <Button\n key={vid}\n size=\"sm\"\n intent={selected ? 'primary' : undefined}\n aria-pressed={selected}\n startIcon={VIEW_ICON[vid]}\n onClick={() => {\n setView(vid);\n setLayout('single');\n }}\n >\n {t(`faceScheme.viewShort.${FACE_VIEWS[vid].labelKey}`)}\n </Button>,\n );\n }\n barChildren.push(\n <Button\n key=\"all\"\n size=\"sm\"\n intent={layout === 'all' ? 'primary' : undefined}\n aria-pressed={layout === 'all'}\n startIcon={<Columns3 aria-hidden=\"true\" />}\n onClick={() => setLayout('all')}\n >\n {t('faceScheme.viewShort.all')}\n </Button>,\n );\n }\n if (captureEnabled) {\n barChildren.push(\n <Button\n key=\"capture\"\n ref={captureButtonRef}\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Camera aria-hidden=\"true\" />}\n data-overflow-pin\n onClick={() => void startCapture()}\n disabled={captureState === 'requesting'}\n >\n {t(\n effectiveSrc\n ? 'faceScheme.capture.retake'\n : 'faceScheme.capture.take',\n )}\n </Button>,\n );\n barChildren.push(\n <Button\n key=\"upload\"\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Upload aria-hidden=\"true\" />}\n onClick={() => fileInputRef.current?.click()}\n >\n {t('faceScheme.capture.upload')}\n </Button>,\n );\n }\n if (panelToggle) barChildren.push(panelToggle);\n\n return (\n <div\n ref={rootRef}\n data-component=\"face-scheme\"\n data-component-id={instanceId}\n data-view={viewId}\n data-layout={isThreeUp ? 'all' : 'single'}\n className={[containerClass, className].filter(Boolean).join(' ')}\n role=\"group\"\n aria-label={ariaLabel ?? t('faceScheme.ariaLabel')}\n >\n {/* Figure column — control bar, figure(s) (or the live viewfinder\n while streaming), and the finding legend. */}\n <div className={figureColClass}>\n {/* Joined control bar — view buttons + capture + the fit-settings\n gear, as a WAI-ARIA toolbar. Hidden while the viewfinder streams. */}\n {!captureStreaming && barHasContent && (\n <ButtonGroup\n toolbar\n label={t('faceScheme.viewSwitcherLabel')}\n overflow=\"menu\"\n collapseToIcons\n className=\"ds:text-center\"\n >\n {barChildren}\n </ButtonGroup>\n )}\n\n {/* Hidden file input (upload fallback) + the capture error live\n region — mounted whenever capture is enabled so the polite region\n exists before its first message. */}\n {captureEnabled && (\n <div className=\"ds:mx-auto ds:flex ds:w-full ds:max-w-[28rem] ds:flex-col\">\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n capture={captureFacingMode}\n onChange={onPickFile}\n className=\"ds:sr-only\"\n aria-hidden=\"true\"\n tabIndex={-1}\n data-testid=\"face-scheme-file-input\"\n />\n <span\n role=\"status\"\n aria-live=\"polite\"\n className={\n captureState === 'requesting'\n ? 'ds:text-start ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)] ds:empty:hidden'\n : 'ds:text-start ds:text-[length:var(--font-size-xs)] ds:text-[var(--destructive)] ds:empty:hidden'\n }\n >\n {captureState === 'requesting'\n ? t(\n 'faceScheme.capture.requesting',\n 'Waiting for camera permission…',\n )\n : captureState === 'error' && captureError\n ? t(CAPTURE_ERROR_KEY[captureError])\n : ''}\n </span>\n </div>\n )}\n\n {/* Live camera viewfinder — replaces the figure while streaming. */}\n {captureStreaming && (\n <div\n data-testid=\"face-scheme-viewfinder\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n {/* eslint-disable-next-line jsx-a11y/media-has-caption -- live self-view, not media content */}\n <video\n ref={videoRef}\n autoPlay\n playsInline\n muted\n aria-label={t('faceScheme.capture.viewfinder')}\n className=\"ds:mx-auto ds:block ds:w-full ds:max-w-[28rem] ds:[border-radius:var(--radius-md)] ds:[transform:scaleX(-1)]\"\n />\n <div className=\"ds:flex ds:flex-wrap ds:justify-center ds:gap-[var(--spacing-xs)]\">\n <Button\n size=\"sm\"\n intent=\"primary\"\n onClick={() => capturePhoto()}\n >\n {t('faceScheme.capture.capture')}\n </Button>\n <Button size=\"sm\" intent=\"outline\" onClick={cancelCapture}>\n {t('faceScheme.capture.cancel')}\n </Button>\n </div>\n </div>\n )}\n\n {/* Figure(s) — the focused interactive figure, or (in three-up) all\n three views with the focused one interactive and the rest as\n read-only, clickable previews. */}\n {!captureStreaming &&\n (isThreeUp ? (\n // Equal columns in every case: the three cards stay the same\n // size, and the photoless schematic crops give the maps\n // matching aspects within them.\n <div className=\"ds:grid ds:grid-cols-1 ds:items-center ds:gap-[var(--spacing-md)] ds:md:grid-cols-3\">\n {VIEW_RENDER_ORDER.map((vid) => (\n <div key={vid} className=\"ds:min-w-0\">\n {renderFigure(vid)}\n </div>\n ))}\n </div>\n ) : (\n renderFigure(viewId)\n ))}\n\n {/* Finding legend — its own card below the figure(s), gated by the\n Show-legend toggle at the edit panel's root. */}\n {legend && showLegend && (\n <Card variant=\"elevated\" data-testid=\"face-scheme-legend\">\n <Card.Body>\n <ul\n aria-label={t('faceScheme.legendLabel')}\n className=\"ds:m-0 ds:flex ds:flex-wrap ds:gap-x-4 ds:gap-y-1 ds:p-0 ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)]\"\n >\n {FACE_FINDING_TYPES.map((type) => {\n const m = FACE_FINDING_MARKER[type];\n return (\n <li\n key={type}\n className=\"ds:flex ds:list-none ds:items-center\"\n >\n <AnnotationMarker\n shape={m.shape}\n tone={m.tone}\n size=\"sm\"\n label={t(`faceScheme.finding.${type}`)}\n />\n </li>\n );\n })}\n </ul>\n </Card.Body>\n </Card>\n )}\n </div>\n\n {hasSidePanel && (\n <div className={sidePanelClass}>\n {/* Edit panel — ONE card, fixed section order everywhere:\n Zones (multi-select) → Draw (annotation palette) → Fit overlay\n (numeric fit sliders), plus the Show-legend switch at root. */}\n <Card\n variant=\"elevated\"\n data-testid=\"face-scheme-panel\"\n id={panelId}\n className={panelCardClass}\n >\n <Card.Body className={panelBodyClass}>\n {zonesSection}\n {zoneSelectMode && (annotationToolbarEnabled || adjusting) && (\n <Separator />\n )}\n {drawSection}\n {annotationToolbarEnabled && adjusting && <Separator />}\n {adjusting && (\n <div\n data-testid=\"face-scheme-registration\"\n role=\"group\"\n aria-labelledby={fitLabelId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <span id={fitLabelId} className={panelLabelClass}>\n {t('faceScheme.panel.fit')}\n </span>\n <p className=\"ds:m-0 ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)]\">\n {t('faceScheme.registration.hint')}\n </p>\n <div className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-xs)] ds:sm:grid-cols-2\">\n {SLIDER_FIELDS.map((field) => {\n const range = SLIDER_RANGES[field];\n const isScale =\n field === 'scaleX' || field === 'scaleY';\n return (\n <div\n key={field}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:text-[length:var(--font-size-xs)] ds:text-[var(--foreground)]\"\n >\n <span>{t(`faceScheme.registration.${field}`)}</span>\n <Slider\n aria-label={t(`faceScheme.registration.${field}`)}\n value={[parts[field]]}\n min={range.min}\n max={range.max}\n step={range.step}\n formatValue={(v) =>\n isScale\n ? `${Math.round(v * 100)}%`\n : field === 'rotation' || field === 'shear'\n ? `${v.toFixed(1)}°`\n : `${Math.round(v)}`\n }\n onValueChange={(vals) => {\n const v = vals[0];\n if (typeof v === 'number') updatePart(field, v);\n }}\n />\n </div>\n );\n })}\n </div>\n <div className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-xs)]\">\n {detectEnabled && (\n <Button\n size=\"sm\"\n intent=\"primary\"\n onClick={() => void runDetect()}\n disabled={\n detectStatus === 'loading' ||\n detectStatus === 'detecting'\n }\n >\n {t('faceScheme.registration.autoDetect')}\n </Button>\n )}\n <Button\n size=\"sm\"\n intent=\"outline\"\n onClick={() => commitReg(IDENTITY_AFFINE)}\n >\n {t('faceScheme.registration.reset')}\n </Button>\n {/* Always mounted so a polite region exists before its first\n message — some SRs miss a live region created in the same\n mutation as its initial text. */}\n {detectEnabled && (\n <span\n role=\"status\"\n aria-live=\"polite\"\n className=\"ds:self-center ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)]\"\n >\n {detectStatus === 'idle'\n ? ''\n : t(`faceScheme.detect.${detectStatus}`)}\n </span>\n )}\n </div>\n </div>\n )}\n {/* Zoom row — wheel/drag work on the figure; these are the\n keyboard-operable equivalents plus the live level readout. */}\n {effectiveZoomable && (\n <>\n {(zoneSelectMode ||\n annotationToolbarEnabled ||\n adjusting) && <Separator />}\n <div\n data-testid=\"face-scheme-zoom\"\n role=\"group\"\n aria-labelledby={zoomLabelId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <span id={zoomLabelId} className={panelLabelClass}>\n {t('faceScheme.zoomLabel')}\n </span>\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n <IconButton\n size=\"sm\"\n icon={<ZoomOut aria-hidden=\"true\" />}\n aria-label={t('faceScheme.zoomOut')}\n disabled={zoomState.k <= 1}\n onClick={() => zoomBy(1 / 1.3)}\n />\n <span\n role=\"status\"\n aria-live=\"polite\"\n aria-label={t('faceScheme.zoomLevel')}\n className=\"ds:min-w-[3.5rem] ds:text-center ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)]\"\n >\n {Math.round(zoomState.k * 100)}%\n </span>\n <IconButton\n size=\"sm\"\n icon={<ZoomIn aria-hidden=\"true\" />}\n aria-label={t('faceScheme.zoomIn')}\n disabled={zoomState.k >= FACE_ZOOM_MAX}\n onClick={() => zoomBy(1.3)}\n />\n <Button\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Maximize2 aria-hidden=\"true\" />}\n disabled={zoomState.k <= 1}\n onClick={resetZoomFn}\n >\n {t('faceScheme.resetView')}\n </Button>\n </div>\n </div>\n </>\n )}\n {/* Show-legend toggle — panel root, reachable whenever the\n legend is configured (independent of adjust mode). */}\n {legend && (\n <>\n <Separator />\n <Switch\n size=\"sm\"\n label={t('faceScheme.showLegend')}\n checked={showLegend}\n onCheckedChange={setShowLegend}\n />\n </>\n )}\n </Card.Body>\n </Card>\n </div>\n )}\n </div>\n );\n },\n);\n\nFaceScheme.displayName = 'FaceScheme';\n"],"names":["__iconNode","Columns3","createLucideIcon","MousePointer2","Pen","PencilRuler","Undo2","UserRoundArrowLeft","UserRound","TOOL_SCHEMA","ZONE_SCHEMA","VIEW_SCHEMA","FINDING_SCHEMA","faceSchemeAgent","handle","zone","findings","f","acc","a","key","args","DEFAULT_VISION_MODULE","DEFAULT_WASM_BASE","DEFAULT_MODEL","ANCHOR_INDICES","landmarkerCache","getLandmarker","visionModuleUrl","wasmBaseUrl","modelAssetPath","onStage","cached","promise","mod","fileset","loadImage","src","img","detectFaceLandmarks","options","viewWidth","viewHeight","image","landmarker","face","imgW","imgH","scale","offsetX","offsetY","toView","lm","pairs","id","indices","sx","sy","count","idx","v","DEFAULT_ORT_MODULE","DEFAULT_ORT_WASM_BASE","NET_SIZE","STRIDES","KEYPOINT_IDS","sessionCache","getSession","ortModuleUrl","ortWasmBaseUrl","modelUrl","ort","model","session","defaultModelUrl","preprocess","Tensor","w","h","dw","dh","padX","padY","canvas","ctx","data","n","i","sigmoid","x","decode","out","scoreThreshold","needSigmoid","probe","best","s","cls","obj","kps","cols","rows","cv","ov","score","c","r","keypoints","j","detectFaceYuNet","tensor","result","coverScale","kx","ky","px","py","FRONT_VIEWBOX","FRONT_PIVOT","FRONT_CONTOUR","FRONT_ZONES","FRONT_LANDMARKS","PROFILE_ZONE_PATHS","PROFILE_CONTOUR","z","PROFILE_ZONES","PROFILE_LANDMARKS","FACE_VIEWS","FACE_VIEW_IDS","FACE_FINDING_TYPES","FACE_FINDING_MARKER","FACE_ANNOTATION_TOOLS","ANNOTATION_TOOL_KIND","isShapeTool","tool","isInkTool","isPointTool","inkPath","points","first","d","p","shapePath","kind","from","to","y","cx","cy","rx","ry","arrowHeadPath","size","dx","dy","len","ux","uy","ang","cos","sin","b1x","b1y","b2x","b2y","annotationBBox","minX","minY","maxX","maxY","annotationAnchor","ANN_HIT_STROKE","ANN_HIT_RADIUS","annotationHitGeometry","textSize","width","IDENTITY_AFFINE","affineToString","m","applyAffine","invertAffine","det","ia","ib","ic","AUTO_FRAME_FRACTION","autoFrameViewBox","meshBox","affine","opts","full","fraction","corners","mirroredMin","bw","bh","aspect","FACE_ZOOM_MIN","FACE_ZOOM_MAX","FACE_ZOOM_RESET","clamp01","parseViewBox","vb","height","boxToViewBox","b","composeZoomWindow","base","zoomWindowAround","factor","k","cur","u","rangeX","rangeY","panZoomWindow","DEG","composeAffine","parts","pivot","rad","ca","sa","e","decomposeAffine","scaleX","rotation","scaleY","shear","translateX","translateY","solveAffine","dst","Sxx","Sxy","Sx","Syy","Sy","bx0","bx1","bx2","by0","by1","by2","t","i00","i01","i02","i11","i12","i22","solve","r0","r1","r2","profileTriangleFromYuNet","photoOf","_a","nose","rightEye","leftEye","rightMouth","leftMouth","farther","mediaDevicesAvailable","classifyMediaError","err","name","CAPTURE_ERROR_KEY","markerToneFill","annotationToneStroke","ANN_MARKER_R","ANN_PEN_WIDTH","ANN_HIGHLIGHTER_WIDTH","ANN_SHAPE_WIDTH","ANN_ARROW_HEAD","ANN_TEXT_SIZE","ANN_FOCUS_PAD","EMPTY_ANNOTATIONS","DRAFT_ID","VIEW_RENDER_ORDER","VIEW_ICON","jsx","TOOL_ICON","MapPin","Highlighter","ArrowUpRight","Minus","SquareIcon","CircleIcon","TypeIcon","ANNOTATION_TONES","zoneVariants","cva","SLIDER_RANGES","SLIDER_FIELDS","FaceScheme","forwardRef","patientPhoto","viewPhotos","viewProp","defaultView","onViewChange","showViewSwitcher","defaultLayout","mode","value","defaultValue","onChange","onSelectZone","activeFinding","zoneSelect","selectedZonesProp","defaultSelectedZones","onSelectedZonesChange","annotations","defaultAnnotations","onAnnotationsChange","onAnnotationSelect","showAnnotationToolbar","zoomable","defaultPanelOpen","activeTool","defaultTool","onToolChange","defaultAnnotationShape","defaultAnnotationColor","registration","defaultRegistration","onRegistrationChange","registrationMode","autoDetect","onDetectStatus","allowCapture","captureFacingMode","onCapture","legend","ariaLabel","className","ref","useTranslation","reactId","useId","instanceId","rootRef","useRef","svgRef","videoRef","streamRef","fileInputRef","captureButtonRef","unmountedRef","isViewControlled","internalView","setInternalView","useState","viewId","viewIdRef","setView","useCallback","next","panelOpen","setPanelOpen","panelId","layout","setLayout","showLegend","setShowLegend","view","vbW","vbH","interactive","adjusting","isControlled","internal","setInternal","chart","chartRef","commitChart","addFinding","zoneId","type","note","current","removeFindingFn","copy","toggleFinding","zoneSelectMode","isZoneSelControlled","internalZoneSel","setInternalZoneSel","zoneSelection","zoneSelectionRef","zoneSelectionSet","useMemo","commitZoneSelection","ids","toggleZoneSelected","clearZoneSelectionFn","bulkNote","setBulkNote","setFindingBulkFn","changed","removeFindingBulkFn","rest","isRegControlled","internalReg","setInternalReg","regMap","activeAffine","affineRef","affineRefMap","commitReg","mirrorPt","targets","setTargets","draggingRef","frozenFrame","setFrozenFrame","frameNowRef","zoomState","setZoomState","zoomStateRef","baseWindowRef","panRef","useEffect","fitFromPairs","pair","anchor","l","toSvgPoint","clientX","clientY","svg","pt","ctm","local","zoomAtCentre","zoomAtCentreRef","zoomBy","setZoomTo","resetZoomFn","endPan","handlePointerDown","index","handlePointerMove","tg","handlePointerUp","captureState","setCaptureState","captureError","setCaptureError","capturedByView","setCapturedByView","viewPhoto","effectiveSrc","isAnnotationsControlled","internalAnnotations","setInternalAnnotations","annMap","annMapRef","viewAnnotations","commitAnnotations","nextForView","annIdRef","nextAnnId","selectedAnnotationId","setSelectedAnnotationId","selectedAnnotationIdRef","selectAnnotationFn","hitTestZone","photoPoint","meshPt","paths","zoneEl","addAnnotationFn","input","newId","withId","ann","list","removeAnnotationFn","annId","setAnnotationZoneFn","undoAnnotationFn","clearAnnotationsFn","isToolControlled","internalTool","setInternalTool","toolRef","setToolFn","annShape","setAnnShape","annTone","setAnnTone","annShapeRef","annToneRef","draft","setDraft","draftRef","drawingRef","editingTextId","setEditingTextId","editingTextIdRef","prevZoneSelCount","prevToolRef","prevViewRef","selId","drawingEnabled","beginDraw","active","_b","moveDraw","prev","endDraw","_draftId","editingText","updateEditingText","nextText","finishEditingText","stopStream","track","video","cancelCapture","startCapture","stream","playResult","commitCaptured","capturePhoto","vw","vh","onPickFile","file","reader","captureStreaming","wasStreamingRef","detectStatus","setDetectStatus","setStatus","runDetect","stage","raw","focusZoneEl","useImperativeHandle","useAgentRegistration","zoneLabel","findingNames","handleActivate","photoAlt","meshTransform","updatePart","field","val","detectEnabled","captureEnabled","hasViewSwitcher","annotationToolbarEnabled","effectiveZoomable","panelAvailable","hasSidePanel","isThreeUp","onWheel","sideBeside","containerClass","figureColClass","sidePanelClass","panelCardClass","panelBodyClass","showViewButtons","barHasContent","panelToggle","IconButton","open","toolbarValue","drawLabelId","fitLabelId","zoomLabelId","toolLabelId","toneLabelId","shapeLabelId","zoneRowLabelId","selectedAnnotation","zoneOptions","panelLabelClass","zonesLabelId","zonesApplyLabelId","zonesSection","jsxs","allHave","zid","Button","markerPath","TextInput","drawSection","IconButtonGroup","tv","Icon","nextTone","toneOpt","MARKER_SHAPES","shapeOpt","Combobox","Eraser","Trash2","annotationLabel","renderAnnotationVisual","tone","renderAnnotationHit","hit","focusedFrame","baseWindow","zoomedIn","zoomedWindow","panEligible","renderFigure","vid","previewPhoto","previewSrc","previewAffine","previewMesh","previewAnnotations","Card","marked","offset","RadixTooltip","el","pan","rect","zoneSelected","bbox","selected","barChildren","Camera","Upload","ButtonGroup","AnnotationMarker","Separator","range","isScale","Slider","vals","Fragment","ZoomOut","ZoomIn","Maximize2","Switch"],"mappings":"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","x_google_ignoreList":[0,1,2,3,4,5,6]}
1
+ {"version":3,"file":"face-scheme-DA2vjqaM.js","sources":["../../node_modules/lucide-react/dist/esm/icons/columns-3.mjs","../../node_modules/lucide-react/dist/esm/icons/mouse-pointer-2.mjs","../../node_modules/lucide-react/dist/esm/icons/pen.mjs","../../node_modules/lucide-react/dist/esm/icons/pencil-ruler.mjs","../../node_modules/lucide-react/dist/esm/icons/undo-2.mjs","../../node_modules/lucide-react/dist/esm/icons/user-round-arrow-left.mjs","../../node_modules/lucide-react/dist/esm/icons/user-round.mjs","../../src/components/face-scheme/face-scheme.agent.ts","../../src/components/face-scheme/detect-face-landmarks.ts","../../src/components/face-scheme/detect-face-yunet.ts","../../src/components/face-scheme/face-scheme-zones.ts","../../src/components/face-scheme/face-scheme-data.ts","../../src/components/face-scheme/face-scheme.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"3\", rx: \"2\", key: \"afitv7\" }],\n [\"path\", { d: \"M9 3v18\", key: \"fh3hqa\" }],\n [\"path\", { d: \"M15 3v18\", key: \"14nvp0\" }]\n];\nconst Columns3 = createLucideIcon(\"columns-3\", __iconNode);\n\nexport { __iconNode, Columns3 as default };\n//# sourceMappingURL=columns-3.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M4.037 4.688a.495.495 0 0 1 .651-.651l16 6.5a.5.5 0 0 1-.063.947l-6.124 1.58a2 2 0 0 0-1.438 1.435l-1.579 6.126a.5.5 0 0 1-.947.063z\",\n key: \"edeuup\"\n }\n ]\n];\nconst MousePointer2 = createLucideIcon(\"mouse-pointer-2\", __iconNode);\n\nexport { __iconNode, MousePointer2 as default };\n//# sourceMappingURL=mouse-pointer-2.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\",\n key: \"1a8usu\"\n }\n ]\n];\nconst Pen = createLucideIcon(\"pen\", __iconNode);\n\nexport { __iconNode, Pen as default };\n//# sourceMappingURL=pen.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n { d: \"M13 7 8.7 2.7a2.41 2.41 0 0 0-3.4 0L2.7 5.3a2.41 2.41 0 0 0 0 3.4L7 13\", key: \"orapub\" }\n ],\n [\"path\", { d: \"m8 6 2-2\", key: \"115y1s\" }],\n [\"path\", { d: \"m18 16 2-2\", key: \"ee94s4\" }],\n [\n \"path\",\n {\n d: \"m17 11 4.3 4.3c.94.94.94 2.46 0 3.4l-2.6 2.6c-.94.94-2.46.94-3.4 0L11 17\",\n key: \"cfq27r\"\n }\n ],\n [\n \"path\",\n {\n d: \"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\",\n key: \"1a8usu\"\n }\n ],\n [\"path\", { d: \"m15 5 4 4\", key: \"1mk7zo\" }]\n];\nconst PencilRuler = createLucideIcon(\"pencil-ruler\", __iconNode);\n\nexport { __iconNode, PencilRuler as default };\n//# sourceMappingURL=pencil-ruler.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M9 14 4 9l5-5\", key: \"102s5s\" }],\n [\"path\", { d: \"M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11\", key: \"f3b9sd\" }]\n];\nconst Undo2 = createLucideIcon(\"undo-2\", __iconNode);\n\nexport { __iconNode, Undo2 as default };\n//# sourceMappingURL=undo-2.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"m19 16-3 3\", key: \"lp3y45\" }],\n [\"path\", { d: \"M2 21a8 8 0 0 1 12.664-6.5\", key: \"1ap0vn\" }],\n [\"path\", { d: \"M22 19h-6l3 3\", key: \"13fjle\" }],\n [\"circle\", { cx: \"10\", cy: \"8\", r: \"5\", key: \"o932ke\" }]\n];\nconst UserRoundArrowLeft = createLucideIcon(\"user-round-arrow-left\", __iconNode);\n\nexport { __iconNode, UserRoundArrowLeft as default };\n//# sourceMappingURL=user-round-arrow-left.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"8\", r: \"5\", key: \"1hypcn\" }],\n [\"path\", { d: \"M20 21a8 8 0 0 0-16 0\", key: \"rfgkzh\" }]\n];\nconst UserRound = createLucideIcon(\"user-round\", __iconNode);\n\nexport { __iconNode, UserRound as default };\n//# sourceMappingURL=user-round.mjs.map\n","import type { AgentAdapter } from '../../agent/types';\nimport type { FaceSchemeHandle } from './face-scheme';\nimport type {\n FaceAnnotationTool,\n FaceFindingType,\n FaceViewId,\n} from './face-scheme-data';\n\nconst TOOL_SCHEMA = {\n type: 'string',\n enum: [\n 'none',\n 'marker',\n 'pen',\n 'highlighter',\n 'arrow',\n 'line',\n 'rect',\n 'ellipse',\n 'text',\n ],\n description:\n \"Drawing tool: 'none' (off), 'marker', 'pen', 'highlighter', 'arrow', 'line', 'rect', 'ellipse', or 'text'.\",\n} as const;\n\nconst ZONE_SCHEMA = {\n type: 'string',\n description:\n \"Face-zone id (e.g. 'glabella', 'nasolabialFold', 'forehead', 'mandibularAngleLeft' on the front view; 'cheekbone', 'masseter', 'chin' on a profile view).\",\n} as const;\n\nconst VIEW_SCHEMA = {\n type: 'string',\n enum: ['front', 'profile-left', 'profile-right'],\n description: \"Active view id: 'front', 'profile-left', or 'profile-right'.\",\n} as const;\n\nconst FINDING_SCHEMA = {\n enum: ['observation', 'treatment', 'concern', 'note'],\n} as const;\n\nexport const faceSchemeAgent: AgentAdapter<FaceSchemeHandle> = {\n id: 'face-scheme',\n // pick — focus a zone (transient); set_value / edit_inline — record / clear\n // findings on a zone; view_change — switch the active view (front / left /\n // right profile), since each view renders a different zone set. Registration\n // (the photo fit) is exposed only as the auto-align action.\n capabilities: ['pick', 'set_value', 'edit_inline', 'view_change'],\n state: {\n activeView: {\n // Which view is mounted — it determines which zones are in the DOM, so an\n // agent must read this before focus_zone on a profile-only zone.\n type: 'string',\n descriptionKey: 'ui.agent.faceScheme.state.activeView',\n description:\n 'Id of the currently displayed view (front / profile-left / profile-right).',\n read: (handle) => handle.getView(),\n },\n zoom: {\n type: 'number',\n descriptionKey: 'ui.agent.faceScheme.state.zoom',\n description:\n 'Current figure zoom factor (1 = the base framing; up to 8). Only meaningful when the surface enables `zoomable`.',\n read: (handle) => handle.getZoom(),\n },\n chart: {\n // A9: identifiers + finding ENUMS only — never the free-text finding\n // `note` (PHI) and never the patient-photo `src`. Notes are written but\n // never read back through the snapshot.\n type: 'Record<string, string[]>',\n descriptionKey: 'ui.agent.faceScheme.state.chart',\n description:\n 'Current face chart — the finding types recorded on each zone, keyed by zone id. Free-text notes and the patient photo are not exposed here.',\n read: (handle) =>\n Object.fromEntries(\n Object.entries(handle.getChart()).map(([zone, findings]) => [\n zone,\n findings.map((f) => f.type),\n ]),\n ),\n },\n markedZones: {\n type: 'string[]',\n descriptionKey: 'ui.agent.faceScheme.state.markedZones',\n description: 'Zone ids carrying at least one finding.',\n read: (handle) => Object.keys(handle.getChart()),\n },\n activeTool: {\n type: 'string | null',\n descriptionKey: 'ui.agent.faceScheme.state.activeTool',\n description:\n 'The active free-form drawing tool (marker / pen / highlighter / arrow / line / rect / ellipse / text), or null when none is selected.',\n read: (handle) => handle.getTool(),\n },\n annotationCounts: {\n // PHI-safe: counts by kind only — never the coordinates, and never the\n // free-text of a `text` callout.\n type: 'Record<string, number>',\n descriptionKey: 'ui.agent.faceScheme.state.annotationCounts',\n description:\n 'Count of free-form annotations on the active view, keyed by kind (marker / pen / highlighter / arrow / line / rect / ellipse / text). Never includes coordinates or the free-text of a text callout.',\n read: (handle) =>\n handle.getAnnotations().reduce<Record<string, number>>((acc, a) => {\n acc[a.kind] = (acc[a.kind] ?? 0) + 1;\n return acc;\n }, {}),\n },\n selectedAnnotation: {\n // PHI-safe: id + kind only — never the coordinates, and never the\n // free-text of a `text` callout.\n type: '{ id: string; kind: string } | null',\n descriptionKey: 'ui.agent.faceScheme.state.selectedAnnotation',\n description:\n 'The selected free-form annotation on the active view (id + kind), or null when nothing is selected. Never includes coordinates or the free-text of a text callout.',\n read: (handle) => handle.getSelectedAnnotation(),\n },\n selectedZones: {\n // PHI-safe: zone ids only — selection is UI state, findings stay in\n // `chart`.\n type: 'string[]',\n descriptionKey: 'ui.agent.faceScheme.state.selectedZones',\n description:\n 'Zone ids in the multi-selection (zoneSelect=\"multi\") — the set a bulk finding apply targets. Empty when the mode is off or nothing is selected.',\n read: (handle) => handle.getSelectedZones(),\n },\n annotationZones: {\n // PHI-safe: counts per linked zone only — never the coordinates, and\n // never the free-text of a `text` callout.\n type: 'Record<string, number>',\n descriptionKey: 'ui.agent.faceScheme.state.annotationZones',\n description:\n \"Count of free-form annotations on the active view keyed by their linked zone id ('unassigned' = outside every zone or not yet assessed). Counts only — never coordinates or text.\",\n read: (handle) =>\n handle.getAnnotations().reduce<Record<string, number>>((acc, a) => {\n const key = a.zoneId ?? 'unassigned';\n acc[key] = (acc[key] ?? 0) + 1;\n return acc;\n }, {}),\n },\n },\n actions: {\n focus_zone: {\n safety: 'read',\n argsType: '{ id: string }',\n argsSchema: {\n type: 'object',\n properties: { id: ZONE_SCHEMA },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.focusZone',\n description: 'Move focus to a specific face zone by id.',\n invoke: (handle, args: { id: string }) => {\n handle.focusZone(args.id);\n },\n },\n get_zone: {\n safety: 'read',\n argsType: '{ id: string }',\n argsSchema: {\n type: 'object',\n properties: { id: ZONE_SCHEMA },\n required: ['id'],\n },\n returns: 'string[]',\n returnsSchema: { type: 'array', items: FINDING_SCHEMA },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.getZone',\n description:\n 'Read the finding types recorded on one zone (notes are not returned).',\n invoke: (handle, args: { id: string }) =>\n handle.getZone(args.id).map((f) => f.type),\n },\n zones_with: {\n safety: 'read',\n argsType: '{ finding: FaceFindingType }',\n argsSchema: {\n type: 'object',\n properties: { finding: FINDING_SCHEMA },\n required: ['finding'],\n },\n returns: 'string[]',\n returnsSchema: { type: 'array', items: ZONE_SCHEMA },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.zonesWith',\n description: 'List the zone ids carrying a given finding type.',\n invoke: (handle, args: { finding: FaceFindingType }) =>\n handle.zonesWith(args.finding),\n },\n set_finding: {\n safety: 'write',\n argsType: '{ id: string; finding: FaceFindingType; note?: string }',\n argsSchema: {\n type: 'object',\n properties: {\n id: ZONE_SCHEMA,\n finding: FINDING_SCHEMA,\n note: { type: 'string' },\n },\n required: ['id', 'finding'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.setFinding',\n description:\n 'Record a finding on a zone, with an optional free-text note.',\n invoke: (\n handle,\n args: { id: string; finding: FaceFindingType; note?: string },\n ) => {\n handle.setFinding(args.id, args.finding, args.note);\n },\n },\n remove_finding: {\n safety: 'write',\n argsType: '{ id: string; finding: FaceFindingType }',\n argsSchema: {\n type: 'object',\n properties: { id: ZONE_SCHEMA, finding: FINDING_SCHEMA },\n required: ['id', 'finding'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.removeFinding',\n description: 'Remove a single finding from a zone.',\n invoke: (handle, args: { id: string; finding: FaceFindingType }) => {\n handle.removeFinding(args.id, args.finding);\n },\n },\n clear_zone: {\n safety: 'destructive',\n argsType: '{ id: string }',\n argsSchema: {\n type: 'object',\n properties: { id: ZONE_SCHEMA },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.clearZone',\n description: 'Clear every finding from a zone.',\n invoke: (handle, args: { id: string }) => {\n handle.clearZone(args.id);\n },\n },\n auto_align: {\n safety: 'write',\n argsType: '{}',\n argsSchema: { type: 'object', properties: {} },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.autoAlign',\n description:\n 'Run the on-device detector to align the zone overlay to the patient photo (works on the active view — front or profile). No-op if detection is disabled or no face is found.',\n invoke: (handle) => {\n void handle.detect();\n },\n },\n set_view: {\n safety: 'write',\n argsType: '{ view: FaceViewId }',\n argsSchema: {\n type: 'object',\n properties: { view: VIEW_SCHEMA },\n required: ['view'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.setView',\n description:\n \"Switch the active view ('front' / 'profile-left' / 'profile-right'). Each view renders a different zone set, so switch before focusing a zone that belongs to another view.\",\n invoke: (handle, args: { view: FaceViewId }) => {\n handle.setView(args.view);\n },\n },\n set_zoom: {\n safety: 'write',\n argsType: '{ factor: number }',\n argsSchema: {\n type: 'object',\n properties: {\n factor: { type: 'number', minimum: 1, maximum: 8 },\n },\n required: ['factor'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.setZoom',\n description:\n 'Set the figure zoom factor (1 = reset to the base framing, clamped to 1–8), anchored on the window centre. No-op unless the surface enables `zoomable`.',\n invoke: (handle, args: { factor: number }) => {\n handle.setZoom(args.factor);\n },\n },\n set_tool: {\n safety: 'write',\n argsType: \"{ tool: FaceAnnotationTool | 'none' }\",\n argsSchema: {\n type: 'object',\n properties: { tool: TOOL_SCHEMA },\n required: ['tool'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.setTool',\n description:\n \"Select the active free-form drawing tool ('none' turns drawing off; pointer then falls through to zone selection).\",\n invoke: (handle, args: { tool: string }) => {\n handle.setTool(\n args.tool === 'none' ? null : (args.tool as FaceAnnotationTool),\n );\n },\n },\n undo_annotation: {\n safety: 'write',\n argsType: '{}',\n argsSchema: { type: 'object', properties: {} },\n descriptionKey: 'ui.agent.faceScheme.actions.undoAnnotation',\n description:\n 'Remove the most-recently-added free-form annotation from the active view.',\n invoke: (handle) => {\n handle.undoAnnotation();\n },\n },\n select_annotation: {\n safety: 'read',\n argsType: '{ id: string | null }',\n argsSchema: {\n type: 'object',\n properties: {\n id: {\n type: ['string', 'null'],\n description:\n 'Annotation id on the active view (null clears the selection). Unknown ids are ignored.',\n },\n },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.selectAnnotation',\n description:\n 'Select a free-form annotation on the active view by id (null clears). Selection reveals the mark and enables its panel affordances (delete / recolour).',\n invoke: (handle, args: { id: string | null }) => {\n handle.selectAnnotation(args.id);\n },\n },\n set_annotation_zone: {\n safety: 'write',\n argsType: '{ id: string; zone: string | null }',\n argsSchema: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'Annotation id on the active view.',\n },\n zone: {\n type: ['string', 'null'],\n description: \"Zone id to link, or null to unlink ('no zone').\",\n },\n },\n required: ['id', 'zone'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.setAnnotationZone',\n description:\n 'Link a free-form annotation to a face zone by id (null unlinks it). Unknown annotation ids are ignored. New drawings are auto-linked to the zone under them; this re-assigns marks drawn outside every zone.',\n invoke: (handle, args: { id: string; zone: string | null }) => {\n handle.setAnnotationZone(args.id, args.zone);\n },\n },\n select_zones: {\n safety: 'read',\n argsType: '{ ids: string[] }',\n argsSchema: {\n type: 'object',\n properties: {\n ids: {\n type: 'array',\n items: ZONE_SCHEMA,\n description:\n 'Zone ids to select (replaces the current selection; [] clears).',\n },\n },\n required: ['ids'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.selectZones',\n description:\n 'Replace the zone multi-selection (zoneSelect=\"multi\"). Selection is UI state only — pair with set_finding_bulk to record a finding on the selected zones, or pass ids straight to set_finding_bulk instead.',\n invoke: (handle, args: { ids: string[] }) => {\n handle.setSelectedZones(args.ids);\n },\n },\n set_finding_bulk: {\n safety: 'write',\n argsType: '{ ids: string[]; finding: FaceFindingType; note?: string }',\n argsSchema: {\n type: 'object',\n properties: {\n ids: {\n type: 'array',\n items: ZONE_SCHEMA,\n description: 'Zone ids to record the finding on.',\n },\n finding: FINDING_SCHEMA,\n note: { type: 'string' },\n },\n required: ['ids', 'finding'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.setFindingBulk',\n description:\n 'Record one finding on several zones in a single chart commit (the multi-zone diagnosis path). Zones already carrying the finding are left as they are; the optional note lands only where the finding is newly added.',\n invoke: (\n handle,\n args: { ids: string[]; finding: FaceFindingType; note?: string },\n ) => {\n handle.setFindingBulk(args.ids, args.finding, args.note);\n },\n },\n clear_annotations: {\n safety: 'destructive',\n argsType: '{}',\n argsSchema: { type: 'object', properties: {} },\n idempotent: true,\n descriptionKey: 'ui.agent.faceScheme.actions.clearAnnotations',\n description:\n 'Clear every free-form annotation from the active view. Zone findings are untouched.',\n invoke: (handle) => {\n handle.clearAnnotations();\n },\n },\n },\n domHooks: {\n root: { attr: 'data-component', value: 'face-scheme' },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n item: {\n attr: 'data-zone',\n description:\n 'Each clickable zone `<g>` carries its zone id as `data-zone` (plus `data-side` for the anatomical side, and `data-zone-selected=\"true\"` while in the multi-selection). Each free-form annotation `<g>` carries `data-annotation` (its id), `data-annotation-kind`, `data-annotation-zone` (its linked zone id, when linked), and `data-selected=\"true\"` while selected. The root `<div>` carries the active view id as `data-view` — only the zones for the active view are in the DOM.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* FaceScheme — on-device face-landmark detection (lazy). */\n/* */\n/* Wraps Google's MediaPipe Face Landmarker. The model + wasm runtime */\n/* are LAZY-LOADED from a CDN (overridable) only when detection actually */\n/* runs — so the kit's base bundle ships ZERO ML and FaceScheme stays */\n/* lightweight for consumers that never auto-detect. Everything runs */\n/* on-device: the patient photo and the derived landmarks never leave */\n/* the browser. The same helper is exported for consumer-side use. */\n/* */\n/* It returns canonical-anchor → photo-point pairs in the FaceScheme */\n/* view coordinate space, ready to hand to `FaceSchemeHandle.fitToLand- */\n/* marks` (or the kit feeds them internally for Auto-fit). */\n/* ------------------------------------------------------------------ */\n\nimport type { Point } from './face-scheme-data';\n\n/** Default CDN sources — override to self-host (recommended for production CSP). */\nconst DEFAULT_VISION_MODULE =\n 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.18/vision_bundle.mjs';\nconst DEFAULT_WASM_BASE =\n 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.18/wasm';\nconst DEFAULT_MODEL =\n 'https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task';\n\n/**\n * Canonical FaceScheme anchor → MediaPipe FaceMesh landmark indices.\n * Multiple indices are averaged. Sides are anatomical (the subject's right eye\n * sits on the viewer's left), matching the canonical anchor ids in the data\n * module. Indices are the stable FaceMesh topology (468/478-point).\n */\nconst ANCHOR_INDICES: Record<string, number[]> = {\n 'right-eye': [33, 133], // subject's right eye, outer + inner corners\n 'left-eye': [263, 362], // subject's left eye, outer + inner corners\n 'nose-tip': [1],\n chin: [152],\n // Midline cephalometric points — the profile views fit on these (the detector\n // tracks them on a side profile even though the contralateral side is\n // occluded). The front view ignores ids it has no landmark for.\n nasion: [168], // bridge of the nose, between the brows\n subnasale: [2], // base of the nose / top of the philtrum\n};\n\nexport interface DetectFaceLandmarksOptions {\n /** View coordinate width the points must be projected into (the SVG viewBox W). */\n viewWidth: number;\n /** View coordinate height (the SVG viewBox H). */\n viewHeight: number;\n /** ESM bundle URL for `@mediapipe/tasks-vision`. */\n visionModuleUrl?: string;\n /** Base URL for the MediaPipe wasm fileset. */\n wasmBaseUrl?: string;\n /** URL of the `face_landmarker.task` model. */\n modelAssetPath?: string;\n /** Lifecycle hook — `'loading'` while the model initialises, `'detecting'` during inference. */\n onStage?: (stage: 'loading' | 'detecting') => void;\n}\n\ninterface NormalizedLandmark {\n x: number;\n y: number;\n z: number;\n}\ninterface FaceLandmarkerResult {\n faceLandmarks: NormalizedLandmark[][];\n}\ninterface FaceLandmarkerInstance {\n detect: (image: HTMLImageElement) => FaceLandmarkerResult;\n}\ninterface VisionModule {\n FilesetResolver: { forVisionTasks: (wasmBase: string) => Promise<unknown> };\n FaceLandmarker: {\n createFromOptions: (\n fileset: unknown,\n options: {\n baseOptions: { modelAssetPath: string; delegate?: 'CPU' | 'GPU' };\n runningMode: 'IMAGE' | 'VIDEO';\n numFaces: number;\n },\n ) => Promise<FaceLandmarkerInstance>;\n };\n}\n\n// One landmarker per unique source triple, loaded once and reused.\nconst landmarkerCache = new Map<string, Promise<FaceLandmarkerInstance>>();\n\nfunction getLandmarker(\n visionModuleUrl: string,\n wasmBaseUrl: string,\n modelAssetPath: string,\n onStage?: (stage: 'loading' | 'detecting') => void,\n): Promise<FaceLandmarkerInstance> {\n const key = `${visionModuleUrl}|${wasmBaseUrl}|${modelAssetPath}`;\n const cached = landmarkerCache.get(key);\n if (cached) return cached;\n onStage?.('loading');\n // Variable specifier + @vite-ignore: nothing is bundled or pre-resolved; the\n // ESM module is fetched at call time. Cast through `unknown` — no `any`.\n const promise = (async () => {\n const mod = (await import(\n /* @vite-ignore */ visionModuleUrl\n )) as unknown as VisionModule;\n const fileset = await mod.FilesetResolver.forVisionTasks(wasmBaseUrl);\n return mod.FaceLandmarker.createFromOptions(fileset, {\n baseOptions: { modelAssetPath, delegate: 'GPU' },\n runningMode: 'IMAGE',\n numFaces: 1,\n });\n })();\n landmarkerCache.set(key, promise);\n // Don't cache a rejected init — let the next call retry.\n promise.catch(() => landmarkerCache.delete(key));\n return promise;\n}\n\nfunction loadImage(src: string): Promise<HTMLImageElement> {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.src = src;\n return img.decode().then(() => img);\n}\n\n/**\n * Detect a single face in `src` and return the FaceScheme canonical-anchor →\n * photo-point pairs, projected into the view coordinate space using the same\n * `xMidYMid slice` (cover) fit the FaceScheme `<image>` uses. Resolves `null`\n * if no face is found. Browser-only.\n */\nexport async function detectFaceLandmarks(\n src: string,\n options: DetectFaceLandmarksOptions,\n): Promise<Array<{ id: string; photo: Point }> | null> {\n if (typeof window === 'undefined' || typeof Image === 'undefined') {\n throw new Error('detectFaceLandmarks runs in the browser only.');\n }\n const {\n viewWidth,\n viewHeight,\n visionModuleUrl = DEFAULT_VISION_MODULE,\n wasmBaseUrl = DEFAULT_WASM_BASE,\n modelAssetPath = DEFAULT_MODEL,\n onStage,\n } = options;\n\n const [image, landmarker] = await Promise.all([\n loadImage(src),\n getLandmarker(visionModuleUrl, wasmBaseUrl, modelAssetPath, onStage),\n ]);\n\n onStage?.('detecting');\n const result = landmarker.detect(image);\n const face = result.faceLandmarks[0];\n if (!face || face.length === 0) return null;\n\n // Replicate the component's cover (slice) placement: the image fills the\n // viewBox, centred, cropped — map normalized landmarks → view coordinates.\n const imgW = image.naturalWidth || image.width;\n const imgH = image.naturalHeight || image.height;\n const scale = Math.max(viewWidth / imgW, viewHeight / imgH);\n const offsetX = (viewWidth - imgW * scale) / 2;\n const offsetY = (viewHeight - imgH * scale) / 2;\n const toView = (lm: NormalizedLandmark): Point => ({\n x: offsetX + lm.x * imgW * scale,\n y: offsetY + lm.y * imgH * scale,\n });\n\n const pairs: Array<{ id: string; photo: Point }> = [];\n for (const [id, indices] of Object.entries(ANCHOR_INDICES)) {\n let sx = 0;\n let sy = 0;\n let count = 0;\n for (const idx of indices) {\n const lm = face[idx];\n if (!lm) continue;\n const v = toView(lm);\n sx += v.x;\n sy += v.y;\n count++;\n }\n if (count > 0) pairs.push({ id, photo: { x: sx / count, y: sy / count } });\n }\n return pairs.length >= 3 ? pairs : null;\n}\n","/* ------------------------------------------------------------------ */\n/* FaceScheme — on-device PROFILE face detection (lazy). */\n/* */\n/* The MediaPipe FaceMesh family (see detect-face-landmarks.ts) is */\n/* trained near-frontal: on a 90° lateral profile it under-reads the */\n/* pose and hallucinates the occluded half of the face, so it can't */\n/* register the profile mesh. YuNet (OpenCV Zoo) is a WIDERFACE-trained */\n/* CNN detector that tracks the VISIBLE-side keypoints across poses, so */\n/* the kit uses it for the two profile views. */\n/* */\n/* Runtime: onnxruntime-web is LAZY-LOADED from a CDN (overridable) and */\n/* the ~232 KB model is a code-split asset fetched only when profile */\n/* auto-fit actually runs — the base bundle ships zero ML, matching the */\n/* MediaPipe wrapper. Everything runs on-device: the patient photo and */\n/* the derived keypoints never leave the browser. */\n/* */\n/* It returns YuNet's five canonical keypoints (two eyes, nose tip, two */\n/* mouth corners) projected into the FaceScheme view coordinate space. */\n/* The component picks the visible-side eye + mouth for the profile fit. */\n/* ------------------------------------------------------------------ */\n\nimport type { Point } from './face-scheme-data';\n\n/** Default CDN sources — override to self-host (recommended for production CSP). */\nconst DEFAULT_ORT_MODULE =\n 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.19.2/dist/ort.min.mjs';\nconst DEFAULT_ORT_WASM_BASE =\n 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.19.2/dist/';\n\n/** YuNet 2023mar: fixed 640×640 input, decoded over three strides. */\nconst NET_SIZE = 640;\nconst STRIDES = [8, 16, 32] as const;\n/** YuNet keypoint order → FaceScheme anchor ids (sides are the subject's). */\nconst KEYPOINT_IDS = [\n 'right-eye',\n 'left-eye',\n 'nose-tip',\n 'mouth-right',\n 'mouth-left',\n] as const;\n\nexport interface DetectFaceYuNetOptions {\n /** View coordinate width the points must be projected into (the SVG viewBox W). */\n viewWidth: number;\n /** View coordinate height (the SVG viewBox H). */\n viewHeight: number;\n /** ESM bundle URL for `onnxruntime-web`. */\n ortModuleUrl?: string;\n /** Base URL for the ORT wasm fileset. */\n ortWasmBaseUrl?: string;\n /** URL of the YuNet `.onnx` model (defaults to the kit's bundled copy). */\n modelUrl?: string;\n /** Minimum detection score (default 0.6). */\n scoreThreshold?: number;\n /** Lifecycle hook — `'loading'` while the runtime/model initialise, `'detecting'` during inference. */\n onStage?: (stage: 'loading' | 'detecting') => void;\n}\n\ninterface OrtTensor {\n data: Float32Array;\n dims: readonly number[];\n}\ninterface OrtSession {\n inputNames: string[];\n run: (feeds: Record<string, OrtTensor>) => Promise<Record<string, OrtTensor>>;\n}\ninterface OrtModule {\n env: { wasm: { wasmPaths: string; numThreads: number }; logLevel?: string };\n Tensor: new (\n type: 'float32',\n data: Float32Array,\n dims: number[],\n ) => OrtTensor;\n InferenceSession: {\n create: (\n model: Uint8Array,\n options: { executionProviders: string[] },\n ) => Promise<OrtSession>;\n };\n}\n\n// One session per unique source pair, loaded once and reused.\nconst sessionCache = new Map<\n string,\n Promise<{ ort: OrtModule; session: OrtSession }>\n>();\n\nasync function getSession(\n ortModuleUrl: string,\n ortWasmBaseUrl: string,\n modelUrl: string,\n onStage?: (stage: 'loading' | 'detecting') => void,\n): Promise<{ ort: OrtModule; session: OrtSession }> {\n const key = `${ortModuleUrl}|${ortWasmBaseUrl}|${modelUrl}`;\n const cached = sessionCache.get(key);\n if (cached) return cached;\n onStage?.('loading');\n // Variable specifier + @vite-ignore: nothing is bundled or pre-resolved; the\n // ESM runtime is fetched at call time. Cast through `unknown` — no `any`.\n const promise = (async () => {\n const ort = (await import(\n /* @vite-ignore */ ortModuleUrl\n )) as unknown as OrtModule;\n ort.env.wasm.wasmPaths = ortWasmBaseUrl;\n // Single-threaded: avoids the cross-origin-isolation (COOP/COEP) requirement\n // that SharedArrayBuffer-backed threads impose on the host page.\n ort.env.wasm.numThreads = 1;\n ort.env.logLevel = 'error';\n const model = new Uint8Array(await (await fetch(modelUrl)).arrayBuffer());\n const session = await ort.InferenceSession.create(model, {\n executionProviders: ['wasm'],\n });\n return { ort, session };\n })();\n sessionCache.set(key, promise);\n promise.catch(() => sessionCache.delete(key));\n return promise;\n}\n\nfunction loadImage(src: string): Promise<HTMLImageElement> {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.src = src;\n return img.decode().then(() => img);\n}\n\n/** Resolve the kit's bundled model URL (code-split — fetched only on demand). */\nasync function defaultModelUrl(): Promise<string> {\n const mod = (await import('./face_detection_yunet_2023mar.onnx?url')) as {\n default: string;\n };\n return mod.default;\n}\n\ninterface Candidate {\n score: number;\n keypoints: Array<[number, number]>;\n}\n\n/** Letterbox into NET_SIZE², BGR, NCHW, 0–255 (YuNet/OpenCV convention). */\nfunction preprocess(\n Tensor: OrtModule['Tensor'],\n img: HTMLImageElement,\n): { tensor: OrtTensor; scale: number; padX: number; padY: number } {\n const w = img.naturalWidth || img.width;\n const h = img.naturalHeight || img.height;\n const scale = Math.min(NET_SIZE / w, NET_SIZE / h);\n const dw = Math.round(w * scale);\n const dh = Math.round(h * scale);\n const padX = Math.floor((NET_SIZE - dw) / 2);\n const padY = Math.floor((NET_SIZE - dh) / 2);\n const canvas = document.createElement('canvas');\n canvas.width = NET_SIZE;\n canvas.height = NET_SIZE;\n const ctx = canvas.getContext('2d');\n if (!ctx) throw new Error('2D canvas context unavailable.');\n // Letterbox padding is black: a fresh canvas's default fillStyle is already\n // opaque black, so fillRect needs no colour (YuNet expects zero-padding).\n ctx.fillRect(0, 0, NET_SIZE, NET_SIZE);\n ctx.drawImage(img, padX, padY, dw, dh);\n const { data } = ctx.getImageData(0, 0, NET_SIZE, NET_SIZE);\n const n = NET_SIZE * NET_SIZE;\n const f = new Float32Array(3 * n);\n for (let i = 0; i < n; i++) {\n f[i] = data[i * 4 + 2]; // B\n f[n + i] = data[i * 4 + 1]; // G\n f[2 * n + i] = data[i * 4]; // R\n }\n return {\n tensor: new Tensor('float32', f, [1, 3, NET_SIZE, NET_SIZE]),\n scale,\n padX,\n padY,\n };\n}\n\nconst sigmoid = (x: number): number => 1 / (1 + Math.exp(-x));\n\n/** Decode YuNet's 12 outputs (cls/obj/bbox/kps × 3 strides) → keypoint sets. */\nfunction decode(\n out: Record<string, OrtTensor>,\n scoreThreshold: number,\n): Candidate | null {\n // 2023mar bakes the sigmoid in; older exports emit logits — detect + apply.\n let needSigmoid = false;\n const probe = out['cls_8'].data;\n for (let i = 0; i < Math.min(probe.length, 256); i++) {\n if (probe[i] < 0 || probe[i] > 1) {\n needSigmoid = true;\n break;\n }\n }\n let best: Candidate | null = null;\n for (const s of STRIDES) {\n const cls = out[`cls_${s}`].data;\n const obj = out[`obj_${s}`].data;\n const kps = out[`kps_${s}`].data;\n const cols = NET_SIZE / s;\n const rows = NET_SIZE / s;\n const n = cols * rows;\n for (let i = 0; i < n; i++) {\n let cv = cls[i];\n let ov = obj[i];\n if (needSigmoid) {\n cv = sigmoid(cv);\n ov = sigmoid(ov);\n }\n cv = Math.min(Math.max(cv, 0), 1);\n ov = Math.min(Math.max(ov, 0), 1);\n const score = Math.sqrt(cv * ov);\n if (score < scoreThreshold) continue;\n if (best && score <= best.score) continue;\n const c = i % cols;\n const r = Math.floor(i / cols);\n const keypoints: Array<[number, number]> = [];\n for (let j = 0; j < 5; j++) {\n keypoints.push([\n (c + kps[i * 10 + 2 * j]) * s,\n (r + kps[i * 10 + 2 * j + 1]) * s,\n ]);\n }\n best = { score, keypoints };\n }\n }\n return best;\n}\n\n/**\n * Detect a single face in `src` and return YuNet's canonical keypoint →\n * photo-point pairs, projected into the view coordinate space using the same\n * `xMidYMid slice` (cover) fit the FaceScheme `<image>` uses. Resolves `null`\n * if no face is found. Browser-only.\n */\nexport async function detectFaceYuNet(\n src: string,\n options: DetectFaceYuNetOptions,\n): Promise<Array<{ id: string; photo: Point }> | null> {\n if (typeof window === 'undefined' || typeof Image === 'undefined') {\n throw new Error('detectFaceYuNet runs in the browser only.');\n }\n const {\n viewWidth,\n viewHeight,\n ortModuleUrl = DEFAULT_ORT_MODULE,\n ortWasmBaseUrl = DEFAULT_ORT_WASM_BASE,\n modelUrl = await defaultModelUrl(),\n scoreThreshold = 0.6,\n onStage,\n } = options;\n\n const [image, { ort, session }] = await Promise.all([\n loadImage(src),\n getSession(ortModuleUrl, ortWasmBaseUrl, modelUrl, onStage),\n ]);\n\n onStage?.('detecting');\n const { tensor, scale, padX, padY } = preprocess(ort.Tensor, image);\n const result = await session.run({ [session.inputNames[0]]: tensor });\n const face = decode(result, scoreThreshold);\n if (!face) return null;\n\n // Replicate the component's cover (slice) placement of the <image>.\n const imgW = image.naturalWidth || image.width;\n const imgH = image.naturalHeight || image.height;\n const coverScale = Math.max(viewWidth / imgW, viewHeight / imgH);\n const offsetX = (viewWidth - imgW * coverScale) / 2;\n const offsetY = (viewHeight - imgH * coverScale) / 2;\n\n return face.keypoints.map(([kx, ky], j) => {\n // Un-letterbox (network space → original image px), then project to view.\n const px = (kx - padX) / scale;\n const py = (ky - padY) / scale;\n return {\n id: KEYPOINT_IDS[j],\n photo: {\n x: offsetX + px * coverScale,\n y: offsetY + py * coverScale,\n },\n };\n });\n}\n","/* Provenance — FRONT zones are AUTO-GENERATED by scratchpad/gen-zones.mjs from\n platform faceElements.js and are byte-identical to the platform FaceMap.\n PROFILE zones diverge from the platform on purpose: the platform side-profile is a\n photo-less schematic with a stylised, over-deep skull that no rigid fit can register\n onto a real photographed profile. The kit therefore reshapes the platform-authored\n profile paths with a thin-plate-spline warp pinned to anatomical landmarks (crown,\n nasion, eye, nose-tip, subnasale, lips, chin, jaw-angle, ear, back-skull, nape) so the\n mesh traces a real face for the photo overlay. Do not hand-edit the path data: re-run\n the front generator, or the profile TPS bake (scratchpad/faces/tps + bake-zones), and\n paste the output here. Centroids are the path-bounds midpoint, used to anchor finding\n markers. viewBox is the platform 0 0 808 944. */\n\nimport type { FaceLandmarkSeed, FaceZoneSeed } from './face-scheme-data';\n\nexport const FRONT_VIEWBOX = '0 0 808 944';\nexport const FRONT_PIVOT = { x: 404, y: 472 } as const;\n\nexport const FRONT_CONTOUR: FaceZoneSeed = {\n id: 'faceContour',\n labelKey: 'faceContour',\n d: 'M688.38,439.4c-9.78,0-15.37,4.04-17.86,6.47,1.31-10.99,2.5-20.62,3.49-28.2,7.55-57.89,5.03-94.39,5.03-94.39-15.15-165.92-111.73-221.46-186.21-239.39h0s-.1-.02-.1-.02c-6.18-1.49-12.21-2.72-18.02-3.73l-.96-.2c-46.02-9.51-93.5-9.51-139.52,0l-.95.2c-5.82,1.01-11.85,2.24-18.04,3.73l-.08.02h0c-74.48,17.94-171.06,73.48-186.21,239.39,0,0-2.52,36.5,5.03,94.39,1,7.68,2.2,17.45,3.53,28.61-2.25-2.35-7.91-6.88-18.26-6.88-13.97,0-29.06,16.21-20.12,63.71,8.94,47.5,17.3,80.48,18.43,97.24,1.11,16.47,24.08,47.91,41.43,38.23.9,8.33,1.42,13.17,1.42,13.17,0,0,8.81,59.15,56.63,104.46,12.62,11.95,25.84,23.46,38.49,33.94,7.14-4.56,24-16.96,29.06-35.21.9-3.24,1.73-6.33,2.52-9.29,2.46-9.17,4.59-17.1,7.4-24.46,3.44-9.01,7.62-16.28,13.25-23.04-47.54-46.57-49.82-89.3-48.75-104.93-21.75-2.47-38.06-19.4-47.37-49.37-7.27-23.39-7.77-46.39-7.79-47.36-.02-1.34.43-2.57,1.21-3.54-.47-2.21-.65-3.58-.67-3.77-.28-2.23.97-4.38,3.05-5.24.34-.14.69-.23,1.04-.29.47-3.26,2.23-10.86,8.8-18.21,10.82-12.11,28.95-17.92,53.93-17.22,41.5,1.13,55.11,17.49,59.58,28.15,1.45.85,2.49,2.34,2.68,4.14,0,.05.02.21.05.45.22.48.36,1,.42,1.56.04.41.34,3.71.16,8.68.17,6.11.1,14.39-.75,23.68-.27,2.9-.6,5.73-.98,8.49,4.1-9.94,7.68-20.29,11.15-30.32l.31-.89-10.84-54.18c-2.15-3.39-8.76-12.5-21.75-19.51-21.63-11.68-51.16-12.3-85.4-1.8-2.58.79-5.32-.61-6.19-3.16l-53.03-154.45c-.88-1.09-1.31-2.52-1.05-4.01.26-1.43,6.68-35.35,39.46-69.52,19.15-19.96,43.37-35.84,72.01-47.21,35.3-14.02,77.45-21.18,125.28-21.27h0s.98,0,.98,0c47.83.1,89.98,7.25,125.28,21.27,28.63,11.37,52.86,27.26,72.01,47.21,30.62,31.92,38.24,63.61,39.32,68.82.29.8.42,1.35.47,1.59.17.87.11,1.77-.17,2.61l-53.21,154.96c-.88,2.55-3.62,3.95-6.19,3.16-34.24-10.5-63.77-9.88-85.4,1.8-11.42,6.17-17.92,13.96-20.78,18.06l-11.25,56.25.04.11c2.95,8.52,5.98,17.28,9.34,25.81-.14-1.26-.28-2.53-.4-3.82-.53-5.79-.75-11.19-.81-15.92-1.11-9.09-.51-15.85-.45-16.44.11-1.1.59-2.08,1.3-2.85.19-.72.52-1.37.96-1.94,3.86-10.54,16.77-28.3,60.04-29.48,24.93-.69,43.04,5.1,53.85,17.2,6.53,7.3,8.3,14.85,8.78,18.13.53.04,1.05.16,1.56.37,2.08.86,3.32,3.01,3.05,5.24-.02.14-.12.93-.37,2.25,1.7.96,2.84,2.8,2.8,4.89-.02.97-.52,23.97-7.79,47.36-8.99,28.91-24.49,45.69-45.11,49.05,1.16,15.29-.68,58.78-49.42,106.1,5.35,6.56,9.36,13.63,12.68,22.33,2.81,7.36,4.94,15.28,7.4,24.45.79,2.96,1.62,6.05,2.52,9.29,5.07,18.28,21.97,30.69,29.09,35.23,12.65-10.48,25.88-21.99,38.5-33.95,47.82-45.31,56.63-104.46,56.63-104.46,0,0,.51-4.77,1.4-13,17.31,9.1,39.99-22.04,41.09-38.41,1.13-16.77,9.49-49.74,18.43-97.24,8.94-47.5-6.15-63.71-20.12-63.71Z',\n};\n\nexport const FRONT_ZONES: FaceZoneSeed[] = [\n {\n id: 'lateralNeckRight',\n labelKey: 'lateralNeckRight',\n d: 'M234.37,783.6s32.84,133.08,163.93,137.04v-48.41s-103.52,3.15-163.93-88.63Z',\n cx: 316,\n cy: 852,\n side: 'right',\n },\n {\n id: 'lateralNeckLeft',\n labelKey: 'lateralNeckLeft',\n d: 'M572.98,783.6s-32.84,133.08-163.93,137.04v-48.41s103.52,3.15,163.93-88.63Z',\n cx: 491,\n cy: 852,\n side: 'left',\n },\n {\n id: 'forehead',\n labelKey: 'forehead',\n d: 'M404,206.87s-.1,0-.14,0h-1.06s-.09,0-.14,0c-193.61.2-222.63,42.82-226.18,50.14l51.08,148.75c44.34-12.51,72.83-4.7,89.09,4.28,11.9,6.57,19.12,14.63,22.86,19.75,9.12-6.42,21.26-11.05,36.17-13.79,13.2-2.43,24.31-2.56,27.4-2.54.05,0,.1,0,.16,0h.04s.07,0,.11,0h.04c.2,0,.4,0,.64,0,3.65,0,14.33.22,26.92,2.54,14.91,2.74,27.05,7.37,36.17,13.79,3.74-5.12,10.96-13.18,22.86-19.75,16.26-8.98,44.75-16.79,89.09-4.28l51.08-148.75c-3.54-7.32-32.57-49.94-226.18-50.14Z',\n cx: 403,\n cy: 318,\n side: 'midline',\n },\n {\n id: 'glabella',\n labelKey: 'glabella',\n d: 'M403.28,472.75s.03,0,.04,0c.11,0,.22,0,.34,0,.11,0,.22,0,.34,0,.02,0,.03,0,.04,0,28.06.09,43.26,5.62,51.09,10.26l8.65-43.23c-19.58-15.79-54.78-16.31-59.89-16.33-.13,0-.27,0-.4,0h-.16s-.16,0-.16,0c-.13,0-.27,0-.4,0-5.09-.02-39.63.51-59.32,15.85l8.74,43.71c7.83-4.64,23.03-10.17,51.09-10.26Z',\n cx: 404,\n cy: 453,\n side: 'midline',\n },\n {\n id: 'nasalBase',\n labelKey: 'nasalBase',\n d: 'M403.9,608.63c-.19.02-.38.06-.58.06-34.25,0-47.76,9.72-52.65,15.19-.02.21-.05.42-.1.62,10.07,8.84,28.11,13.48,52.75,13.48.15,0,.29.03.43.04.15-.01.29-.04.43-.04,24.98,0,43.18-4.76,53.17-13.83-4.69-5.41-18.09-15.46-52.89-15.46-.2,0-.38-.04-.58-.06Z',\n cx: 404,\n cy: 623,\n side: 'midline',\n },\n {\n id: 'nasolabialFold',\n labelKey: 'nasolabialFold',\n d: 'M347.77,580.98c-2.28,3.78-4.09,6.76-5.04,9.96-1.38,4.58-3.68,15.46,1.36,25.35,7.25-7.51,23.63-17.61,59.24-17.61.2,0,.38.04.58.06.19-.02.38-.06.58-.06,35.31,0,51.71,9.93,59.05,17.42,4.92-9.84,2.63-20.61,1.27-25.17-.96-3.19-2.76-6.18-5.04-9.96-5.23-8.65-12.39-20.5-14.97-45.03-2.34-22.26,2.15-36.18,6.11-43.75-5.65-3.61-19.1-9.4-47.23-9.45-27.9.05-41.36,5.75-47.09,9.36,3.98,7.55,8.51,21.49,6.16,43.84-2.58,24.53-9.74,36.38-14.97,45.03Z',\n cx: 404,\n cy: 550,\n side: 'midline',\n },\n {\n id: 'medialCheekboneRight',\n labelKey: 'medialCheekboneRight',\n d: 'M310.99,528.29c6.75-7.41,10.08-16.87,11.7-25.19-.55.67-1.13,1.34-1.73,2.02-11.93,13.41-27.69,20.63-45.58,20.88-24.57.33-43.87-10.86-55.92-20.57,6.83,15.71,22.29,36.28,56.41,36.28,15.2,0,27.02-4.51,35.12-13.42Z',\n cx: 271,\n cy: 522,\n side: 'right',\n },\n {\n id: 'medialCheekboneLeft',\n labelKey: 'medialCheekboneLeft',\n d: 'M529.65,526c-17.89-.25-33.66-7.47-45.58-20.88-.48-.54-.94-1.08-1.39-1.62.02.49.04.99.06,1.49,1.74,7.84,5.06,16.45,11.3,23.3,8.11,8.9,19.92,13.42,35.12,13.42,34.11,0,49.57-20.57,56.41-36.28-12.05,9.71-31.35,20.9-55.92,20.57Z',\n cx: 534,\n cy: 523,\n side: 'left',\n },\n {\n id: 'lateralCheekLeft',\n labelKey: 'lateralCheekLeft',\n d: 'M540.15,593.37c-18.18-.45-32.31-6.73-43.63-16.5-1.18-.24-2.29-.88-3.12-1.88-1.11-1.34-2.16-2.75-3.18-4.2-15.93-17.11-25.66-41.5-33.74-64.38-1.86,6.64-3.07,15.9-1.75,28.49,2.35,22.31,8.58,32.62,13.58,40.91,2.44,4.04,4.74,7.85,6.06,12.26,1.9,6.35,5.16,22.19-4,36.16,7.6,9.08,23.47,31.53,26.94,63.94,25.78-26.28,36.07-50.77,40.13-67.19,3.11-12.6,3.1-22.36,2.72-27.61Z',\n cx: 497,\n cy: 597,\n side: 'left',\n },\n {\n id: 'lateralCheekRight',\n labelKey: 'lateralCheekRight',\n d: 'M350.8,505.59c-14.12,40.11-33.1,85.3-81.73,87.86-.37,5.26-.37,15,2.72,27.53,4.02,16.29,14.18,40.52,39.5,66.55,3.52-31.28,18.56-53.18,26.31-62.61-9.73-14.13-6.4-30.4-4.46-36.85,1.32-4.41,3.62-8.22,6.06-12.26,5-8.29,11.23-18.6,13.58-40.91,1.38-13.12,0-22.63-1.99-29.32Z',\n cx: 311,\n cy: 597,\n side: 'right',\n },\n {\n id: 'zygomaticArchRight',\n labelKey: 'zygomaticArchRight',\n d: 'M319.21,534.06c-.26.3-.51.61-.78.91-10.08,11.1-24.4,16.73-42.56,16.73-30.94,0-48.47-15.12-58-28.84,4.69,25.35,16.61,59.69,46.82,59.69,16.21,0,28.81-5.46,38.96-14.31.06-.09.11-.18.18-.26,7.83-9.48,12.57-21.69,15.39-33.93Z',\n cx: 269,\n cy: 553,\n side: 'right',\n },\n {\n id: 'zygomaticArchLeft',\n labelKey: 'zygomaticArchLeft',\n d: 'M542.24,582.4c31.74,0,43.29-37.91,47.48-63.47-.28.46-.57.93-.86,1.4-9.09,14.32-26.82,31.38-59.69,31.38-18.08,0-32.36-5.59-42.43-16.6,2.41,10.07,6.15,20.06,11.85,28.48,10.9,11.46,24.85,18.81,43.65,18.81Z',\n cx: 538,\n cy: 551,\n side: 'left',\n },\n {\n id: 'upperForehead',\n labelKey: 'upperForehead',\n d: 'M524.46,147.46c-34.16-13.49-75.08-20.35-121.64-20.4-46.56.05-87.49,6.91-121.64,20.4-27.26,10.76-50.3,25.76-68.48,44.56-15.39,15.91-24.67,31.94-30.13,44.09,4.92-3.6,11.3-7.4,19.61-11.17,40.86-18.52,108.25-27.96,200.32-28.07.05,0,.11,0,.16,0h.68s.68,0,.68,0c.05,0,.11,0,.16,0,92.07.1,159.46,9.55,200.32,28.07,7.48,3.39,13.39,6.81,18.08,10.08-5.52-12-14.69-27.55-29.63-43-18.18-18.8-41.22-33.79-68.48-44.56Z',\n cx: 403,\n cy: 182,\n side: 'midline',\n },\n {\n id: 'marionetteLines',\n labelKey: 'marionetteLines',\n d: 'M344.66,676.82c23.78-8.45,44.18-6.91,59.31,4.4,15.13-11.32,35.54-12.87,59.33-4.41,9.61,3.41,17.99,7.81,23.93,11.32-3.32-27.6-16.56-47.44-23.55-56.2-11.99,10.66-31.94,16.05-59.49,16.05-.15,0-.29-.03-.43-.04-.15.01-.29.04-.43.04-27.09,0-46.83-5.21-58.88-15.52-7.05,8.98-19.76,28.44-23.08,55.31,5.9-3.44,14.03-7.65,23.29-10.94Z',\n cx: 404,\n cy: 660,\n side: 'midline',\n },\n {\n id: 'lowerLip',\n labelKey: 'lowerLip',\n d: 'M487.84,709.63c-4.92,5.03-11.64,11.3-19.65,17.27-17.67,13.18-35.13,19.92-51.28,19.92-4.52,0-8.94-.53-13.23-1.6-4.29,1.06-8.71,1.6-13.23,1.6-16.15,0-33.61-6.74-51.28-19.92-7.36-5.49-13.63-11.23-18.42-16.03,1.76,38.11,15.57,71.15,82.56,71.15.33,0,.64.04.95.1.31-.06.62-.1.95-.1,67.72,0,81.09-33.76,82.62-72.39Z',\n cx: 404,\n cy: 746,\n side: 'midline',\n },\n {\n id: 'lipCommissures',\n labelKey: 'lipCommissures',\n d: 'M407.45,691.27c-.9.8-2.02,1.19-3.13,1.23-1.34.13-2.72-.26-3.8-1.22-22.23-19.67-55.63-5.3-72.53,4.24,11.5,1.38,25.87,2.57,31.61,1.13,6.72-1.68,12.32.35,18.25,2.5,6.08,2.2,13.64,4.94,25.48,4.98,11.85-.04,19.41-2.78,25.48-4.98,5.93-2.15,11.53-4.18,18.25-2.5,5.93,1.48,21.03.17,32.69-1.26-16.96-9.54-50.17-23.72-72.31-4.13Z',\n cx: 404,\n cy: 688,\n side: 'midline',\n },\n {\n id: 'upperLip',\n labelKey: 'upperLip',\n d: 'M444.65,706.36c-3.59-.9-6.73.14-12.42,2.2-6.4,2.32-15.13,5.47-28.52,5.57-.03,0-.06,0-.09,0-.09,0-.18,0-.28,0-.09,0-.18,0-.28,0-.03,0-.06,0-.09,0-13.39-.1-22.12-3.25-28.52-5.57-5.69-2.06-8.83-3.1-12.42-2.2-6.87,1.72-20.85.72-32.07-.53,15.47,14.96,44.16,37.13,72.34,29.42.46-.13.93-.16,1.39-.15.46,0,.93.03,1.4.15,28.22,7.72,56.98-14.55,72.43-29.5-11.35,1.29-25.82,2.37-32.86.61Z',\n cx: 404,\n cy: 724,\n side: 'midline',\n },\n {\n id: 'submental',\n labelKey: 'submental',\n d: 'M402.47,796.81c-31.67.12-55.93,8.97-72.11,26.31-5.47,5.87-9.06,11.79-11.35,16.53.85.63,1.68,1.27,2.5,1.95,4.99,4.16,26.68,19.07,81.31,19.07s76.32-14.91,81.31-19.07c.65-.54,1.31-1.06,1.98-1.57-2.28-4.8-5.91-10.88-11.53-16.91-16.17-17.35-40.44-26.19-72.11-26.31Z',\n cx: 403,\n cy: 829,\n side: 'midline',\n },\n {\n id: 'mandibularAngleLeft',\n labelKey: 'mandibularAngleLeft',\n d: 'M514.03,757.42c-.91-3.27-1.74-6.39-2.54-9.37-2.39-8.91-4.46-16.6-7.08-23.48-1.84-4.83-3.93-9.07-6.37-12.99-1.26,23.6-6.85,40.74-17.31,53.43-10.17,12.33-24.87,20.32-44.53,24.16,17.13,3.95,34.7,11.85,48.39,26.79,5.59,6.1,9.46,12.22,12.09,17.4,10.43-7.53,28.1-20.6,47.98-36.72-9.19-6.29-25.19-19.64-30.61-39.21Z',\n cx: 490,\n cy: 772,\n side: 'left',\n },\n {\n id: 'mandibularAngleRight',\n labelKey: 'mandibularAngleRight',\n d: 'M372.3,789.03c-19.33-3.89-33.81-11.84-43.86-24.02-10.59-12.83-16.18-30.24-17.35-54.26-2.69,4.15-4.95,8.66-6.92,13.84-2.63,6.88-4.69,14.57-7.08,23.48-.8,2.98-1.64,6.1-2.54,9.37-5.42,19.55-21.39,32.89-30.58,39.19,19.56,15.86,36.98,28.78,47.47,36.36,2.63-5.1,6.44-11.07,11.9-17.03,13.85-15.11,31.67-23.02,48.98-26.92Z',\n cx: 318,\n cy: 772,\n side: 'right',\n },\n {\n id: 'eyelidRight',\n labelKey: 'eyelidRight',\n d: 'M270.93,458.23c-50.38-1.36-52.57,26.33-52.64,27.51-.08,1.39-.72,2.61-1.69,3.46,7.87,8.21,29.3,27.23,58.63,26.79,29.72-.41,43.34-22.6,47.54-31.28-.03-.39-.05-.75-.07-1.07-1.34-6.07-8.94-24.24-51.76-25.41Z',\n cx: 270,\n cy: 487,\n side: 'right',\n },\n {\n id: 'eyelidLeft',\n labelKey: 'eyelidLeft',\n d: 'M586.21,485.71c-.08-1.27-2.3-28.82-52.55-27.45-36.35.99-47.27,14.25-50.55,21.95.08.48.1.98.05,1.49-.01.11-.16,1.63-.31,4.22,4.82,9.37,18.52,29.69,46.94,30.08,29.04.43,50.34-18.21,58.4-26.55-1.13-.87-1.91-2.2-1.98-3.73Z',\n cx: 536,\n cy: 487,\n side: 'left',\n },\n];\n\nexport const FRONT_LANDMARKS: FaceLandmarkSeed[] = [\n { id: 'right-eye', labelKey: 'rightEye', x: 268, y: 487 },\n { id: 'left-eye', labelKey: 'leftEye', x: 535, y: 487 },\n { id: 'nose-tip', labelKey: 'noseTip', x: 403, y: 620 },\n { id: 'chin', labelKey: 'chin', x: 404, y: 858 },\n];\n\n/* Side-profile zone paths (left-facing), kept for a future profile view. Not yet\n wired into FACE_VIEWS — front is the photo-mapping surface today. */\nexport const PROFILE_ZONE_PATHS: FaceZoneSeed[] = [\n {\n id: 'cheekbone',\n labelKey: 'cheekbone',\n d: 'M587.86 415.87C586.01 408.8 583.79 409.02 576.91 410.15C573.08 410.38 567.86 410.32 561.24 408.36C547.07 403.39 488.66 358.5 465.97 345.98C436.12 334.42 407.31 328.09 390.38 326.48C395.19 331.07 399.27 338.58 388.69 345.72C397.48 346.49 408.73 348.34 421.39 351.61C467.3 374.36 523.12 420.78 541.55 435.68C550.62 443.21 555.39 449.39 559.11 454.28C564.66 461.73 567.89 466.16 579.26 467.46C583.31 467.67 586.22 465.29 588.19 460.34C591.18 452.28 592.1 431.43 587.86 415.88Z',\n cx: 490,\n cy: 397,\n },\n {\n id: 'profileContour',\n labelKey: 'profileContour',\n d: 'M657.04 427.15C645.32 417.42 612.92 377.67 608.47 342.76C610.05 315.91 614.77 299.37 606.91 241.79C600.19 175.54 556.62 116.74 420.63 130.08C253.44 160.79 152.79 273.93 132.98 380.57C116.36 516.03 182.43 589.12 182.43 589.12L226.57 641.41C234.86 650.15 249.78 644.43 261.09 627.35L321.54 525.13C328.57 512.58 325.7 495.54 318.17 493.61C294.63 488.83 257.86 468.83 262.84 409.94C267.69 380.06 284 357.04 302.38 340.78C330.2 319.79 367.62 311.97 382.74 320.74C382.87 320.84 382.94 320.94 382.99 321.04C388.82 321.28 405.44 322.73 426.75 326.43C424.09 323.46 422.53 319.98 422.13 315.98C421.41 309.9 423.49 304.51 423.88 303.54C426.23 284.75 477.87 242.7 506.61 211.31L506.84 210.99C508.32 208.89 511.62 207.65 515.45 207.77C519.23 207.92 522.88 209.42 524.98 211.72L567.11 326.31C568.13 330.65 567.2 335.05 564.76 336.69C563.35 337.54 561.24 339.5 558.91 342.14C559.06 342.41 559.15 342.57 559.15 342.57L573.97 372.38C575.71 369.67 578.22 365.84 581.33 362.37C585.49 356.14 590.79 348.98 597.61 352.24C598.15 352.43 598.76 354.7 598.84 357.08C598.91 358.84 598.59 359.88 598.14 359.69C597.37 359.38 596.65 359.2 595.96 359.12C597.33 369.53 600.96 398.18 595.38 398C588.92 397.38 587.72 374.56 588.46 362.31C586.69 363.79 584.85 365.85 582.96 368.5C580.04 371.85 577.73 375.59 576.26 377.97L577.27 380.55C577.56 381.29 577.66 382.22 577.55 383.11C577.43 384 577.11 384.76 576.66 385.24L553.04 396.96C558.13 400.5 560.86 401.88 562.35 402.34C568.32 404.04 572.97 404.02 576.7 403.74C583.09 402.53 587.8 400.9 590.94 412.75C594.16 424.28 596.78 449.29 591.87 464.27C589.18 471.56 584.78 475.46 579.05 475.22C575.99 474.97 573.36 474.4 571.04 473.57C567.75 472.35 565.15 470.69 562.9 468.71C562.88 472.1 562.76 476.4 562.38 481.46C567.8 483.15 578.56 487.63 584.78 500.94C588.58 509.77 589.68 521.45 587.53 535.74C590.03 539.27 597.49 548.85 608.32 547.11C615.16 544.28 621.37 543.88 625.6 545.18C627.13 536.84 628.35 525.82 627.96 516.71C626.08 501.81 623.74 494.92 625.48 485.82C627.82 477.03 640.49 466.24 651.72 451.57C662.37 438.81 663.39 438.52 657.07 427.15Z',\n cx: 390,\n cy: 383,\n },\n {\n id: 'temple',\n labelKey: 'temple',\n d: 'M551.29 339.27C551.73 338.72 552.17 338.34 552.62 338.11C556.19 334.28 559.65 331.21 562.14 329.85C562.68 329.54 562.9 328.65 562.67 327.75L518.07 213.95C517.55 213.37 516.78 213.26 516.36 213.24C515.95 213.22 515.19 213.27 514.81 213.81L514.57 214.13C507.63 223.01 490.31 241.35 473.08 259.55C456.86 274.15 435.38 293.06 434.06 303.22L434.04 303.36L433.97 303.51C433.88 303.72 424.42 324.26 448.09 332.54C448.37 332.66 448.62 332.79 448.84 332.93C456.22 335.74 463.82 338.97 471.46 342.54C502.66 360.75 523.25 375.04 536.66 384.85C535.73 382.31 534.95 379.47 534.57 376.45C533.66 370.15 534.7 364.78 536.86 360.11C539.61 349.89 545.41 345.33 549.41 341.41C549.46 341.36 549.51 341.3 549.56 341.25C550.19 340.57 550.77 339.92 551.29 339.26Z',\n cx: 494,\n cy: 299,\n },\n {\n id: 'preauricularArea',\n labelKey: 'preauricularArea',\n d: 'M399.04 423.47C400.19 426.46 399.28 429.83 397.03 431.07L421.24 493.26C429.33 496.6 440.56 504.27 451.47 519.28C455.98 526.45 460.47 535.45 464.49 546.37C473.34 527.06 479.06 492.31 479.5 447.01C480.52 417.95 479.02 394.87 478.75 390.28C457.75 375.55 435.02 362.96 415.32 355.59C403.76 352.86 393.4 351.38 385.05 350.82C383.53 355.04 382.54 362.85 384.93 378.19C389.1 396.84 398.92 423.16 399.04 423.46Z',\n cx: 432,\n cy: 449,\n },\n {\n id: 'mandibularBody',\n labelKey: 'mandibularBody',\n d: 'M448.9 529.33C441.36 518.39 433.39 511.79 426.69 508.14L444.05 565.22L444.11 565.55C444.61 568.53 446.18 612.75 465.58 621.58C467.31 622.11 469.2 622.59 471.21 623.04C472.27 587.41 463.32 555.13 448.9 529.33Z',\n cx: 449,\n cy: 566,\n },\n {\n id: 'submentalProfile',\n labelKey: 'submentalProfile',\n d: 'M499.51 624.48C500.22 624.28 501.01 624.05 501.85 623.78C506.95 622.1 508.34 617.25 499.33 608.72C499.3 608.71 499.28 608.69 499.25 608.67C498.87 608.43 498.48 608.2 498.08 607.95C489.61 603.09 481.6 597.71 477.16 594.66C477.83 603.57 477.42 613.28 475.61 623.94C494.7 628.41 483.66 636.08 483.66 636.08C483.66 636.08 476.69 649.28 527.7 627.3C518.99 627.63 510.52 627.34 503.56 626.55C496.4 626.16 495.89 625.71 499.5 624.48Z',\n cx: 502,\n cy: 622,\n },\n {\n id: 'masseter',\n labelKey: 'masseter',\n d: 'M554.71 459.19C550.92 454.22 546.49 448.51 537.91 441.39C528.42 433.63 510.52 417.13 488.4 397.93C489.3 421.03 491.75 514.66 467.63 555.34C470.6 563.87 473.34 573.19 475.46 583.39C476.18 582.97 476.93 582.94 477.54 583.4C477.77 583.56 487.55 590.84 499.76 598.04C530.58 563.84 546.09 529.73 552.28 505.65C557.13 483.51 556.81 466.48 556.58 461.68C555.96 460.87 555.34 460.04 554.7 459.2Z',\n cx: 512,\n cy: 498,\n },\n {\n id: 'cheek',\n labelKey: 'cheek',\n d: 'M503.7 600.29L503.69 600.76C506.68 599.48 519.15 594.49 532.76 586.74C551.63 579.2 568.84 567.08 579.23 546.08C584.39 529.37 584.46 515.84 580.48 506.25C575.46 495.21 566.3 491.13 561.55 489.57C560.86 495.06 559.83 501.15 558.34 507.68C551.78 532.36 535.25 566.52 503.69 600.3Z',\n cx: 544,\n cy: 545,\n },\n {\n id: 'chin',\n labelKey: 'chin',\n d: 'M622.37 557.72C618.53 556.38 613.08 555.94 606.76 557.59C595.83 558.3 588.65 550.46 584.99 545.44C584.69 546.34 584.38 547.24 584.03 548.15C571.22 572.11 550.01 585.32 530.6 593C522.53 597.65 514.89 601.46 509.24 604.26C515.21 610.11 514.33 615.81 510.02 618.18C502.34 623.58 523.79 624.61 543.95 623.09C547.34 622.17 550.83 621.19 554.45 620.12L594.99 602.7L595.21 602.54C596.13 601.8 602.57 595.37 608.29 593.49C613.07 590.42 621.01 568.35 622.15 559.26C622.19 558.76 622.27 558.26 622.36 557.75Z',\n cx: 562,\n cy: 585,\n },\n {\n id: 'browTail',\n labelKey: 'browTail',\n d: 'M555.64 346.57C555.64 346.57 530.25 360.36 547.29 391.38L572.95 381.28L555.64 346.57Z',\n cx: 552,\n cy: 369,\n },\n];\n","/* ------------------------------------------------------------------ */\n/* FaceScheme — data module (pure, no React). */\n/* */\n/* The clinical face-zone taxonomy (aesthetic-medicine front view), */\n/* the finding vocabulary + its shared marker glyphs, and the affine */\n/* registration maths used to map the canonical zone mesh onto a real */\n/* patient photo. This module is the swap seam: the FRONT zone `d` paths */\n/* are byte-identical to the platform FaceMap; the PROFILE paths are */\n/* TPS-reshaped to trace a real face (see face-scheme-zones.ts). */\n/* */\n/* Registration is a 6-DOF affine — independent horizontal + vertical */\n/* scale, rotation, shear and translation — emitted as an SVG */\n/* `transform` matrix on the mesh group (never an inline style). The */\n/* same `solveAffine` least-squares fit serves manual landmark drag */\n/* AND a consumer-/kit-run face detector (detect-face-landmarks.ts). */\n/* ------------------------------------------------------------------ */\n\nimport type { MarkerShape, MarkerTone } from '../annotation-marker';\nimport {\n FRONT_CONTOUR,\n FRONT_LANDMARKS,\n FRONT_PIVOT,\n FRONT_VIEWBOX,\n FRONT_ZONES,\n PROFILE_ZONE_PATHS,\n} from './face-scheme-zones';\n\n/* ------------------------------------------------------------------ */\n/* Geometry vocabulary */\n/* ------------------------------------------------------------------ */\n\nexport type FaceViewId = 'front' | 'profile-left' | 'profile-right';\nexport type FaceSide = 'left' | 'right' | 'midline';\n\nexport interface Point {\n x: number;\n y: number;\n}\n\n/** Raw zone shape emitted by the generator (cx/cy/side present for clickable\n * zones, absent on the contour guide). */\nexport interface FaceZoneSeed {\n id: string;\n labelKey: string;\n d: string;\n cx?: number;\n cy?: number;\n side?: FaceSide;\n}\nexport interface FaceLandmarkSeed {\n id: string;\n labelKey: string;\n x: number;\n y: number;\n}\n\n/** A clickable face zone — a region of the canonical mesh. */\nexport interface FaceZone {\n id: string;\n /** `faceScheme.zone.<labelKey>` translation key. */\n labelKey: string;\n /** SVG path data in the view's coordinate space. */\n d: string;\n /** Path-bounds centroid — anchors the finding marker. */\n cx: number;\n cy: number;\n /** Patient-anatomical side (not reading direction). */\n side: FaceSide;\n}\n\n/** A canonical landmark anchor used to fit the mesh to a photo. */\nexport interface FaceLandmark {\n id: string;\n /** `faceScheme.landmark.<labelKey>` translation key. */\n labelKey: string;\n x: number;\n y: number;\n}\n\n/** Axis-aligned box in view user units. */\nexport interface Box {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface FaceView {\n id: FaceViewId;\n /** `faceScheme.view.<labelKey>` translation key. */\n labelKey: string;\n viewBox: string;\n /** Photoless window: measured identity-affine mesh bbox + 24-unit pad,\n pre-mirrored for the right profile. Re-measure if the mesh changes. */\n schematicViewBox: string;\n /** Raw identity-affine mesh bbox in LOCAL (un-mirrored) coords — the\n auto-framing anchor. Same measurement as schematicViewBox, no pad. */\n meshContentBox: Box;\n /** Pivot for the registration controls (the face centre). */\n pivot: Point;\n /** The face outline, drawn as a non-interactive guide. */\n contour: { id: string; labelKey: string; d: string };\n zones: FaceZone[];\n /** Canonical anchors for landmark fitting / auto-detect. */\n landmarks: FaceLandmark[];\n /** Render the mesh horizontally mirrored (right profile = mirrored left). */\n mirror?: boolean;\n}\n\n// The side-profile contour is one of the profile seeds; the rest are the\n// clickable profile zones. They carry no `side` (a profile is single-sided),\n// so default it to 'midline' for the data-side hook.\nconst PROFILE_CONTOUR =\n PROFILE_ZONE_PATHS.find((z) => z.id === 'profileContour') ?? FRONT_CONTOUR;\nconst PROFILE_ZONES: FaceZone[] = PROFILE_ZONE_PATHS.filter(\n (z) => z.id !== 'profileContour',\n).map((z) => ({\n id: z.id,\n labelKey: z.labelKey,\n d: z.d,\n cx: z.cx ?? 0,\n cy: z.cy ?? 0,\n side: z.side ?? 'midline',\n}));\n\n// Canonical profile anchors on the reshaped side-profile mesh (the face faces +x).\n// A non-collinear EYE / NOSE-TIP / MOUTH triangle — exactly the visible-side\n// keypoints the YuNet profile detector returns, which (unlike the old collinear\n// nose-tip/nasion/subnasale/chin midline points) give the affine solver a\n// well-conditioned, shear-free fit. Because the profile mesh is TPS-reshaped to\n// sit on the canonical demo face, these coordinates are the detector's keypoints\n// *on that face* — so Auto-detect resolves to ~identity and preserves the fit\n// rather than re-distorting it. They double as the manual drag handles; the right\n// profile reuses them and mirrors the rendered result. See detect-face-yunet.ts.\nconst PROFILE_LANDMARKS: FaceLandmark[] = [\n { id: 'eye', labelKey: 'eye', x: 561, y: 374 },\n { id: 'nose-tip', labelKey: 'noseTip', x: 668, y: 432 },\n { id: 'mouth', labelKey: 'mouth', x: 592, y: 532 },\n];\n\nexport const FACE_VIEWS: Record<FaceViewId, FaceView> = {\n front: {\n id: 'front',\n labelKey: 'front',\n viewBox: FRONT_VIEWBOX,\n schematicViewBox: '152 103 502 842',\n meshContentBox: { x: 176, y: 127, width: 454, height: 794 },\n pivot: FRONT_PIVOT,\n contour: FRONT_CONTOUR,\n // The generator guarantees every clickable zone carries cx/cy/side.\n zones: FRONT_ZONES as FaceZone[],\n landmarks: FRONT_LANDMARKS,\n },\n // The reshaped profile zones face +x; the right profile is the same mesh\n // mirrored. Both fit on the eye/nose-tip/mouth anchors — auto-detect and manual\n // drag/sliders all work; the right profile mirrors the fit at render time.\n 'profile-left': {\n id: 'profile-left',\n labelKey: 'profileLeft',\n viewBox: FRONT_VIEWBOX,\n schematicViewBox: '359 189 287 475',\n meshContentBox: { x: 383, y: 213, width: 239, height: 427 },\n pivot: FRONT_PIVOT,\n contour: PROFILE_CONTOUR,\n zones: PROFILE_ZONES,\n landmarks: PROFILE_LANDMARKS,\n },\n 'profile-right': {\n id: 'profile-right',\n labelKey: 'profileRight',\n viewBox: FRONT_VIEWBOX,\n schematicViewBox: '162 189 287 475',\n meshContentBox: { x: 383, y: 213, width: 239, height: 427 },\n pivot: FRONT_PIVOT,\n contour: PROFILE_CONTOUR,\n zones: PROFILE_ZONES,\n landmarks: PROFILE_LANDMARKS,\n mirror: true,\n },\n};\n\nexport const FACE_VIEW_IDS: FaceViewId[] = [\n 'front',\n 'profile-left',\n 'profile-right',\n];\n\n/* ------------------------------------------------------------------ */\n/* Finding vocabulary — generic clinical annotations. */\n/* */\n/* Deliberately practice-neutral: the consumer maps these to its own */\n/* clinical meaning. The SHAPE is the accessible channel (WCAG 1.4.1); */\n/* tone is decorative reinforcement only. */\n/* ------------------------------------------------------------------ */\n\nexport type FaceFindingType = 'observation' | 'treatment' | 'concern' | 'note';\n\nexport const FACE_FINDING_TYPES: FaceFindingType[] = [\n 'observation',\n 'treatment',\n 'concern',\n 'note',\n];\n\nexport const FACE_FINDING_MARKER: Record<\n FaceFindingType,\n { shape: MarkerShape; tone: MarkerTone }\n> = {\n observation: { shape: 'circle', tone: 'info' },\n treatment: { shape: 'square', tone: 'success' },\n concern: { shape: 'triangle', tone: 'warning' },\n note: { shape: 'diamond', tone: 'neutral' },\n};\n\nexport interface FaceFinding {\n type: FaceFindingType;\n /** Optional free-text note (PHI — never surfaced in the agent snapshot). */\n note?: string;\n}\n\n/** Findings keyed by zone id. */\nexport type FaceChart = Record<string, FaceFinding[]>;\n\n/* ------------------------------------------------------------------ */\n/* Free-form annotations — positional drawing over the photo. */\n/* */\n/* Distinct from FaceChart (zone-keyed findings): these are freehand, */\n/* POSITIONAL marks in the photo's own viewBox space. They do NOT ride */\n/* the registration affine — the photo doesn't move when the zone mesh */\n/* is re-fitted, so a mark drawn on the cheek stays on the cheek. Kept */\n/* per-view, since each view carries its own photo. Text carries PHI. */\n/* ------------------------------------------------------------------ */\n\n/** The drawing tools the annotation layer exposes. */\nexport type FaceAnnotationTool =\n | 'marker'\n | 'pen'\n | 'highlighter'\n | 'arrow'\n | 'line'\n | 'rect'\n | 'ellipse'\n | 'text';\n\n/** Toolbar order. */\nexport const FACE_ANNOTATION_TOOLS: FaceAnnotationTool[] = [\n 'marker',\n 'pen',\n 'highlighter',\n 'arrow',\n 'line',\n 'rect',\n 'ellipse',\n 'text',\n];\n\n/** Shared fields on every annotation. `tone` is decorative reinforcement of the\n * KIND (shape / stroke style is the accessible channel), never colour alone. */\ninterface FaceAnnotationBase {\n /** Stable id — the kit generates one when the consumer doesn't supply it. */\n id: string;\n tone?: MarkerTone;\n /** Linked clinical zone — a zone id, `null` = assessed outside every zone,\n * `undefined` = never assessed. Sticky: not re-assessed on mesh re-fit. */\n zoneId?: string | null;\n}\n\n/** A shape glyph dropped at an arbitrary point (NOT snapped to a zone). */\nexport interface MarkerAnnotation extends FaceAnnotationBase {\n kind: 'marker';\n x: number;\n y: number;\n shape: MarkerShape;\n}\n/** A freehand stroke — `pen` (opaque, thin) or `highlighter` (translucent, wide). */\nexport interface InkAnnotation extends FaceAnnotationBase {\n kind: 'pen' | 'highlighter';\n points: Point[];\n}\n/** A two-point vector primitive drawn by dragging. */\nexport interface ShapeAnnotation extends FaceAnnotationBase {\n kind: 'arrow' | 'line' | 'rect' | 'ellipse';\n from: Point;\n to: Point;\n}\n/** A typed callout pinned to a point. `text` is PHI — never surfaced in the\n * agent snapshot, never persisted/logged/transmitted by the kit. */\nexport interface TextAnnotation extends FaceAnnotationBase {\n kind: 'text';\n x: number;\n y: number;\n text: string;\n}\n\nexport type FaceAnnotation =\n | MarkerAnnotation\n | InkAnnotation\n | ShapeAnnotation\n | TextAnnotation;\n\n/** The distinct annotation kinds — the agent snapshot reports counts per kind. */\nexport type FaceAnnotationKind = FaceAnnotation['kind'];\n\n/** An annotation as passed to `addAnnotation` — the `id` is optional (the kit\n * generates a stable one when omitted). */\nexport type FaceAnnotationInput =\n | (Omit<MarkerAnnotation, 'id'> & { id?: string })\n | (Omit<InkAnnotation, 'id'> & { id?: string })\n | (Omit<ShapeAnnotation, 'id'> & { id?: string })\n | (Omit<TextAnnotation, 'id'> & { id?: string });\n\n/** Annotations keyed by view — each view draws over its own photo. */\nexport type FaceAnnotations = Partial<Record<FaceViewId, FaceAnnotation[]>>;\n\n/** The annotation kind each tool produces. */\nexport const ANNOTATION_TOOL_KIND: Record<\n FaceAnnotationTool,\n FaceAnnotationKind\n> = {\n marker: 'marker',\n pen: 'pen',\n highlighter: 'highlighter',\n arrow: 'arrow',\n line: 'line',\n rect: 'rect',\n ellipse: 'ellipse',\n text: 'text',\n};\n\n/** True when the tool draws by dragging between two points. */\nexport function isShapeTool(tool: FaceAnnotationTool): boolean {\n return (\n tool === 'arrow' || tool === 'line' || tool === 'rect' || tool === 'ellipse'\n );\n}\n/** True when the tool captures a freehand point stream. */\nexport function isInkTool(tool: FaceAnnotationTool): boolean {\n return tool === 'pen' || tool === 'highlighter';\n}\n/** True when the tool places a single-click annotation (marker / text). */\nexport function isPointTool(tool: FaceAnnotationTool): boolean {\n return tool === 'marker' || tool === 'text';\n}\n\n/** SVG path `d` for a freehand point list (a polyline). Pure — no React/DOM. */\nexport function inkPath(points: Point[]): string {\n if (points.length === 0) return '';\n const first = points[0]!;\n if (points.length === 1) {\n // A dot — nudge so a round-capped zero-length stroke still paints.\n return `M ${first.x} ${first.y} L ${first.x + 0.01} ${first.y}`;\n }\n let d = `M ${first.x} ${first.y}`;\n for (let i = 1; i < points.length; i++) {\n const p = points[i]!;\n d += ` L ${p.x} ${p.y}`;\n }\n return d;\n}\n\n/** SVG path `d` for a two-point shape (arrowhead drawn separately). Pure. */\nexport function shapePath(\n kind: ShapeAnnotation['kind'],\n from: Point,\n to: Point,\n): string {\n switch (kind) {\n case 'line':\n case 'arrow':\n return `M ${from.x} ${from.y} L ${to.x} ${to.y}`;\n case 'rect': {\n const x = Math.min(from.x, to.x);\n const y = Math.min(from.y, to.y);\n const w = Math.abs(to.x - from.x);\n const h = Math.abs(to.y - from.y);\n return `M ${x} ${y} h ${w} v ${h} h ${-w} Z`;\n }\n case 'ellipse': {\n const cx = (from.x + to.x) / 2;\n const cy = (from.y + to.y) / 2;\n const rx = Math.abs(to.x - from.x) / 2;\n const ry = Math.abs(to.y - from.y) / 2;\n if (rx === 0 || ry === 0)\n return `M ${from.x} ${from.y} L ${to.x} ${to.y}`;\n return `M ${cx - rx} ${cy} a ${rx} ${ry} 0 1 0 ${2 * rx} 0 a ${rx} ${ry} 0 1 0 ${-2 * rx} 0 Z`;\n }\n }\n}\n\n/** SVG path `d` for a two-barb arrowhead at `to`, pointing along from→to. Pure. */\nexport function arrowHeadPath(from: Point, to: Point, size = 16): string {\n const dx = to.x - from.x;\n const dy = to.y - from.y;\n const len = Math.hypot(dx, dy) || 1;\n const ux = dx / len;\n const uy = dy / len;\n const ang = 0.5; // ~28° barbs\n const cos = Math.cos(ang);\n const sin = Math.sin(ang);\n const b1x = to.x - size * (ux * cos - uy * sin);\n const b1y = to.y - size * (uy * cos + ux * sin);\n const b2x = to.x - size * (ux * cos + uy * sin);\n const b2y = to.y - size * (uy * cos - ux * sin);\n return `M ${to.x} ${to.y} L ${b1x} ${b1y} M ${to.x} ${to.y} L ${b2x} ${b2y}`;\n}\n\n/** Axis-aligned bounding box of an annotation, in viewBox units. Pure. */\nexport function annotationBBox(a: FaceAnnotation): {\n x: number;\n y: number;\n width: number;\n height: number;\n} {\n switch (a.kind) {\n case 'marker':\n case 'text':\n return { x: a.x, y: a.y, width: 0, height: 0 };\n case 'pen':\n case 'highlighter': {\n if (a.points.length === 0) return { x: 0, y: 0, width: 0, height: 0 };\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const p of a.points) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n }\n default: {\n const minX = Math.min(a.from.x, a.to.x);\n const minY = Math.min(a.from.y, a.to.y);\n const maxX = Math.max(a.from.x, a.to.x);\n const maxY = Math.max(a.from.y, a.to.y);\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n }\n }\n}\n\n/** Bounding-box centre of an annotation — anchors its focus outline / label. */\nexport function annotationAnchor(a: FaceAnnotation): Point {\n switch (a.kind) {\n case 'marker':\n case 'text':\n return { x: a.x, y: a.y };\n case 'pen':\n case 'highlighter': {\n if (a.points.length === 0) return { x: 0, y: 0 };\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const p of a.points) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n return { x: (minX + maxX) / 2, y: (minY + maxY) / 2 };\n }\n default:\n return { x: (a.from.x + a.to.x) / 2, y: (a.from.y + a.to.y) / 2 };\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Selection hit geometry (pure). */\n/* ------------------------------------------------------------------ */\n\n/** Stroke width of an annotation's invisible pointer hit clone, in viewBox units. */\nexport const ANN_HIT_STROKE = 28;\n/** Pointer hit radius around a point annotation (marker), in viewBox units. */\nexport const ANN_HIT_RADIUS = 26;\n\nexport type AnnotationHitGeometry =\n | { type: 'stroke'; d: string }\n | { type: 'circle'; cx: number; cy: number; r: number }\n | { type: 'rect'; x: number; y: number; width: number; height: number };\n\n/** Geometry for an annotation's transparent pointer hit target. Stroke kinds\n * get a fat clone of their own path (hit on the stroke only — a hollow rect /\n * ellipse interior stays click-through to the zones); marker gets a hit\n * circle, text an estimated glyph box. Pure. */\nexport function annotationHitGeometry(\n a: FaceAnnotation,\n textSize = 30,\n): AnnotationHitGeometry {\n switch (a.kind) {\n case 'marker':\n return { type: 'circle', cx: a.x, cy: a.y, r: ANN_HIT_RADIUS };\n case 'pen':\n case 'highlighter':\n return { type: 'stroke', d: inkPath(a.points) };\n case 'arrow':\n case 'line':\n case 'rect':\n case 'ellipse':\n return { type: 'stroke', d: shapePath(a.kind, a.from, a.to) };\n case 'text': {\n // SVG text extent is unmeasurable purely — estimate from glyph count.\n const width = Math.max(60, a.text.length * textSize * 0.62);\n return {\n type: 'rect',\n x: a.x - ANN_HIT_RADIUS,\n y: a.y - textSize * 1.2,\n width: width + ANN_HIT_RADIUS,\n height: textSize * 1.7,\n };\n }\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Registration — 6-DOF affine maths (pure). */\n/* */\n/* A `FaceAffine` is the SVG matrix(a b c d e f): x' = a·x + c·y + e, */\n/* y' = b·x + d·y + f. Applied as a `transform` ATTRIBUTE on the mesh */\n/* group, so it never becomes an inline style. */\n/* ------------------------------------------------------------------ */\n\nexport type FaceAffine = readonly [\n number,\n number,\n number,\n number,\n number,\n number,\n];\n\nexport const IDENTITY_AFFINE: FaceAffine = [1, 0, 0, 1, 0, 0];\n\n/** Per-view registration matrices. */\nexport type FaceRegistration = Partial<Record<FaceViewId, FaceAffine>>;\n\nexport function affineToString(m: FaceAffine): string {\n return `matrix(${m[0]} ${m[1]} ${m[2]} ${m[3]} ${m[4]} ${m[5]})`;\n}\n\nexport function applyAffine(m: FaceAffine, p: Point): Point {\n return {\n x: m[0] * p.x + m[2] * p.y + m[4],\n y: m[1] * p.x + m[3] * p.y + m[5],\n };\n}\n\n/** Inverse of a (non-degenerate) affine: photo space → mesh space. Pure. */\nexport function invertAffine(m: FaceAffine): FaceAffine {\n const det = m[0] * m[3] - m[1] * m[2];\n const ia = m[3] / det;\n const ib = -m[1] / det;\n const ic = -m[2] / det;\n const id = m[0] / det;\n return [ia, ib, ic, id, -(ia * m[4] + ic * m[5]), -(ib * m[4] + id * m[5])];\n}\n\n/** Share of an auto-framed window the registered mesh occupies. 0.84 is the\n * front mesh's natural canvas fill, so the front keeps its full frame and\n * the profiles (smaller canvas share) zoom in to match it. */\nexport const AUTO_FRAME_FRACTION = 0.84;\n\n/**\n * Photo window that frames the registered mesh at a consistent size — the\n * three-up \"equal heads in equal cards\" window. Transforms `meshBox` through\n * `affine` (reflecting for the mirrored right profile), then returns a\n * canvas-aspect window centred on the mesh, sized so the mesh fills\n * `fraction` of it, shifted (never shrunk) to stay inside the canvas.\n * Falls back to the full canvas when the window cannot fit or the input is\n * degenerate. Pure; a window only — never a transform, so mesh, photo and\n * annotation geometry are untouched.\n */\nexport function autoFrameViewBox(\n meshBox: Box,\n affine: FaceAffine,\n canvas: { width: number; height: number },\n opts: { mirror?: boolean; fraction?: number } = {},\n): string {\n const full = `0 0 ${canvas.width} ${canvas.height}`;\n const fraction = opts.fraction ?? AUTO_FRAME_FRACTION;\n if (fraction <= 0 || fraction > 1) return full;\n const corners = [\n { x: meshBox.x, y: meshBox.y },\n { x: meshBox.x + meshBox.width, y: meshBox.y },\n { x: meshBox.x, y: meshBox.y + meshBox.height },\n { x: meshBox.x + meshBox.width, y: meshBox.y + meshBox.height },\n ].map((p) => applyAffine(affine, p));\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const p of corners) {\n minX = Math.min(minX, p.x);\n minY = Math.min(minY, p.y);\n maxX = Math.max(maxX, p.x);\n maxY = Math.max(maxY, p.y);\n }\n if (opts.mirror) {\n const mirroredMin = canvas.width - maxX;\n maxX = canvas.width - minX;\n minX = mirroredMin;\n }\n const bw = maxX - minX;\n const bh = maxY - minY;\n if (!Number.isFinite(minX + minY + bw + bh) || bw <= 0 || bh <= 0) {\n return full;\n }\n const aspect = canvas.width / canvas.height;\n const h = Math.max(bh / fraction, bw / fraction / aspect);\n const w = h * aspect;\n if (w > canvas.width || h > canvas.height) return full;\n const x = Math.min(Math.max(minX + bw / 2 - w / 2, 0), canvas.width - w);\n const y = Math.min(Math.max(minY + bh / 2 - h / 2, 0), canvas.height - h);\n return `${Math.round(x)} ${Math.round(y)} ${Math.round(w)} ${Math.round(h)}`;\n}\n\n/* ------------------------------------------------------------------ */\n/* User zoom / pan — a window composed over the base window */\n/* ------------------------------------------------------------------ */\n\n/** User zoom state: magnification `k` (1 = base window) plus the window\n * origin as fractions of the pannable range, so it survives base-window\n * changes (auto-frame recomputes, registration commits). */\nexport interface FaceZoomState {\n k: number;\n fx: number;\n fy: number;\n}\n\nexport const FACE_ZOOM_MIN = 1;\nexport const FACE_ZOOM_MAX = 8;\nexport const FACE_ZOOM_RESET: FaceZoomState = { k: 1, fx: 0.5, fy: 0.5 };\n\nconst clamp01 = (v: number) => Math.min(Math.max(v, 0), 1);\n\n/** Parse a `\"x y w h\"` viewBox string into a Box. */\nexport function parseViewBox(vb: string): Box {\n const [x = 0, y = 0, width = 0, height = 0] = vb.split(/\\s+/).map(Number);\n return { x, y, width, height };\n}\n\n/** Stringify a Box as a rounded viewBox value. */\nexport function boxToViewBox(b: Box): string {\n return `${Math.round(b.x)} ${Math.round(b.y)} ${Math.round(b.width)} ${Math.round(b.height)}`;\n}\n\n/** The visible window for a zoom state: the base window shrunk by `k`,\n * positioned by the fractional origin. `k <= 1` returns the base. */\nexport function composeZoomWindow(base: Box, z: FaceZoomState): Box {\n if (z.k <= 1) return base;\n const width = base.width / z.k;\n const height = base.height / z.k;\n return {\n x: base.x + z.fx * (base.width - width),\n y: base.y + z.fy * (base.height - height),\n width,\n height,\n };\n}\n\n/** Zoom by `factor` keeping the user-space point `p` fixed in the window.\n * Clamped to [FACE_ZOOM_MIN, FACE_ZOOM_MAX] and to the base bounds. */\nexport function zoomWindowAround(\n base: Box,\n z: FaceZoomState,\n p: { x: number; y: number },\n factor: number,\n): FaceZoomState {\n const k = Math.min(Math.max(z.k * factor, FACE_ZOOM_MIN), FACE_ZOOM_MAX);\n if (k <= 1) return FACE_ZOOM_RESET;\n if (k === z.k || !Number.isFinite(k)) return z;\n const cur = composeZoomWindow(base, z);\n const w = base.width / k;\n const h = base.height / k;\n const u = cur.width > 0 ? clamp01((p.x - cur.x) / cur.width) : 0.5;\n const v = cur.height > 0 ? clamp01((p.y - cur.y) / cur.height) : 0.5;\n const x = p.x - u * w;\n const y = p.y - v * h;\n const rangeX = base.width - w;\n const rangeY = base.height - h;\n return {\n k,\n fx: rangeX > 0 ? clamp01((x - base.x) / rangeX) : 0.5,\n fy: rangeY > 0 ? clamp01((y - base.y) / rangeY) : 0.5,\n };\n}\n\n/** Pan the zoom window by a user-space delta (drag the content by `dx,dy`\n * moves the window the opposite way), clamped to the base bounds. */\nexport function panZoomWindow(\n base: Box,\n z: FaceZoomState,\n dx: number,\n dy: number,\n): FaceZoomState {\n if (z.k <= 1) return z;\n const cur = composeZoomWindow(base, z);\n const rangeX = base.width - cur.width;\n const rangeY = base.height - cur.height;\n return {\n k: z.k,\n fx: rangeX > 0 ? clamp01((cur.x - dx - base.x) / rangeX) : 0.5,\n fy: rangeY > 0 ? clamp01((cur.y - dy - base.y) / rangeY) : 0.5,\n };\n}\n\n/** Editable decomposition of an affine about a pivot — what the numeric\n * registration panel exposes. Angles are degrees. */\nexport interface AffineParts {\n scaleX: number;\n scaleY: number;\n /** degrees */\n rotation: number;\n /** degrees */\n shear: number;\n translateX: number;\n translateY: number;\n}\n\nconst DEG = Math.PI / 180;\n\nexport function composeAffine(parts: AffineParts, pivot: Point): FaceAffine {\n const rad = parts.rotation * DEG;\n const ca = Math.cos(rad);\n const sa = Math.sin(rad);\n const k = Math.tan(parts.shear * DEG);\n const a = parts.scaleX * ca;\n const b = parts.scaleX * sa;\n const c = parts.scaleY * (k * ca - sa);\n const d = parts.scaleY * (k * sa + ca);\n const e = parts.translateX + pivot.x - (a * pivot.x + c * pivot.y);\n const f = parts.translateY + pivot.y - (b * pivot.x + d * pivot.y);\n return [a, b, c, d, e, f];\n}\n\nexport function decomposeAffine(m: FaceAffine, pivot: Point): AffineParts {\n const [a, b, c, d, e, f] = m;\n const scaleX = Math.hypot(a, b);\n const rotation = Math.atan2(b, a) / DEG;\n const det = a * d - b * c;\n const scaleY = scaleX === 0 ? 0 : det / scaleX;\n const shear = Math.atan2(a * c + b * d, det) / DEG;\n const translateX = e - pivot.x + (a * pivot.x + c * pivot.y);\n const translateY = f - pivot.y + (b * pivot.x + d * pivot.y);\n return { scaleX, scaleY, rotation, shear, translateX, translateY };\n}\n\n/**\n * Least-squares 6-DOF affine mapping `src` → `dst` (≥3 non-collinear pairs).\n * Independent horizontal + vertical scale fall out of the fit — this is the\n * shared solver behind both manual landmark drag and face-detector auto-fit.\n * Returns the identity if the system is degenerate.\n */\nexport function solveAffine(src: Point[], dst: Point[]): FaceAffine {\n const n = Math.min(src.length, dst.length);\n if (n < 3) return IDENTITY_AFFINE;\n let Sxx = 0;\n let Sxy = 0;\n let Sx = 0;\n let Syy = 0;\n let Sy = 0;\n let bx0 = 0;\n let bx1 = 0;\n let bx2 = 0;\n let by0 = 0;\n let by1 = 0;\n let by2 = 0;\n for (let i = 0; i < n; i++) {\n const s = src[i];\n const t = dst[i];\n if (!s || !t) continue;\n Sxx += s.x * s.x;\n Sxy += s.x * s.y;\n Sx += s.x;\n Syy += s.y * s.y;\n Sy += s.y;\n bx0 += t.x * s.x;\n bx1 += t.x * s.y;\n bx2 += t.x;\n by0 += t.y * s.x;\n by1 += t.y * s.y;\n by2 += t.y;\n }\n // 3×3 normal matrix N (symmetric); solve N·[a c e]ᵀ = bx and N·[b d f]ᵀ = by.\n const det =\n Sxx * (Syy * n - Sy * Sy) -\n Sxy * (Sxy * n - Sy * Sx) +\n Sx * (Sxy * Sy - Syy * Sx);\n if (Math.abs(det) < 1e-9) return IDENTITY_AFFINE;\n // Inverse of the symmetric 3×3, reused for both right-hand sides.\n const i00 = Syy * n - Sy * Sy;\n const i01 = Sx * Sy - Sxy * n;\n const i02 = Sxy * Sy - Sx * Syy;\n const i11 = Sxx * n - Sx * Sx;\n const i12 = Sx * Sxy - Sxx * Sy;\n const i22 = Sxx * Syy - Sxy * Sxy;\n const solve = (\n r0: number,\n r1: number,\n r2: number,\n ): [number, number, number] => [\n (i00 * r0 + i01 * r1 + i02 * r2) / det,\n (i01 * r0 + i11 * r1 + i12 * r2) / det,\n (i02 * r0 + i12 * r1 + i22 * r2) / det,\n ];\n const [a, c, e] = solve(bx0, bx1, bx2);\n const [b, d, f] = solve(by0, by1, by2);\n return [a, b, c, d, e, f];\n}\n","/* ------------------------------------------------------------------ */\n/* FaceScheme — patient-photo face-zone mapping (aesthetic medicine). */\n/* */\n/* A consumer-supplied patient photo renders as the <image> base; the */\n/* clinical face-zone mesh (byte-identical to the platform FaceMap) */\n/* floats on top as transparent CLICK HOTSPOTS with a crisp 1px outline. */\n/* Because the mesh is a canonical schematic and the photo is an */\n/* arbitrary face, the mesh is REGISTERED onto the photo with a 6-DOF */\n/* affine — independent horizontal/vertical scale, rotation, shear and */\n/* offset — driven by draggable landmark points, accessible numeric */\n/* sliders, or the optional in-kit face detector (lazy-loaded). Findings */\n/* are marked with the shared AnnotationMarker glyph (SHAPE carries the */\n/* meaning, never colour alone) and ride the registration transform. */\n/* */\n/* PHI: the kit is render-only. The photo arrives as a prop and is only */\n/* ever drawn into <image href>; it is never fetched, persisted, logged, */\n/* or exposed through the agent snapshot. The detector runs on-device. */\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type KeyboardEvent,\n type MouseEvent as ReactMouseEvent,\n type PointerEvent as ReactPointerEvent,\n type ReactElement,\n} from 'react';\nimport * as RadixTooltip from '@radix-ui/react-tooltip';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { useAgentRegistration } from '../../agent/registry';\nimport {\n AnnotationMarker,\n markerPath,\n MARKER_SHAPES,\n type MarkerShape,\n type MarkerTone,\n} from '../annotation-marker';\nimport {\n ArrowUpRight,\n Camera,\n Circle as CircleIcon,\n Columns3,\n Eraser,\n Highlighter,\n MapPin,\n Minus,\n MousePointer2,\n Pen,\n PencilRuler,\n Square as SquareIcon,\n Trash2,\n Type as TypeIcon,\n Maximize2,\n Undo2,\n Upload,\n ZoomIn,\n ZoomOut,\n UserRound,\n UserRoundArrowLeft,\n} from 'lucide-react';\nimport { Button, IconButton } from '../button';\nimport { ButtonGroup } from '../button-group';\nimport { Combobox, type ComboboxOption } from '../combobox';\nimport { IconButtonGroup } from '../icon-button-group';\nimport { TextInput } from '../text-input';\nimport { Card } from '../card';\nimport { Separator } from '../separator';\nimport { Slider } from '../slider';\nimport { Switch } from '../switch';\nimport { faceSchemeAgent } from './face-scheme.agent';\nimport { detectFaceLandmarks } from './detect-face-landmarks';\nimport { detectFaceYuNet } from './detect-face-yunet';\nimport {\n FACE_VIEWS,\n FACE_VIEW_IDS,\n FACE_FINDING_MARKER,\n FACE_FINDING_TYPES,\n FACE_ANNOTATION_TOOLS,\n IDENTITY_AFFINE,\n ANN_HIT_STROKE,\n affineToString,\n applyAffine,\n autoFrameViewBox,\n arrowHeadPath,\n annotationAnchor,\n annotationBBox,\n annotationHitGeometry,\n boxToViewBox,\n composeAffine,\n composeZoomWindow,\n invertAffine,\n decomposeAffine,\n FACE_ZOOM_MAX,\n FACE_ZOOM_RESET,\n panZoomWindow,\n parseViewBox,\n zoomWindowAround,\n inkPath,\n shapePath,\n solveAffine,\n type FaceAffine,\n type FaceZoomState,\n type FaceAnnotation,\n type FaceAnnotationInput,\n type FaceAnnotationKind,\n type FaceAnnotations,\n type FaceAnnotationTool,\n type FaceChart,\n type FaceFindingType,\n type FaceRegistration,\n type FaceViewId,\n type FaceZone,\n type Point,\n} from './face-scheme-data';\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport type FaceDetectStatus =\n | 'idle'\n | 'loading'\n | 'detecting'\n | 'done'\n | 'no-face'\n | 'error';\n\nexport interface FaceDetectOptions {\n /** FRONT view (MediaPipe): base URL for the wasm fileset (defaults to the jsDelivr CDN). */\n wasmBaseUrl?: string;\n /** FRONT view (MediaPipe): URL of the `face_landmarker.task` model (defaults to Google's CDN). */\n modelAssetPath?: string;\n /** PROFILE views (YuNet): ESM bundle URL for `onnxruntime-web` (defaults to the jsDelivr CDN). */\n ortModuleUrl?: string;\n /** PROFILE views (YuNet): base URL for the ORT wasm fileset (defaults to the jsDelivr CDN). */\n ortWasmBaseUrl?: string;\n /** PROFILE views (YuNet): URL of the YuNet `.onnx` model (defaults to the kit's bundled copy). */\n yunetModelUrl?: string;\n}\n\n/**\n * Reduce YuNet's five keypoints to the profile fit triangle. On a 90° profile\n * the contralateral eye / mouth-corner are hallucinated FORWARD (toward the\n * nose), so the VISIBLE ones are the keypoints farther from the nose tip in x.\n * The resulting eye / nose-tip / mouth ids match the profile `PROFILE_LANDMARKS`.\n */\nfunction profileTriangleFromYuNet(\n pairs: Array<{ id: string; photo: Point }>,\n): Array<{ id: string; photo: Point }> | null {\n const photoOf = (id: string) => pairs.find((p) => p.id === id)?.photo;\n const nose = photoOf('nose-tip');\n const rightEye = photoOf('right-eye');\n const leftEye = photoOf('left-eye');\n const rightMouth = photoOf('mouth-right');\n const leftMouth = photoOf('mouth-left');\n if (!nose || !rightEye || !leftEye || !rightMouth || !leftMouth) return null;\n const farther = (a: Point, b: Point) =>\n Math.abs(a.x - nose.x) >= Math.abs(b.x - nose.x) ? a : b;\n return [\n { id: 'eye', photo: farther(rightEye, leftEye) },\n { id: 'nose-tip', photo: nose },\n { id: 'mouth', photo: farther(rightMouth, leftMouth) },\n ];\n}\n\nexport interface FaceSchemeProps {\n /** Opaque instance id — emitted as `data-component-id` for the agent registry. */\n id?: string;\n /**\n * Consumer-supplied patient photo for the FRONT view (shorthand for\n * `viewPhotos.front`). RASTER ONLY (object-URL / `data:image` / app CDN\n * raster) — never an `.svg`. PHI: the kit renders it into an SVG\n * `<image href>` and does nothing else (no fetch, persist, log, transmit) and\n * never exposes `src` via the agent snapshot.\n */\n patientPhoto?: { src: string; altKey?: string };\n /** Per-view photos — each view shows its own image, swapped by the switcher. */\n viewPhotos?: Partial<Record<FaceViewId, { src: string; altKey?: string }>>;\n /** Controlled active view (`front` / `profile-left` / `profile-right`). */\n view?: FaceViewId;\n /** Uncontrolled initial view (default `'front'`). */\n defaultView?: FaceViewId;\n /** Fired when the view switcher changes the active view. */\n onViewChange?: (view: FaceViewId) => void;\n /** Show the built-in view switcher tabs (default `true`). */\n showViewSwitcher?: boolean;\n /** Uncontrolled initial layout — `'all'` opens in the three-up view (every\n * face at once, focused view interactive). Default `'single'`. Only takes\n * effect with the view switcher shown, which owns the layout buttons. */\n defaultLayout?: 'single' | 'all';\n /** `'interactive'` enables zone selection, finding edits and registration; `'display'` is read-only. */\n mode?: 'interactive' | 'display';\n /** Controlled findings — `Record<zoneId, FaceFinding[]>`. */\n value?: FaceChart;\n /** Uncontrolled initial findings. */\n defaultValue?: FaceChart;\n /** Fired whenever the chart changes. */\n onChange?: (next: FaceChart) => void;\n /** Fired when a zone is activated (click / Enter / Space). */\n onSelectZone?: (zoneId: string) => void;\n /** The finding type a zone-click applies in interactive mode (toggles it). */\n activeFinding?: FaceFindingType;\n /**\n * `'multi'` turns zone activation (click / Enter / Space) into selection\n * toggling — one diagnosis can then be applied to every selected zone at\n * once from the panel's Zones section, in a single `onChange` commit.\n * `activeFinding` no longer stamps in this mode (it only pre-arms the\n * section); the selection survives view switches. Default `'off'`.\n */\n zoneSelect?: 'off' | 'multi';\n /** Controlled selected zone ids (with `zoneSelect=\"multi\"`). */\n selectedZones?: string[];\n /** Uncontrolled initial selected zone ids. */\n defaultSelectedZones?: string[];\n /** Fired when the zone selection changes. */\n onSelectedZonesChange?: (ids: string[]) => void;\n /* ---- Free-form annotations (draw directly on the photo) ---- */\n /**\n * Controlled per-view annotations — freehand marks (point-anywhere markers,\n * pen / highlighter ink, arrows / lines / boxes / ellipses, text callouts)\n * drawn in the photo's own coordinate space. Distinct from the zone-keyed\n * `value` findings, and they do NOT ride the registration transform. PHI: a\n * text annotation's `text` is rendered only — never logged, persisted,\n * transmitted, or exposed via the agent snapshot.\n */\n annotations?: FaceAnnotations;\n /** Uncontrolled initial annotations. */\n defaultAnnotations?: FaceAnnotations;\n /** Fired whenever the annotations change. */\n onAnnotationsChange?: (next: FaceAnnotations) => void;\n /**\n * Fired when the annotation selection changes (`null` = cleared). Selection\n * is pointer-mode-scoped: it clears on tool or view change, and a freshly\n * committed mark auto-selects so its panel affordances target it at once.\n */\n onAnnotationSelect?: (id: string | null) => void;\n /**\n * Show the built-in Draw section (tool select, colour, marker shape, undo,\n * clear) inside the edit panel. Requires `mode=\"interactive\"`. Default\n * `true` — pass `false` to opt a surface out of the drawing tools.\n */\n showAnnotationToolbar?: boolean;\n /**\n * Opt into figure zoom + pan: mouse-wheel / panel-button zoom on the focused\n * figure, drag-pan from empty space while zoomed, plus a Zoom row in the edit\n * panel. Requires `mode=\"interactive\"`. Default `false` (MuscleScheme parity).\n */\n zoomable?: boolean;\n /**\n * Uncontrolled initial open state of the edit panel (Zones / Draw / Fit\n * sections). Default `true`: the panel is visible everywhere; the control-bar\n * toggle only collapses it.\n */\n defaultPanelOpen?: boolean;\n /** Controlled active drawing tool — `null` = none (pointer falls through to\n * zone selection / registration). */\n activeTool?: FaceAnnotationTool | null;\n /** Uncontrolled initial tool (default `null`). */\n defaultTool?: FaceAnnotationTool | null;\n /** Fired when the active tool changes (built-in toolbar or handle). */\n onToolChange?: (tool: FaceAnnotationTool | null) => void;\n /** Initial marker shape for the marker tool (default `'circle'`). */\n defaultAnnotationShape?: MarkerShape;\n /** Initial annotation tone (default `'accent'`). */\n defaultAnnotationColor?: MarkerTone;\n /** Controlled per-view registration affine. */\n registration?: FaceRegistration;\n /** Uncontrolled initial registration. */\n defaultRegistration?: FaceRegistration;\n /** Fired whenever the registration changes. */\n onRegistrationChange?: (next: FaceRegistration) => void;\n /** `'off'` hides the fit controls; `'adjust'` shows landmark handles + numeric sliders + auto-fit. */\n registrationMode?: 'off' | 'adjust';\n /**\n * Enable the in-kit, on-device face detector for Auto-fit. The front view\n * uses MediaPipe Face Landmarker; the two profile views use YuNet (which,\n * unlike the near-frontal FaceMesh, locates a 90° profile). Both runtimes and\n * their models are lazy-loaded only when detection actually runs, so nothing\n * weighs on the base bundle. Pass options to point at self-hosted models.\n */\n autoDetect?: boolean | FaceDetectOptions;\n /** Observe the detector lifecycle. */\n onDetectStatus?: (status: FaceDetectStatus) => void;\n /**\n * Opt-in: show an on-device photo-capture affordance — a live camera\n * viewfinder (with a file-upload fallback). The captured frame is rendered\n * into the same `<image>` base and emitted via `onCapture`; it is never\n * uploaded, persisted, or logged by the kit. The camera stream is torn down\n * the instant a frame is frozen and on cancel / unmount. Independent of\n * `mode` — set it wherever the practitioner should be able to (re)take the\n * photo.\n */\n allowCapture?: boolean;\n /** Camera to request for capture (default `'user'` — a face self-portrait). */\n captureFacingMode?: 'user' | 'environment';\n /**\n * Fired when a photo is captured or chosen — a `data:` URL, its intrinsic\n * pixel size, and the view it belongs to. PHI: the consumer owns persistence;\n * the kit only renders it.\n */\n onCapture?: (photo: {\n src: string;\n width: number;\n height: number;\n view: FaceViewId;\n }) => void;\n /** Show the finding-type legend below the figure. */\n legend?: boolean;\n /** Accessible label override for the chart region. */\n ariaLabel?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n}\n\nexport interface FaceSchemeHandle {\n /** Focus a zone by id. */\n focusZone: (zoneId: string) => void;\n /** Read the current chart state. */\n getChart: () => FaceChart;\n /** Read the findings on one zone (empty array if none). */\n getZone: (zoneId: string) => FaceChart[string];\n /** Read the zone ids carrying a given finding type. */\n zonesWith: (type: FaceFindingType) => string[];\n /** Add a finding to a zone (no-op if already present). */\n setFinding: (zoneId: string, type: FaceFindingType, note?: string) => void;\n /** Remove a finding type from a zone. */\n removeFinding: (zoneId: string, type: FaceFindingType) => void;\n /** Clear every finding from a zone. */\n clearZone: (zoneId: string) => void;\n /** Read the active-view registration affine. */\n getRegistration: () => FaceAffine;\n /** Set the active-view registration affine. */\n setRegistration: (m: FaceAffine) => void;\n /** Reset the active-view registration to the identity. */\n resetRegistration: () => void;\n /** Solve + apply an affine from canonical-anchor → photo-point pairs. */\n fitToLandmarks: (pairs: { id: string; photo: Point }[]) => void;\n /** Run the on-device detector on the current photo and auto-fit. Resolves\n * `true` on a successful fit, `false` if detection is disabled / finds no face. */\n detect: () => Promise<boolean>;\n /** Start the on-device camera viewfinder (no-op if capture is disabled or the\n * camera API is unavailable — emits an error status in that case). */\n startCapture: () => void;\n /** Stop the camera viewfinder without capturing. */\n cancelCapture: () => void;\n /** Read the active view id (`front` / `profile-left` / `profile-right`). */\n getView: () => FaceViewId;\n /** Switch the active view. */\n setView: (view: FaceViewId) => void;\n /** Read the current zoom factor (1 = base window). */\n getZoom: () => number;\n /** Set the zoom factor (clamped to 1–8), anchored on the window centre. */\n setZoom: (factor: number) => void;\n /** Reset zoom and pan to the base window. */\n resetZoom: () => void;\n /** Read the active-view annotations. */\n getAnnotations: () => FaceAnnotation[];\n /** Add an annotation to the active view; returns its (generated) id. */\n addAnnotation: (annotation: FaceAnnotationInput) => string;\n /** Remove an annotation from the active view by id. */\n removeAnnotation: (id: string) => void;\n /** Remove the most-recently-added annotation on the active view. */\n undoAnnotation: () => void;\n /** Clear every annotation from the active view. */\n clearAnnotations: () => void;\n /** Read the active drawing tool (`null` = none). */\n getTool: () => FaceAnnotationTool | null;\n /** Set the active drawing tool (`null` = none). */\n setTool: (tool: FaceAnnotationTool | null) => void;\n /** Read the selected annotation (id + kind), or `null` when none. */\n getSelectedAnnotation: () => { id: string; kind: FaceAnnotationKind } | null;\n /** Select an active-view annotation by id (`null` clears; unknown ids no-op). */\n selectAnnotation: (id: string | null) => void;\n /** Link / unlink an active-view annotation to a zone (`null` = no zone). */\n setAnnotationZone: (id: string, zoneId: string | null) => void;\n /** Read the selected zone ids (`zoneSelect=\"multi\"`). */\n getSelectedZones: () => string[];\n /** Replace the zone selection (any view's zone ids). */\n setSelectedZones: (ids: string[]) => void;\n /** Clear the zone selection. */\n clearZoneSelection: () => void;\n /** Add a finding to every selected zone in ONE chart commit; the optional\n * note lands only on zones the finding is newly added to. */\n applyFindingToSelection: (type: FaceFindingType, note?: string) => void;\n /** Remove a finding type from every selected zone in ONE chart commit. */\n removeFindingFromSelection: (type: FaceFindingType) => void;\n /** Selection-independent bulk write — add a finding to each given zone in\n * ONE chart commit (the agent `set_finding_bulk` path). */\n setFindingBulk: (ids: string[], type: FaceFindingType, note?: string) => void;\n}\n\n/* ------------------------------------------------------------------ */\n/* Capture (on-device camera) — privacy-first, mirrors DocumentScanner */\n/* ------------------------------------------------------------------ */\n\nexport type FaceCaptureState = 'idle' | 'requesting' | 'streaming' | 'error';\nexport type FaceCaptureError =\n | 'permission-denied'\n | 'no-camera'\n | 'not-readable'\n | 'insecure-context'\n | 'capture-failed';\n\n/** True when getUserMedia is reachable (secure context + API present). */\nfunction mediaDevicesAvailable(): boolean {\n return (\n typeof navigator !== 'undefined' &&\n typeof navigator.mediaDevices !== 'undefined' &&\n typeof navigator.mediaDevices.getUserMedia === 'function'\n );\n}\n\n/** Map a getUserMedia rejection (a DOMException) to our error kind. */\nfunction classifyMediaError(err: unknown): FaceCaptureError {\n const name = err instanceof Error ? err.name : '';\n if (name === 'NotAllowedError' || name === 'SecurityError')\n return 'permission-denied';\n if (name === 'NotFoundError' || name === 'OverconstrainedError')\n return 'no-camera';\n if (name === 'NotReadableError' || name === 'AbortError')\n return 'not-readable';\n return 'capture-failed';\n}\n\nconst CAPTURE_ERROR_KEY: Record<FaceCaptureError, string> = {\n 'permission-denied': 'faceScheme.capture.error.permissionDenied',\n 'no-camera': 'faceScheme.capture.error.noCamera',\n 'not-readable': 'faceScheme.capture.error.notReadable',\n 'insecure-context': 'faceScheme.capture.error.insecureContext',\n 'capture-failed': 'faceScheme.capture.error.captureFailed',\n};\n\n/* ------------------------------------------------------------------ */\n/* Tone → fill class (no inline styles; tokens only) */\n/* ------------------------------------------------------------------ */\n\nconst markerToneFill: Record<MarkerTone, string> = {\n neutral: 'ds:[fill:var(--muted-foreground)]',\n info: 'ds:[fill:var(--info)]',\n success: 'ds:[fill:var(--success)]',\n warning: 'ds:[fill:var(--warning)]',\n error: 'ds:[fill:var(--destructive)]',\n accent: 'ds:[fill:var(--accent)]',\n};\n\n// Annotation strokes reuse the same tone → token map. The annotation layer is\n// NOT inside the affine group, so strokes are in plain viewBox user units and\n// scale with the photo (no non-scaling-stroke needed).\nconst annotationToneStroke: Record<MarkerTone, string> = {\n neutral: 'ds:[stroke:var(--muted-foreground)]',\n info: 'ds:[stroke:var(--info)]',\n success: 'ds:[stroke:var(--success)]',\n warning: 'ds:[stroke:var(--warning)]',\n error: 'ds:[stroke:var(--destructive)]',\n accent: 'ds:[stroke:var(--accent)]',\n};\n\n// Annotation geometry, in the 808×944 viewBox's user units (calibrated to the\n// zone-marker r≈11 scale). Plain widths — the layer is not transformed.\nconst ANN_MARKER_R = 13;\nconst ANN_PEN_WIDTH = 5;\nconst ANN_HIGHLIGHTER_WIDTH = 24;\nconst ANN_SHAPE_WIDTH = 5;\nconst ANN_ARROW_HEAD = 26;\nconst ANN_TEXT_SIZE = 30;\nconst ANN_FOCUS_PAD = 14;\n\n// A stable empty list so a view with no annotations doesn't churn identity.\nconst EMPTY_ANNOTATIONS: FaceAnnotation[] = [];\n\n// Placeholder id for the in-progress draft (never committed as-is).\nconst DRAFT_ID = '__draft__';\n\n// Bar + three-up render order — Front centred between the two profiles.\n// Data-model order (FACE_VIEW_IDS) is unchanged; this is presentation only.\nconst VIEW_RENDER_ORDER: FaceViewId[] = [\n 'profile-left',\n 'front',\n 'profile-right',\n];\n\n// The profiles share one glyph; the right one is mirrored physically — an\n// anatomical direction, so it must not re-flip under RTL (no flipIconInRtl).\nconst VIEW_ICON: Record<FaceViewId, ReactElement> = {\n 'profile-left': <UserRoundArrowLeft aria-hidden=\"true\" />,\n front: <UserRound aria-hidden=\"true\" />,\n 'profile-right': (\n <UserRoundArrowLeft aria-hidden=\"true\" className=\"ds:-scale-x-100\" />\n ),\n};\n\n/** The toolbar's tool set, including a leading \"select\" (no drawing) tool. */\ntype ToolbarValue = 'select' | FaceAnnotationTool;\n\n/** lucide icon per tool for the built-in drawing toolbar. */\nconst TOOL_ICON: Record<ToolbarValue, typeof MapPin> = {\n select: MousePointer2,\n marker: MapPin,\n pen: Pen,\n highlighter: Highlighter,\n arrow: ArrowUpRight,\n line: Minus,\n rect: SquareIcon,\n ellipse: CircleIcon,\n text: TypeIcon,\n};\n\n/** Selectable annotation tones for the built-in colour picker. */\nconst ANNOTATION_TONES: MarkerTone[] = [\n 'accent',\n 'info',\n 'success',\n 'warning',\n 'error',\n 'neutral',\n];\n\n// One fill declaration per zone resolved through compoundVariants. The outline is\n// a constant 1px (non-scaling-stroke) so it stays crisp under the registration\n// scale. To keep dense meshes (the profile jaw, the 22-zone front) legible, an\n// unmarked zone's outline sits at a low stroke-opacity at rest and rises to full\n// on hover, on keyboard focus (see the wrapper's focus-visible rule), or when the\n// zone carries a finding; the fill reveals on the same triggers.\nconst zoneVariants = cva(\n [\n 'ds:[vector-effect:non-scaling-stroke]',\n 'ds:transition-[fill-opacity,stroke-opacity] ds:[transition-duration:var(--animation-duration)]',\n 'ds:[fill:transparent] ds:[stroke:var(--accent)] ds:[stroke-width:1] ds:[stroke-opacity:0.35]',\n ].join(' '),\n {\n variants: {\n interactive: { true: 'ds:cursor-pointer', false: '' },\n marked: { true: '', false: '' },\n selected: { true: '', false: '' },\n },\n compoundVariants: [\n {\n marked: false,\n interactive: true,\n class:\n 'ds:hover:[fill:var(--accent)] ds:hover:[fill-opacity:0.14] ds:hover:[stroke-opacity:1]',\n },\n {\n marked: true,\n class:\n 'ds:[fill:var(--accent)] ds:[fill-opacity:0.18] ds:[stroke-opacity:1]',\n },\n // Multi-select membership — a heavier outline than the marked tint so the\n // two states read apart even when they coincide on one zone.\n {\n selected: true,\n class:\n 'ds:[fill:var(--accent)] ds:[fill-opacity:0.16] ds:[stroke-opacity:0.9] ds:[stroke-width:2] ds:forced-colors:[stroke:Highlight]',\n },\n ],\n defaultVariants: { interactive: false, marked: false, selected: false },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nconst SLIDER_RANGES = {\n scaleX: { min: 0.3, max: 1.8, step: 0.01 },\n scaleY: { min: 0.3, max: 1.8, step: 0.01 },\n rotation: { min: -20, max: 20, step: 0.5 },\n shear: { min: -20, max: 20, step: 0.5 },\n translateX: { min: -240, max: 240, step: 1 },\n translateY: { min: -240, max: 240, step: 1 },\n} as const;\n\ntype SliderField = keyof typeof SLIDER_RANGES;\n// Order mirrors the 6 DOF the pointer-drag fit can reach, so the keyboard path\n// has full parity with the landmark handles (size → angle/skew → position).\nconst SLIDER_FIELDS: SliderField[] = [\n 'scaleX',\n 'scaleY',\n 'rotation',\n 'shear',\n 'translateX',\n 'translateY',\n];\n\n/* ------------------------------------------------------------------ */\n/* FaceScheme */\n/* ------------------------------------------------------------------ */\n\nexport const FaceScheme = forwardRef<FaceSchemeHandle, FaceSchemeProps>(\n (\n {\n id,\n patientPhoto,\n viewPhotos,\n view: viewProp,\n defaultView = 'front',\n onViewChange,\n showViewSwitcher = true,\n defaultLayout = 'single',\n mode = 'interactive',\n value,\n defaultValue,\n onChange,\n onSelectZone,\n activeFinding,\n zoneSelect = 'off',\n selectedZones: selectedZonesProp,\n defaultSelectedZones,\n onSelectedZonesChange,\n annotations,\n defaultAnnotations,\n onAnnotationsChange,\n onAnnotationSelect,\n showAnnotationToolbar = true,\n zoomable = false,\n defaultPanelOpen = true,\n activeTool,\n defaultTool = null,\n onToolChange,\n defaultAnnotationShape = 'circle',\n defaultAnnotationColor = 'accent',\n registration,\n defaultRegistration,\n onRegistrationChange,\n registrationMode = 'off',\n autoDetect,\n onDetectStatus,\n allowCapture = false,\n captureFacingMode = 'user',\n onCapture,\n legend = false,\n ariaLabel,\n className,\n },\n ref,\n ) => {\n const { t } = useTranslation();\n const reactId = useId();\n const instanceId = id ?? reactId;\n const rootRef = useRef<HTMLDivElement>(null);\n const svgRef = useRef<SVGSVGElement>(null);\n const videoRef = useRef<HTMLVideoElement>(null);\n const streamRef = useRef<MediaStream | null>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n // The persistent Take/Retake button — focus re-homes here when the\n // streaming viewfinder (which held focus) unmounts on capture / cancel.\n const captureButtonRef = useRef<HTMLButtonElement>(null);\n const unmountedRef = useRef(false);\n\n /* ---- Active view (controlled / uncontrolled, tab-driven) ---- */\n const isViewControlled = viewProp !== undefined;\n const [internalView, setInternalView] = useState<FaceViewId>(\n viewProp ?? defaultView,\n );\n const viewId = isViewControlled ? viewProp : internalView;\n const viewIdRef = useRef<FaceViewId>(viewId);\n viewIdRef.current = viewId;\n const setView = useCallback(\n (next: FaceViewId) => {\n if (!isViewControlled) setInternalView(next);\n onViewChange?.(next);\n },\n [isViewControlled, onViewChange],\n );\n\n // Whether the edit panel (Zones / Draw / Fit sections) is shown. Open by\n // default everywhere; the PencilRuler disclosure only collapses it.\n const [panelOpen, setPanelOpen] = useState(defaultPanelOpen);\n const panelId = `${reactId}-panel`;\n\n // Layout: 'single' shows the focused view (settings beside it); 'all' is the\n // three-up view showing every face at once (settings underneath). The\n // control bar's Front/Left/Right pick a single view; All switches to 'all'.\n const [layout, setLayout] = useState<'single' | 'all'>(defaultLayout);\n\n // Whether the finding legend card (below the figure) is shown — flipped by a\n // toggle inside the settings card. Only relevant when `legend` is enabled.\n const [showLegend, setShowLegend] = useState(true);\n\n const view = FACE_VIEWS[viewId];\n const [, , vbW, vbH] = view.viewBox.split(' ').map(Number) as [\n number,\n number,\n number,\n number,\n ];\n const interactive = mode === 'interactive';\n const adjusting = interactive && registrationMode === 'adjust';\n\n /* ---- Findings state (controlled / uncontrolled) ---- */\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState<FaceChart>(defaultValue ?? {});\n const chart = isControlled ? value : internal;\n const chartRef = useRef<FaceChart>(chart);\n chartRef.current = chart;\n\n const commitChart = useCallback(\n (next: FaceChart) => {\n if (!isControlled) setInternal(next);\n onChange?.(next);\n },\n [isControlled, onChange],\n );\n\n const addFinding = useCallback(\n (zoneId: string, type: FaceFindingType, note?: string) => {\n const current = chartRef.current[zoneId] ?? [];\n if (current.some((f) => f.type === type)) return;\n commitChart({\n ...chartRef.current,\n [zoneId]: [...current, { type, note }],\n });\n },\n [commitChart],\n );\n const removeFindingFn = useCallback(\n (zoneId: string, type: FaceFindingType) => {\n const current = chartRef.current[zoneId] ?? [];\n const next = current.filter((f) => f.type !== type);\n const copy = { ...chartRef.current };\n if (next.length > 0) copy[zoneId] = next;\n else delete copy[zoneId];\n commitChart(copy);\n },\n [commitChart],\n );\n const toggleFinding = useCallback(\n (zoneId: string, type: FaceFindingType) => {\n const has = (chartRef.current[zoneId] ?? []).some(\n (f) => f.type === type,\n );\n if (has) removeFindingFn(zoneId, type);\n else addFinding(zoneId, type);\n },\n [addFinding, removeFindingFn],\n );\n\n /* ---- Zone multi-selection (zoneSelect=\"multi\") ---- */\n const zoneSelectMode = interactive && zoneSelect === 'multi';\n const isZoneSelControlled = selectedZonesProp !== undefined;\n const [internalZoneSel, setInternalZoneSel] = useState<string[]>(\n defaultSelectedZones ?? [],\n );\n const zoneSelection = isZoneSelControlled\n ? selectedZonesProp\n : internalZoneSel;\n const zoneSelectionRef = useRef<string[]>(zoneSelection);\n zoneSelectionRef.current = zoneSelection;\n const zoneSelectionSet = useMemo(\n () => new Set(zoneSelection),\n [zoneSelection],\n );\n const commitZoneSelection = useCallback(\n (ids: string[]) => {\n // Eager ref update so same-tick sequential handle / agent calls\n // compose instead of reading a stale selection.\n if (!isZoneSelControlled) zoneSelectionRef.current = ids;\n if (!isZoneSelControlled) setInternalZoneSel(ids);\n onSelectedZonesChange?.(ids);\n },\n [isZoneSelControlled, onSelectedZonesChange],\n );\n const toggleZoneSelected = useCallback(\n (zoneId: string) => {\n const cur = zoneSelectionRef.current;\n commitZoneSelection(\n cur.includes(zoneId)\n ? cur.filter((z) => z !== zoneId)\n : [...cur, zoneId],\n );\n },\n [commitZoneSelection],\n );\n const clearZoneSelectionFn = useCallback(() => {\n if (zoneSelectionRef.current.length > 0) commitZoneSelection([]);\n }, [commitZoneSelection]);\n // Optional shared note typed in the Zones section — consumed (and cleared)\n // by the next bulk apply; it never mutates findings that already exist.\n const [bulkNote, setBulkNote] = useState('');\n\n // Bulk chart writes — the whole batch lands as ONE commit so controlled\n // consumers see a single onChange (never one per zone). The shared note\n // rides only on zones the finding is newly added to.\n const setFindingBulkFn = useCallback(\n (ids: string[], type: FaceFindingType, note?: string) => {\n const next = { ...chartRef.current };\n let changed = false;\n for (const zoneId of ids) {\n const cur = next[zoneId] ?? [];\n if (cur.some((f) => f.type === type)) continue;\n next[zoneId] = [...cur, { type, note }];\n changed = true;\n }\n if (changed) commitChart(next);\n },\n [commitChart],\n );\n const removeFindingBulkFn = useCallback(\n (ids: string[], type: FaceFindingType) => {\n const next = { ...chartRef.current };\n let changed = false;\n for (const zoneId of ids) {\n const cur = next[zoneId] ?? [];\n if (!cur.some((f) => f.type === type)) continue;\n const rest = cur.filter((f) => f.type !== type);\n if (rest.length > 0) next[zoneId] = rest;\n else delete next[zoneId];\n changed = true;\n }\n if (changed) commitChart(next);\n },\n [commitChart],\n );\n\n /* ---- Registration state (controlled / uncontrolled) ---- */\n const isRegControlled = registration !== undefined;\n const [internalReg, setInternalReg] = useState<FaceRegistration>(\n defaultRegistration ?? {},\n );\n const regMap = isRegControlled ? registration : internalReg;\n const activeAffine = regMap[viewId] ?? IDENTITY_AFFINE;\n const affineRef = useRef<FaceAffine>(activeAffine);\n affineRef.current = activeAffine;\n // Mirror of the full registration map so commits never read a stale closure.\n const affineRefMap = useRef<FaceRegistration>(regMap);\n affineRefMap.current = regMap;\n\n const commitReg = useCallback(\n (m: FaceAffine) => {\n const next = { ...affineRefMap.current, [viewId]: m };\n if (!isRegControlled) setInternalReg(next);\n onRegistrationChange?.(next);\n },\n [isRegControlled, onRegistrationChange, viewId],\n );\n\n const parts = useMemo(\n () => decomposeAffine(activeAffine, view.pivot),\n [activeAffine, view.pivot],\n );\n\n // The right-profile mesh is flipped about the frame centre at render time,\n // so landmark photo points (detector output, drag targets) must be flipped\n // to / from the un-mirrored space the affine is solved in. Self-inverse.\n const mirrorPt = useCallback(\n (p: Point): Point => (view.mirror ? { x: vbW - p.x, y: p.y } : p),\n [view.mirror, vbW],\n );\n\n /* ---- Landmark handle targets (pointer fitting) ---- */\n const [targets, setTargets] = useState<Point[]>(() =>\n view.landmarks.map((lm) => mirrorPt(applyAffine(activeAffine, lm))),\n );\n // Keep handles riding the mesh when the affine changes for any reason other\n // than an in-progress drag (slider, auto-fit, reset, external prop).\n const draggingRef = useRef<number | null>(null);\n // Auto-framed three-up window, frozen for the duration of a handle drag\n // so the photo doesn't zoom underfoot while the mesh is being fitted.\n // frameNowRef carries the current window (assigned each render, since the\n // drag handlers are declared before the layout state they'd close over).\n const [frozenFrame, setFrozenFrame] = useState<string | null>(null);\n const frameNowRef = useRef<string | null>(null);\n\n /* ---- User zoom / pan (opt-in) — a window composed over the base ---- */\n const [zoomState, setZoomState] = useState<FaceZoomState>(FACE_ZOOM_RESET);\n const zoomStateRef = useRef(zoomState);\n zoomStateRef.current = zoomState;\n // Base window (full canvas / auto-frame / schematic crop) as a string;\n // assigned each render at the focused-figure site, read by handlers.\n const baseWindowRef = useRef<string>(view.viewBox);\n const panRef = useRef<{ id: number; x: number; y: number } | null>(null);\n useEffect(() => {\n if (draggingRef.current !== null) return;\n setTargets(\n view.landmarks.map((lm) => mirrorPt(applyAffine(activeAffine, lm))),\n );\n }, [activeAffine, view.landmarks, mirrorPt]);\n\n const fitFromPairs = useCallback(\n (pairs: { id: string; photo: Point }[]) => {\n const src: Point[] = [];\n const dst: Point[] = [];\n for (const pair of pairs) {\n const anchor = view.landmarks.find((l) => l.id === pair.id);\n if (!anchor) continue;\n src.push({ x: anchor.x, y: anchor.y });\n dst.push(mirrorPt(pair.photo));\n }\n if (src.length >= 3) commitReg(solveAffine(src, dst));\n },\n [commitReg, view.landmarks, mirrorPt],\n );\n\n const toSvgPoint = useCallback(\n (clientX: number, clientY: number): Point => {\n const svg = svgRef.current;\n if (!svg) return { x: 0, y: 0 };\n const pt = svg.createSVGPoint();\n pt.x = clientX;\n pt.y = clientY;\n const ctm = svg.getScreenCTM();\n if (!ctm) return { x: 0, y: 0 };\n const local = pt.matrixTransform(ctm.inverse());\n return { x: local.x, y: local.y };\n },\n [],\n );\n\n // Zoom about the current window centre; base window read via ref so the\n // stable callbacks survive base changes (auto-frame, view, registration).\n const zoomAtCentre = (z: FaceZoomState, factor: number): FaceZoomState => {\n const base = parseViewBox(baseWindowRef.current);\n const cur = composeZoomWindow(base, z);\n return zoomWindowAround(\n base,\n z,\n { x: cur.x + cur.width / 2, y: cur.y + cur.height / 2 },\n factor,\n );\n };\n const zoomAtCentreRef = useRef(zoomAtCentre);\n zoomAtCentreRef.current = zoomAtCentre;\n const zoomBy = useCallback((factor: number) => {\n setZoomState((z) => zoomAtCentreRef.current(z, factor));\n }, []);\n const setZoomTo = useCallback((factor: number) => {\n setZoomState((z) =>\n zoomAtCentreRef.current(\n z,\n Number.isFinite(factor) && factor > 0 ? factor / z.k : 1,\n ),\n );\n }, []);\n const resetZoomFn = useCallback(() => setZoomState(FACE_ZOOM_RESET), []);\n const endPan = useCallback((e: ReactPointerEvent<SVGSVGElement>) => {\n if (!panRef.current || panRef.current.id !== e.pointerId) return;\n panRef.current = null;\n try {\n e.currentTarget.releasePointerCapture(e.pointerId);\n } catch {\n /* pointer already released */\n }\n }, []);\n\n const handlePointerDown = useCallback(\n (index: number) => (e: ReactPointerEvent<SVGCircleElement>) => {\n draggingRef.current = index;\n setFrozenFrame(frameNowRef.current);\n e.currentTarget.setPointerCapture(e.pointerId);\n },\n [],\n );\n const handlePointerMove = useCallback(\n (e: ReactPointerEvent<SVGCircleElement>) => {\n const index = draggingRef.current;\n if (index === null) return;\n const p = toSvgPoint(e.clientX, e.clientY);\n const next = targets.map((tg, i) => (i === index ? p : tg));\n setTargets(next);\n const src = view.landmarks.map((lm) => ({ x: lm.x, y: lm.y }));\n // `next` are rendered (possibly mirrored) positions — solve in\n // un-mirrored space so the mirror transform lands them back correctly.\n commitReg(solveAffine(src, next.map(mirrorPt)));\n },\n [targets, toSvgPoint, view.landmarks, commitReg, mirrorPt],\n );\n const handlePointerUp = useCallback(() => {\n draggingRef.current = null;\n setFrozenFrame(null);\n }, []);\n\n /* ---- Capture (on-device camera + file fallback) ---- */\n const [captureState, setCaptureState] = useState<FaceCaptureState>('idle');\n const [captureError, setCaptureError] = useState<FaceCaptureError | null>(\n null,\n );\n // Captured frames are keyed by view — each view keeps its own photo.\n const [capturedByView, setCapturedByView] = useState<\n Partial<Record<FaceViewId, string>>\n >({});\n // Per-view photo: explicit map wins, else `patientPhoto` is the front shorthand.\n const viewPhoto =\n viewPhotos?.[viewId] ?? (viewId === 'front' ? patientPhoto : undefined);\n // The captured frame supersedes the prop photo (uncontrolled-friendly).\n const effectiveSrc = capturedByView[viewId] ?? viewPhoto?.src;\n\n /* ---- Annotations (free-form drawing over the photo) ---- */\n const isAnnotationsControlled = annotations !== undefined;\n const [internalAnnotations, setInternalAnnotations] =\n useState<FaceAnnotations>(defaultAnnotations ?? {});\n const annMap = isAnnotationsControlled ? annotations : internalAnnotations;\n const annMapRef = useRef<FaceAnnotations>(annMap);\n annMapRef.current = annMap;\n const viewAnnotations = annMap[viewId] ?? EMPTY_ANNOTATIONS;\n\n const commitAnnotations = useCallback(\n (nextForView: FaceAnnotation[]) => {\n const next: FaceAnnotations = { ...annMapRef.current };\n if (nextForView.length > 0) next[viewIdRef.current] = nextForView;\n else delete next[viewIdRef.current];\n // Eager — same-tick sequential commits (e.g. two handle adds) compose\n // instead of clobbering; the render-time sync reasserts controlled state.\n annMapRef.current = next;\n if (!isAnnotationsControlled) setInternalAnnotations(next);\n onAnnotationsChange?.(next);\n },\n [isAnnotationsControlled, onAnnotationsChange],\n );\n\n // Monotonic id source for kit-generated annotation ids.\n const annIdRef = useRef(0);\n const nextAnnId = useCallback(\n () => `${instanceId}-a${(annIdRef.current += 1)}`,\n [instanceId],\n );\n\n /* ---- Selection (pointer select mode — no active tool) ---- */\n const [selectedAnnotationId, setSelectedAnnotationId] = useState<\n string | null\n >(null);\n const selectedAnnotationIdRef = useRef<string | null>(null);\n selectedAnnotationIdRef.current = selectedAnnotationId;\n const selectAnnotationFn = useCallback(\n (next: string | null) => {\n if (selectedAnnotationIdRef.current === next) return;\n selectedAnnotationIdRef.current = next;\n setSelectedAnnotationId(next);\n onAnnotationSelect?.(next);\n },\n [onAnnotationSelect],\n );\n\n // Photo space → mesh space is the render pipeline undone: un-mirror FIRST,\n // then the inverse affine. Asks the live zone paths in reverse document\n // order (SVG topmost-wins, matching click behaviour); jsdom lacks\n // isPointInFill, so the feature-detect degrades to null (unassigned).\n const hitTestZone = useCallback(\n (photoPoint: Point): string | null => {\n const svg = svgRef.current;\n if (!svg) return null;\n const meshPt = applyAffine(\n invertAffine(affineRef.current),\n mirrorPt(photoPoint),\n );\n const paths = svg.querySelectorAll<SVGGeometryElement>(\n '[data-zone] > path:first-of-type',\n );\n if (paths.length === 0 || typeof paths[0].isPointInFill !== 'function')\n return null;\n for (let i = paths.length - 1; i >= 0; i -= 1) {\n if (paths[i].isPointInFill({ x: meshPt.x, y: meshPt.y })) {\n const zoneEl = paths[i].closest<SVGGElement>('[data-zone]');\n return zoneEl?.getAttribute('data-zone') ?? null;\n }\n }\n return null;\n },\n [mirrorPt],\n );\n\n const addAnnotationFn = useCallback(\n (input: FaceAnnotationInput): string => {\n const newId = input.id ?? nextAnnId();\n const withId = { ...input, id: newId } as FaceAnnotation;\n // Auto-link to the zone under the anchor unless the caller already\n // assessed it (zoneId null / string). Sticky from here on.\n const ann: FaceAnnotation =\n withId.zoneId === undefined\n ? { ...withId, zoneId: hitTestZone(annotationAnchor(withId)) }\n : withId;\n const list = annMapRef.current[viewIdRef.current] ?? [];\n commitAnnotations([...list, ann]);\n // A fresh mark auto-selects so the panel's selection affordances\n // (delete / recolour / zone assignment) target it immediately.\n selectAnnotationFn(newId);\n return newId;\n },\n [commitAnnotations, nextAnnId, selectAnnotationFn, hitTestZone],\n );\n const removeAnnotationFn = useCallback(\n (annId: string) => {\n const list = annMapRef.current[viewIdRef.current] ?? [];\n if (list.some((a) => a.id === annId))\n commitAnnotations(list.filter((a) => a.id !== annId));\n },\n [commitAnnotations],\n );\n const setAnnotationZoneFn = useCallback(\n (annId: string, zoneId: string | null) => {\n const list = annMapRef.current[viewIdRef.current] ?? [];\n if (list.some((a) => a.id === annId))\n commitAnnotations(\n list.map((a) => (a.id === annId ? { ...a, zoneId } : a)),\n );\n },\n [commitAnnotations],\n );\n const undoAnnotationFn = useCallback(() => {\n const list = annMapRef.current[viewIdRef.current] ?? [];\n if (list.length > 0) commitAnnotations(list.slice(0, -1));\n }, [commitAnnotations]);\n const clearAnnotationsFn = useCallback(() => {\n if ((annMapRef.current[viewIdRef.current] ?? []).length > 0)\n commitAnnotations([]);\n }, [commitAnnotations]);\n\n /* ---- Active tool (controlled / uncontrolled) — inert unless interactive ---- */\n const isToolControlled = activeTool !== undefined;\n const [internalTool, setInternalTool] = useState<FaceAnnotationTool | null>(\n defaultTool,\n );\n const rawTool = isToolControlled ? activeTool : internalTool;\n const tool = interactive ? (rawTool ?? null) : null;\n const toolRef = useRef<FaceAnnotationTool | null>(tool);\n toolRef.current = tool;\n const setToolFn = useCallback(\n (next: FaceAnnotationTool | null) => {\n if (!isToolControlled) setInternalTool(next);\n onToolChange?.(next);\n },\n [isToolControlled, onToolChange],\n );\n\n /* ---- Current annotation style (built-in toolbar state) ---- */\n const [annShape, setAnnShape] = useState<MarkerShape>(\n defaultAnnotationShape,\n );\n const [annTone, setAnnTone] = useState<MarkerTone>(defaultAnnotationColor);\n const annShapeRef = useRef(annShape);\n annShapeRef.current = annShape;\n const annToneRef = useRef(annTone);\n annToneRef.current = annTone;\n\n /* ---- In-progress draft + text editing ---- */\n const [draft, setDraft] = useState<FaceAnnotation | null>(null);\n const draftRef = useRef<FaceAnnotation | null>(null);\n draftRef.current = draft;\n const drawingRef = useRef(false);\n const [editingTextId, setEditingTextId] = useState<string | null>(null);\n const editingTextIdRef = useRef<string | null>(null);\n editingTextIdRef.current = editingTextId;\n\n // The panel hosts the text-callout editor and the selection affordances —\n // auto-open it so an edit request never targets an unmounted field.\n useEffect(() => {\n if (editingTextId !== null) setPanelOpen(true);\n }, [editingTextId]);\n useEffect(() => {\n if (selectedAnnotationId !== null) setPanelOpen(true);\n }, [selectedAnnotationId]);\n // First zone joining the multi-selection opens the panel so the Zones\n // section (count + apply buttons) is visible when it becomes actionable.\n const prevZoneSelCount = useRef(zoneSelection.length);\n useEffect(() => {\n if (prevZoneSelCount.current === 0 && zoneSelection.length > 0)\n setPanelOpen(true);\n prevZoneSelCount.current = zoneSelection.length;\n }, [zoneSelection.length]);\n\n // Selection is pointer-mode-scoped: a tool or view CHANGE drops it (a\n // commit under the same tool keeps its auto-selection); a selected mark\n // that disappears (undo / clear / controlled prop) self-heals to null.\n const prevToolRef = useRef(tool);\n const prevViewRef = useRef(viewId);\n useEffect(() => {\n if (prevToolRef.current !== tool || prevViewRef.current !== viewId) {\n prevToolRef.current = tool;\n prevViewRef.current = viewId;\n selectAnnotationFn(null);\n }\n }, [tool, viewId, selectAnnotationFn]);\n useEffect(() => {\n const selId = selectedAnnotationIdRef.current;\n if (selId !== null && !viewAnnotations.some((a) => a.id === selId))\n selectAnnotationFn(null);\n }, [viewAnnotations, selectAnnotationFn]);\n\n // The draw surface is live when a tool is selected (interactive mode only).\n const drawingEnabled = tool !== null;\n\n const beginDraw = useCallback(\n (e: ReactPointerEvent<SVGRectElement>) => {\n const active = toolRef.current;\n if (!active) return;\n e.stopPropagation();\n const p = toSvgPoint(e.clientX, e.clientY);\n if (active === 'marker') {\n addAnnotationFn({\n kind: 'marker',\n x: p.x,\n y: p.y,\n shape: annShapeRef.current,\n tone: annToneRef.current,\n });\n return;\n }\n if (active === 'text') {\n const newId = addAnnotationFn({\n kind: 'text',\n x: p.x,\n y: p.y,\n text: '',\n tone: annToneRef.current,\n });\n setEditingTextId(newId);\n return;\n }\n e.currentTarget.setPointerCapture?.(e.pointerId);\n drawingRef.current = true;\n if (active === 'pen' || active === 'highlighter') {\n setDraft({\n id: DRAFT_ID,\n kind: active,\n points: [p],\n tone: annToneRef.current,\n });\n } else if (\n active === 'arrow' ||\n active === 'line' ||\n active === 'rect' ||\n active === 'ellipse'\n ) {\n setDraft({\n id: DRAFT_ID,\n kind: active,\n from: p,\n to: p,\n tone: annToneRef.current,\n });\n }\n },\n [toSvgPoint, addAnnotationFn],\n );\n\n const moveDraw = useCallback(\n (e: ReactPointerEvent<SVGRectElement>) => {\n if (!drawingRef.current) return;\n const p = toSvgPoint(e.clientX, e.clientY);\n setDraft((prev) => {\n if (!prev) return prev;\n if (prev.kind === 'pen' || prev.kind === 'highlighter')\n return { ...prev, points: [...prev.points, p] };\n if (\n prev.kind === 'arrow' ||\n prev.kind === 'line' ||\n prev.kind === 'rect' ||\n prev.kind === 'ellipse'\n )\n return { ...prev, to: p };\n return prev;\n });\n },\n [toSvgPoint],\n );\n\n const endDraw = useCallback(\n (e: ReactPointerEvent<SVGRectElement>) => {\n if (!drawingRef.current) return;\n drawingRef.current = false;\n e.currentTarget.releasePointerCapture?.(e.pointerId);\n const d = draftRef.current;\n setDraft(null);\n if (!d) return;\n // Discard a degenerate stroke / shape (a click that never moved).\n if (d.kind === 'pen' || d.kind === 'highlighter') {\n if (d.points.length < 2) return;\n } else if (\n d.kind === 'arrow' ||\n d.kind === 'line' ||\n d.kind === 'rect' ||\n d.kind === 'ellipse'\n ) {\n if (Math.hypot(d.to.x - d.from.x, d.to.y - d.from.y) < 4) return;\n }\n // Strip the draft id — addAnnotationFn assigns a real one.\n const { id: _draftId, ...rest } = d;\n void _draftId;\n addAnnotationFn(rest as FaceAnnotationInput);\n },\n [addAnnotationFn],\n );\n\n /* ---- Text-callout editing (panel field) ---- */\n const editingText = editingTextId\n ? viewAnnotations.find((a) => a.id === editingTextId && a.kind === 'text')\n : undefined;\n const updateEditingText = useCallback(\n (nextText: string) => {\n const id = editingTextIdRef.current;\n if (!id) return;\n const list = annMapRef.current[viewIdRef.current] ?? [];\n commitAnnotations(\n list.map((a) =>\n a.id === id && a.kind === 'text' ? { ...a, text: nextText } : a,\n ),\n );\n },\n [commitAnnotations],\n );\n const finishEditingText = useCallback(() => {\n const id = editingTextIdRef.current;\n setEditingTextId(null);\n if (!id) return;\n const list = annMapRef.current[viewIdRef.current] ?? [];\n const ann = list.find((a) => a.id === id);\n if (ann && ann.kind === 'text' && ann.text.trim() === '')\n commitAnnotations(list.filter((a) => a.id !== id));\n }, [commitAnnotations]);\n\n // Stream teardown — the single most important privacy path.\n const stopStream = useCallback(() => {\n streamRef.current?.getTracks().forEach((track) => track.stop());\n streamRef.current = null;\n const video = videoRef.current;\n if (video) video.srcObject = null;\n }, []);\n\n const cancelCapture = useCallback(() => {\n stopStream();\n setCaptureState('idle');\n }, [stopStream]);\n\n // Start the camera — user gesture only, never auto on mount.\n const startCapture = useCallback(async () => {\n if (!allowCapture) return;\n if (!mediaDevicesAvailable()) {\n setCaptureError('insecure-context');\n setCaptureState('error');\n return;\n }\n setCaptureError(null);\n setCaptureState('requesting');\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n video: { facingMode: captureFacingMode },\n audio: false,\n });\n // Guard an unmount between the permission prompt and resolution.\n if (unmountedRef.current) {\n stream.getTracks().forEach((track) => track.stop());\n return;\n }\n streamRef.current = stream;\n const video = videoRef.current;\n if (video) {\n try {\n video.srcObject = stream;\n } catch {\n /* some envs reject a non-native MediaStream on srcObject; the\n stream is still held + torn down correctly */\n }\n const playResult = video.play?.();\n if (playResult && typeof playResult.catch === 'function') {\n playResult.catch(() => {\n /* autoplay can reject silently; the Capture button still works */\n });\n }\n }\n setCaptureState('streaming');\n } catch (err: unknown) {\n stopStream();\n setCaptureError(classifyMediaError(err));\n setCaptureState('error');\n }\n }, [allowCapture, captureFacingMode, stopStream]);\n\n const commitCaptured = useCallback(\n (src: string, width: number, height: number) => {\n setCapturedByView((prev) => ({ ...prev, [viewId]: src }));\n onCapture?.({ src, width, height, view: viewId });\n },\n [onCapture, viewId],\n );\n\n // Freeze the current frame onto a canvas, release the camera, emit it.\n const capturePhoto = useCallback(() => {\n const video = videoRef.current;\n const vw = video?.videoWidth || video?.clientWidth || 0;\n const vh = video?.videoHeight || video?.clientHeight || 0;\n if (!video || video.readyState < 2 || vw === 0 || vh === 0) {\n setCaptureError('capture-failed');\n setCaptureState('error');\n return;\n }\n const canvas = document.createElement('canvas');\n canvas.width = vw;\n canvas.height = vh;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n setCaptureError('capture-failed');\n setCaptureState('error');\n return;\n }\n try {\n ctx.drawImage(video, 0, 0, vw, vh);\n } catch {\n setCaptureError('capture-failed');\n setCaptureState('error');\n return;\n }\n // Release the camera the instant the frame is frozen — LED goes dark.\n stopStream();\n commitCaptured(canvas.toDataURL('image/jpeg', 0.92), vw, vh);\n setCaptureState('idle');\n }, [stopStream, commitCaptured]);\n\n // File fallback (and the desktop path where no camera is wired up).\n const onPickFile = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (!file) return;\n const reader = new FileReader();\n reader.onload = () => {\n const src = typeof reader.result === 'string' ? reader.result : '';\n if (!src) return;\n const img = new Image();\n img.onload = () =>\n commitCaptured(src, img.naturalWidth, img.naturalHeight);\n img.onerror = () => commitCaptured(src, vbW, vbH);\n img.src = src;\n };\n reader.readAsDataURL(file);\n },\n [commitCaptured, vbW, vbH],\n );\n\n // Privacy: tear the camera down on unmount, whatever the phase.\n useEffect(() => {\n unmountedRef.current = false;\n return () => {\n unmountedRef.current = true;\n streamRef.current?.getTracks().forEach((track) => track.stop());\n streamRef.current = null;\n };\n }, []);\n\n const captureStreaming = captureState === 'streaming';\n\n // When the viewfinder tears down (capture / cancel), it unmounts the button\n // that held focus — re-home focus to the persistent Take/Retake button so a\n // keyboard user isn't dropped to <body>.\n const wasStreamingRef = useRef(false);\n useEffect(() => {\n if (wasStreamingRef.current && !captureStreaming) {\n captureButtonRef.current?.focus();\n }\n wasStreamingRef.current = captureStreaming;\n }, [captureStreaming]);\n\n /* ---- Detection ---- */\n const [detectStatus, setDetectStatus] = useState<FaceDetectStatus>('idle');\n const setStatus = useCallback(\n (s: FaceDetectStatus) => {\n setDetectStatus(s);\n onDetectStatus?.(s);\n },\n [onDetectStatus],\n );\n const runDetect = useCallback(async (): Promise<boolean> => {\n if (!autoDetect || !effectiveSrc || view.landmarks.length === 0)\n return false;\n const options = typeof autoDetect === 'object' ? autoDetect : {};\n const onStage = (stage: 'loading' | 'detecting') =>\n setStatus(stage === 'detecting' ? 'detecting' : 'loading');\n try {\n setStatus('loading');\n // FRONT: MediaPipe FaceMesh (accurate, non-collinear eyes/nose/chin).\n // PROFILE: MediaPipe collapses a 90° pose, so use YuNet and fit the mesh\n // on its visible-side EYE / NOSE-TIP / MOUTH triangle.\n let pairs: Array<{ id: string; photo: Point }> | null;\n if (view.id === 'front') {\n pairs = await detectFaceLandmarks(effectiveSrc, {\n viewWidth: vbW,\n viewHeight: vbH,\n onStage,\n wasmBaseUrl: options.wasmBaseUrl,\n modelAssetPath: options.modelAssetPath,\n });\n } else {\n const raw = await detectFaceYuNet(effectiveSrc, {\n viewWidth: vbW,\n viewHeight: vbH,\n onStage,\n ortModuleUrl: options.ortModuleUrl,\n ortWasmBaseUrl: options.ortWasmBaseUrl,\n modelUrl: options.yunetModelUrl,\n });\n pairs = raw && profileTriangleFromYuNet(raw);\n }\n if (!pairs || pairs.length < 3) {\n setStatus('no-face');\n return false;\n }\n fitFromPairs(pairs);\n setStatus('done');\n return true;\n } catch {\n setStatus('error');\n return false;\n }\n }, [\n autoDetect,\n effectiveSrc,\n view.id,\n view.landmarks,\n vbW,\n vbH,\n setStatus,\n fitFromPairs,\n ]);\n\n /* ---- Imperative handle + agent registration ---- */\n const focusZoneEl = useCallback((zoneId: string) => {\n rootRef.current\n ?.querySelector<SVGGElement>(`[data-zone=\"${zoneId}\"]`)\n ?.focus();\n }, []);\n\n const handle = useMemo<FaceSchemeHandle>(\n () => ({\n focusZone: focusZoneEl,\n getChart: () => chartRef.current,\n getZone: (zoneId) => chartRef.current[zoneId] ?? [],\n zonesWith: (type) =>\n Object.entries(chartRef.current)\n .filter(([, findings]) => findings.some((f) => f.type === type))\n .map(([zoneId]) => zoneId),\n setFinding: addFinding,\n removeFinding: removeFindingFn,\n clearZone: (zoneId) => {\n if (!chartRef.current[zoneId]) return;\n const copy = { ...chartRef.current };\n delete copy[zoneId];\n commitChart(copy);\n },\n getRegistration: () => affineRef.current,\n setRegistration: (m) => commitReg(m),\n resetRegistration: () => commitReg(IDENTITY_AFFINE),\n fitToLandmarks: fitFromPairs,\n detect: runDetect,\n startCapture: () => void startCapture(),\n cancelCapture,\n getView: () => viewIdRef.current,\n getZoom: () => zoomStateRef.current.k,\n setZoom: setZoomTo,\n resetZoom: resetZoomFn,\n setView,\n getAnnotations: () => annMapRef.current[viewIdRef.current] ?? [],\n addAnnotation: addAnnotationFn,\n removeAnnotation: removeAnnotationFn,\n undoAnnotation: undoAnnotationFn,\n clearAnnotations: clearAnnotationsFn,\n getTool: () => toolRef.current,\n setTool: setToolFn,\n getSelectedAnnotation: () => {\n const selId = selectedAnnotationIdRef.current;\n if (selId === null) return null;\n const a = (annMapRef.current[viewIdRef.current] ?? []).find(\n (x) => x.id === selId,\n );\n return a ? { id: a.id, kind: a.kind } : null;\n },\n selectAnnotation: (selId) => {\n if (selId === null) {\n selectAnnotationFn(null);\n return;\n }\n const list = annMapRef.current[viewIdRef.current] ?? [];\n if (list.some((x) => x.id === selId)) selectAnnotationFn(selId);\n },\n setAnnotationZone: setAnnotationZoneFn,\n getSelectedZones: () => zoneSelectionRef.current,\n setSelectedZones: (ids) => commitZoneSelection([...ids]),\n clearZoneSelection: clearZoneSelectionFn,\n applyFindingToSelection: (type, note) =>\n setFindingBulkFn(zoneSelectionRef.current, type, note),\n removeFindingFromSelection: (type) =>\n removeFindingBulkFn(zoneSelectionRef.current, type),\n setFindingBulk: setFindingBulkFn,\n }),\n [\n focusZoneEl,\n addFinding,\n removeFindingFn,\n commitChart,\n commitReg,\n fitFromPairs,\n runDetect,\n startCapture,\n cancelCapture,\n setView,\n addAnnotationFn,\n removeAnnotationFn,\n undoAnnotationFn,\n clearAnnotationsFn,\n setToolFn,\n selectAnnotationFn,\n setAnnotationZoneFn,\n commitZoneSelection,\n clearZoneSelectionFn,\n setFindingBulkFn,\n removeFindingBulkFn,\n setZoomTo,\n resetZoomFn,\n ],\n );\n useImperativeHandle(ref, () => handle, [handle]);\n useAgentRegistration(faceSchemeAgent, handle, instanceId);\n\n /* ---- Zone label ---- */\n const zoneLabel = useCallback(\n (zone: FaceZone): string => {\n const name = t(`faceScheme.zone.${zone.labelKey}`);\n const findings = chartRef.current[zone.id] ?? [];\n if (findings.length === 0) return name;\n const findingNames = findings\n .map((f) => t(`faceScheme.finding.${f.type}`))\n .join(', ');\n return t('faceScheme.zoneWithFindings', {\n zone: name,\n findings: findingNames,\n });\n },\n [t],\n );\n\n const handleActivate = useCallback(\n (zone: FaceZone) => {\n onSelectZone?.(zone.id);\n // Multi-select: activation toggles membership and never stamps —\n // `activeFinding` only pre-arms the panel's Zones section.\n if (zoneSelectMode) toggleZoneSelected(zone.id);\n else if (interactive && activeFinding)\n toggleFinding(zone.id, activeFinding);\n },\n [\n interactive,\n zoneSelectMode,\n toggleZoneSelected,\n activeFinding,\n toggleFinding,\n onSelectZone,\n ],\n );\n\n const photoAlt = viewPhoto?.altKey\n ? t(viewPhoto.altKey)\n : t('faceScheme.photo.defaultAlt');\n\n // Right profile = left mesh mirrored horizontally about the frame centre.\n const meshTransform = view.mirror\n ? `translate(${vbW} 0) scale(-1 1) ${affineToString(activeAffine)}`\n : affineToString(activeAffine);\n\n const updatePart = useCallback(\n (field: SliderField, val: number) => {\n commitReg(composeAffine({ ...parts, [field]: val }, view.pivot));\n },\n [commitReg, parts, view.pivot],\n );\n\n // Auto-detect runs wherever the active view has fit landmarks (all three\n // views do — the front uses eye/nose/chin, the profiles use midline\n // cephalometric points the detector tracks even on a 90° profile).\n const detectEnabled =\n Boolean(autoDetect) && Boolean(effectiveSrc) && view.landmarks.length > 0;\n // Capture is its own opt-in — available regardless of `mode` so the\n // practitioner can (re)take the photo on any surface that allows it.\n const captureEnabled = allowCapture;\n\n /* ---- Render ---- */\n const hasViewSwitcher = showViewSwitcher && FACE_VIEW_IDS.length > 1;\n // The edit panel (Draw section + Fit overlay section, one Card) sits beside\n // the figure on wide viewports in the single-view layout, and stacks\n // underneath in the three-up layout (where the figures already fill the\n // row). The joined control bar (view buttons + capture + the panel toggle)\n // rides above the figure and never counts toward the side panel.\n const annotationToolbarEnabled = interactive && showAnnotationToolbar;\n const effectiveZoomable = interactive && zoomable;\n const panelAvailable =\n zoneSelectMode ||\n annotationToolbarEnabled ||\n adjusting ||\n effectiveZoomable;\n const hasSidePanel = panelOpen && panelAvailable;\n // Three-up (all views at once) is only reachable when the switcher is on.\n const isThreeUp = layout === 'all' && hasViewSwitcher;\n\n // User zoom resets on view switch, on toggling the capability, and when\n // the camera viewfinder takes over the figure.\n useEffect(() => {\n setZoomState(FACE_ZOOM_RESET);\n }, [viewId, effectiveZoomable]);\n useEffect(() => {\n if (captureStreaming) setZoomState(FACE_ZOOM_RESET);\n }, [captureStreaming]);\n\n // Wheel zoom — non-passive so preventDefault stops page scroll; anchored\n // on the pointer. Re-attached after layout/view remounts of the svg node.\n useEffect(() => {\n const svg = svgRef.current;\n if (!svg || !effectiveZoomable) return;\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n const p = toSvgPoint(e.clientX, e.clientY);\n setZoomState((z) =>\n zoomWindowAround(\n parseViewBox(baseWindowRef.current),\n z,\n p,\n e.deltaY < 0 ? 1.15 : 1 / 1.15,\n ),\n );\n };\n svg.addEventListener('wheel', onWheel, { passive: false });\n return () => svg.removeEventListener('wheel', onWheel);\n }, [effectiveZoomable, toSvgPoint, isThreeUp, viewId, captureStreaming]);\n // The panel sits beside the figure only in the single-view layout; in\n // three-up it always drops underneath the (full-width) figure row.\n const sideBeside = hasSidePanel && !isThreeUp;\n // Single-view + panel: keep the figure and the panel as a tight, centred\n // pair (the figure column is sized to the photo, not stretched flex-1, so\n // the panel sits immediately beside the photo rather than floating off at\n // the far right). `items-stretch` makes the panel match the figure's height.\n const containerClass = sideBeside\n ? 'ds:flex ds:flex-col ds:gap-[var(--spacing-md)] ds:lg:flex-row ds:lg:items-stretch ds:lg:justify-center'\n : 'ds:flex ds:flex-col ds:gap-[var(--spacing-md)]';\n const figureColClass = sideBeside\n ? 'ds:flex ds:w-full ds:min-w-0 ds:flex-col ds:gap-[var(--spacing-sm)] ds:lg:w-[28rem] ds:lg:shrink-0'\n : 'ds:flex ds:w-full ds:min-w-0 ds:flex-col ds:gap-[var(--spacing-sm)]';\n const sidePanelClass = sideBeside\n ? 'ds:flex ds:w-full ds:flex-col ds:gap-[var(--spacing-md)] ds:lg:w-[28rem] ds:lg:shrink-0 ds:lg:self-stretch'\n : 'ds:flex ds:w-full ds:flex-col ds:gap-[var(--spacing-md)]';\n // Twin-card geometry: beside the figure the panel matches its height —\n // `h-0 min-h-full` stops panel content growing the row; the body scrolls.\n const panelCardClass = sideBeside\n ? 'ds:lg:h-0 ds:lg:min-h-full'\n : undefined;\n const panelBodyClass = sideBeside\n ? 'ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:lg:min-h-0 ds:lg:flex-1 ds:lg:overflow-y-auto'\n : 'ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]';\n\n // The control bar renders when it has any content: the view buttons (when\n // the switcher is on), the capture buttons (when opted in), or the panel\n // toggle (whenever the edit panel has at least one section to show).\n const showViewButtons = hasViewSwitcher;\n const barHasContent = showViewButtons || captureEnabled || panelAvailable;\n\n // Disclosure toggle for the edit panel — rides in the control bar (outside\n // the Card it shows/hides). Keyed so it can sit in the bar's flat child\n // array beside the view / capture buttons.\n const panelToggle = panelAvailable ? (\n <IconButton\n key=\"panel\"\n size=\"sm\"\n icon={<PencilRuler aria-hidden=\"true\" />}\n aria-label={t('faceScheme.panel.toggle')}\n aria-expanded={panelOpen}\n aria-controls={panelOpen ? panelId : undefined}\n data-overflow-pin\n onClick={() => setPanelOpen((open) => !open)}\n />\n ) : null;\n\n // Draw section of the edit panel — tool select (incl. a leading\n // \"select\"/no-tool), colour, marker shape (marker tool only), the\n // text-callout editor, and undo / clear. Each picker group carries a small\n // visible label (aria-labelledby, not aria-label) and hugs its content\n // (self-start) instead of stretching to the card width.\n const toolbarValue: ToolbarValue = tool ?? 'select';\n const drawLabelId = `${reactId}-draw`;\n const fitLabelId = `${reactId}-fit`;\n const zoomLabelId = `${reactId}-zoom`;\n const toolLabelId = `${reactId}-tools`;\n const toneLabelId = `${reactId}-tones`;\n const shapeLabelId = `${reactId}-shapes`;\n const zoneRowLabelId = `${reactId}-ann-zone`;\n const selectedAnnotation =\n selectedAnnotationId !== null\n ? viewAnnotations.find((a) => a.id === selectedAnnotationId)\n : undefined;\n const zoneOptions: ComboboxOption[] = view.zones.map((z) => ({\n value: z.id,\n label: t(`faceScheme.zone.${z.labelKey}`),\n }));\n const panelLabelClass =\n 'ds:text-[length:var(--font-size-xs)] ds:font-medium ds:text-[var(--muted-foreground)]';\n const zonesLabelId = `${reactId}-zones`;\n const zonesApplyLabelId = `${reactId}-zones-apply`;\n // Zones section of the edit panel — the multi-select flow: a live count of\n // the selected zones, one batched toggle per finding type (not-all-have →\n // add to every selected zone; all-have → remove from all), an optional\n // shared note for the newly-added findings, and clear-selection.\n const zonesSection = zoneSelectMode ? (\n <div\n data-testid=\"face-scheme-zones\"\n role=\"group\"\n aria-labelledby={zonesLabelId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <span id={zonesLabelId} className={panelLabelClass}>\n {t('faceScheme.zonesPanel.label')}\n </span>\n <p className=\"ds:m-0 ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)]\">\n {t('faceScheme.zonesPanel.hint')}\n </p>\n <span\n aria-live=\"polite\"\n className=\"ds:text-[length:var(--font-size-xs)] ds:text-[var(--foreground)]\"\n >\n {t('faceScheme.zonesPanel.selectedTotal', {\n n: zoneSelection.length,\n })}\n </span>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span id={zonesApplyLabelId} className={panelLabelClass}>\n {t('faceScheme.zonesPanel.applyLabel')}\n </span>\n <div\n role=\"group\"\n aria-labelledby={zonesApplyLabelId}\n className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-xs)]\"\n >\n {FACE_FINDING_TYPES.map((type) => {\n const m = FACE_FINDING_MARKER[type];\n const allHave =\n zoneSelection.length > 0 &&\n zoneSelection.every((zid) =>\n (chart[zid] ?? []).some((f) => f.type === type),\n );\n return (\n <Button\n key={type}\n size=\"sm\"\n intent=\"outline\"\n aria-pressed={allHave}\n disabled={zoneSelection.length === 0}\n startIcon={\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d={markerPath(m.shape, 12, 12, 9)}\n className={markerToneFill[m.tone]}\n />\n </svg>\n }\n onClick={() => {\n if (allHave) {\n removeFindingBulkFn(zoneSelectionRef.current, type);\n } else {\n const note = bulkNote.trim();\n setFindingBulkFn(\n zoneSelectionRef.current,\n type,\n note === '' ? undefined : note,\n );\n setBulkNote('');\n }\n }}\n >\n {t(`faceScheme.finding.${type}`)}\n </Button>\n );\n })}\n </div>\n </div>\n <TextInput\n aria-label={t('faceScheme.zonesPanel.noteLabel')}\n placeholder={t('faceScheme.zonesPanel.notePlaceholder')}\n value={bulkNote}\n onChange={(e) => setBulkNote(e.target.value)}\n />\n <Button\n size=\"sm\"\n intent=\"outline\"\n className=\"ds:self-start\"\n onClick={clearZoneSelectionFn}\n disabled={zoneSelection.length === 0}\n >\n {t('faceScheme.zonesPanel.clearSelection')}\n </Button>\n </div>\n ) : null;\n const drawSection = annotationToolbarEnabled ? (\n <div\n data-testid=\"face-scheme-toolbar\"\n role=\"group\"\n aria-labelledby={drawLabelId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <span id={drawLabelId} className={panelLabelClass}>\n {t('faceScheme.panel.draw')}\n </span>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span id={toolLabelId} className={panelLabelClass}>\n {t('faceScheme.annotate.toolLabel')}\n </span>\n <IconButtonGroup\n role=\"radiogroup\"\n mode=\"toggle-single\"\n size=\"sm\"\n aria-labelledby={toolLabelId}\n className=\"ds:self-start\"\n value={toolbarValue}\n onValueChange={(v) =>\n setToolFn(v === 'select' ? null : (v as FaceAnnotationTool))\n }\n >\n {(['select', ...FACE_ANNOTATION_TOOLS] as ToolbarValue[]).map(\n (tv) => {\n const Icon = TOOL_ICON[tv];\n return (\n <IconButton\n key={tv}\n value={tv}\n icon={<Icon aria-hidden=\"true\" />}\n aria-label={t(`faceScheme.annotate.tool.${tv}`)}\n />\n );\n },\n )}\n </IconButtonGroup>\n </div>\n\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span id={toneLabelId} className={panelLabelClass}>\n {t('faceScheme.annotate.colorLabel')}\n </span>\n <IconButtonGroup\n role=\"radiogroup\"\n mode=\"toggle-single\"\n size=\"sm\"\n aria-labelledby={toneLabelId}\n className=\"ds:self-start\"\n value={annTone}\n onValueChange={(v) => {\n const nextTone = v as MarkerTone;\n setAnnTone(nextTone);\n // The picker doubles as the selected mark's tone editor.\n const selId = selectedAnnotationIdRef.current;\n if (selId !== null) {\n const list = annMapRef.current[viewIdRef.current] ?? [];\n if (list.some((x) => x.id === selId))\n commitAnnotations(\n list.map((x) =>\n x.id === selId ? { ...x, tone: nextTone } : x,\n ),\n );\n }\n }}\n >\n {ANNOTATION_TONES.map((toneOpt) => (\n <IconButton\n key={toneOpt}\n value={toneOpt}\n icon={\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <circle\n cx={8}\n cy={8}\n r={6}\n className={markerToneFill[toneOpt]}\n />\n </svg>\n }\n aria-label={t(`faceScheme.annotate.tone.${toneOpt}`)}\n />\n ))}\n </IconButtonGroup>\n </div>\n\n {tool === 'marker' && (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span id={shapeLabelId} className={panelLabelClass}>\n {t('faceScheme.annotate.shapeLabel')}\n </span>\n <IconButtonGroup\n role=\"radiogroup\"\n mode=\"toggle-single\"\n size=\"sm\"\n aria-labelledby={shapeLabelId}\n className=\"ds:self-start\"\n value={annShape}\n onValueChange={(v) => setAnnShape(v as MarkerShape)}\n >\n {MARKER_SHAPES.map((shapeOpt) => (\n <IconButton\n key={shapeOpt}\n value={shapeOpt}\n icon={\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d={markerPath(shapeOpt, 12, 12, 9)}\n className=\"ds:[fill:currentColor]\"\n />\n </svg>\n }\n aria-label={t(`annotationMarker.shape.${shapeOpt}`)}\n />\n ))}\n </IconButtonGroup>\n </div>\n )}\n\n {editingText && editingText.kind === 'text' && (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <TextInput\n aria-label={t('faceScheme.annotate.textLabel')}\n placeholder={t('faceScheme.annotate.textPlaceholder')}\n value={editingText.text}\n // eslint-disable-next-line jsx-a11y/no-autofocus -- focuses the text-callout editor so the note can be typed immediately after the marker is placed\n autoFocus\n onChange={(e) => updateEditingText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === 'Escape') {\n e.preventDefault();\n finishEditingText();\n }\n }}\n />\n <Button size=\"sm\" intent=\"primary\" onClick={finishEditingText}>\n {t('faceScheme.annotate.textDone')}\n </Button>\n </div>\n )}\n\n {selectedAnnotation && (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span id={zoneRowLabelId} className={panelLabelClass}>\n {t('faceScheme.annotate.zoneLabel')}\n </span>\n <span\n aria-live=\"polite\"\n className=\"ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)] ds:empty:hidden\"\n >\n {selectedAnnotation.zoneId === null\n ? t('faceScheme.annotate.outsideZonesHint')\n : null}\n </span>\n <Combobox\n size=\"sm\"\n options={zoneOptions}\n value={selectedAnnotation.zoneId ?? ''}\n clearable\n placeholder={\n selectedAnnotation.zoneId == null\n ? t('faceScheme.annotate.zoneNone')\n : t('faceScheme.annotate.zonePlaceholder')\n }\n aria-label={t('faceScheme.annotate.zoneLabel')}\n onValueChange={(v) =>\n setAnnotationZoneFn(selectedAnnotation.id, v === '' ? null : v)\n }\n />\n </div>\n )}\n\n <div className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-xs)]\">\n <Button\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Eraser aria-hidden=\"true\" />}\n onClick={() => {\n const selId = selectedAnnotationIdRef.current;\n if (selId !== null) removeAnnotationFn(selId);\n }}\n disabled={selectedAnnotationId === null}\n >\n {t('faceScheme.annotate.deleteSelected')}\n </Button>\n <Button\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Undo2 aria-hidden=\"true\" />}\n onClick={undoAnnotationFn}\n disabled={viewAnnotations.length === 0}\n >\n {t('faceScheme.annotate.undo')}\n </Button>\n <Button\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Trash2 aria-hidden=\"true\" />}\n onClick={clearAnnotationsFn}\n disabled={viewAnnotations.length === 0}\n >\n {t('faceScheme.annotate.clear')}\n </Button>\n </div>\n </div>\n ) : null;\n\n // Accessible name for a committed annotation (text folds in its content;\n // a linked zone folds in its name).\n const annotationLabel = (a: FaceAnnotation): string => {\n const base =\n a.kind === 'text'\n ? a.text.trim()\n ? t('faceScheme.annotate.labelText', { text: a.text })\n : t('faceScheme.annotate.kind.text')\n : t(`faceScheme.annotate.kind.${a.kind}`);\n if (!a.zoneId) return base;\n const zone = view.zones.find((z) => z.id === a.zoneId);\n if (!zone) return base;\n return t('faceScheme.annotate.labelWithZone', {\n label: base,\n zone: t(`faceScheme.zone.${zone.labelKey}`),\n });\n };\n\n // The SVG visual for one annotation (committed or draft). Colour rides a\n // token class; all other stroke props are SVG presentation attributes (not\n // inline styles) in the photo's own viewBox units.\n const renderAnnotationVisual = (a: FaceAnnotation) => {\n const tone: MarkerTone = a.tone ?? 'accent';\n switch (a.kind) {\n case 'marker':\n return (\n <path\n d={markerPath(a.shape, a.x, a.y, ANN_MARKER_R)}\n className={markerToneFill[tone]}\n pointerEvents=\"none\"\n />\n );\n case 'pen':\n case 'highlighter':\n return (\n <path\n d={inkPath(a.points)}\n fill=\"none\"\n strokeWidth={\n a.kind === 'highlighter' ? ANN_HIGHLIGHTER_WIDTH : ANN_PEN_WIDTH\n }\n strokeOpacity={a.kind === 'highlighter' ? 0.35 : 1}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={annotationToneStroke[tone]}\n pointerEvents=\"none\"\n />\n );\n case 'arrow':\n return (\n <g className={annotationToneStroke[tone]} pointerEvents=\"none\">\n <path\n d={shapePath('arrow', a.from, a.to)}\n fill=\"none\"\n strokeWidth={ANN_SHAPE_WIDTH}\n strokeLinecap=\"round\"\n />\n <path\n d={arrowHeadPath(a.from, a.to, ANN_ARROW_HEAD)}\n fill=\"none\"\n strokeWidth={ANN_SHAPE_WIDTH}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n );\n case 'line':\n case 'rect':\n case 'ellipse':\n return (\n <path\n d={shapePath(a.kind, a.from, a.to)}\n fill=\"none\"\n strokeWidth={ANN_SHAPE_WIDTH}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={annotationToneStroke[tone]}\n pointerEvents=\"none\"\n />\n );\n case 'text':\n if (!a.text.trim())\n // Empty (being placed) — a small crosshair placeholder.\n return (\n <path\n d={`M ${a.x - 10} ${a.y} H ${a.x + 10} M ${a.x} ${a.y - 10} V ${a.y + 10}`}\n strokeWidth={ANN_SHAPE_WIDTH}\n strokeLinecap=\"round\"\n className={annotationToneStroke[tone]}\n pointerEvents=\"none\"\n />\n );\n return (\n <text\n x={a.x}\n y={a.y}\n fontSize={ANN_TEXT_SIZE}\n paintOrder=\"stroke\"\n strokeWidth={6}\n strokeLinejoin=\"round\"\n className={`${markerToneFill[tone]} ds:[stroke:var(--background)] ds:[font-family:var(--font-sans)] ds:[font-weight:500]`}\n pointerEvents=\"none\"\n >\n {a.text}\n </text>\n );\n }\n };\n\n // Transparent pointer hit target — an SVG <g> is only hit through its\n // children and every visual child is pointer-events:none, so each committed\n // mark gets a fat invisible stroke clone (stroke kinds — hollow interiors\n // stay click-through) or a fill target (marker / text). jsdom cannot\n // hit-test SVG; tests assert this contract structurally.\n const renderAnnotationHit = (a: FaceAnnotation) => {\n const hit = annotationHitGeometry(a, ANN_TEXT_SIZE);\n switch (hit.type) {\n case 'stroke':\n return (\n <path\n data-annotation-hit=\"\"\n d={hit.d}\n fill=\"none\"\n stroke=\"transparent\"\n strokeWidth={ANN_HIT_STROKE}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n pointerEvents=\"stroke\"\n className=\"ds:cursor-pointer\"\n />\n );\n case 'circle':\n return (\n <circle\n data-annotation-hit=\"\"\n cx={hit.cx}\n cy={hit.cy}\n r={hit.r}\n fill=\"transparent\"\n pointerEvents=\"fill\"\n className=\"ds:cursor-pointer\"\n />\n );\n case 'rect':\n return (\n <rect\n data-annotation-hit=\"\"\n x={hit.x}\n y={hit.y}\n width={hit.width}\n height={hit.height}\n fill=\"transparent\"\n pointerEvents=\"fill\"\n className=\"ds:cursor-pointer\"\n />\n );\n }\n };\n\n // Auto-framed window for the focused three-up photo tile: mesh-normalised\n // so all three heads read at matching size in equal cards. A handle drag\n // renders the frozen window captured at drag start instead.\n const focusedFrame =\n isThreeUp && effectiveSrc\n ? autoFrameViewBox(\n view.meshContentBox,\n activeAffine,\n { width: vbW, height: vbH },\n { mirror: view.mirror },\n )\n : null;\n frameNowRef.current = focusedFrame;\n\n // Base window for the focused figure (photo frame / schematic crop / full\n // canvas), with the user zoom window composed over it when zoomed in.\n const baseWindow = effectiveSrc\n ? (frozenFrame ?? focusedFrame ?? view.viewBox)\n : isThreeUp || !adjusting\n ? view.schematicViewBox\n : view.viewBox;\n baseWindowRef.current = baseWindow;\n const zoomedIn = effectiveZoomable && zoomState.k > 1;\n const zoomedWindow = zoomedIn\n ? boxToViewBox(composeZoomWindow(parseViewBox(baseWindow), zoomState))\n : baseWindow;\n const panEligible = zoomedIn && tool === null;\n\n // The registered SVG figure, parameterised by view. The focused view\n // (`vid === viewId`) renders the full interactive figure (handles + draw\n // surface + draft + pointer handlers, driven by the active-view state); any\n // other view — only shown in the three-up layout — renders a read-only,\n // clickable preview that focuses the view when activated (no handles, draw\n // surface, or draft; its SVG is aria-hidden behind the labelled button).\n const renderFigure = (vid: FaceViewId) => {\n if (vid !== viewId) {\n const v = FACE_VIEWS[vid];\n const previewPhoto =\n viewPhotos?.[vid] ?? (vid === 'front' ? patientPhoto : undefined);\n const previewSrc = capturedByView[vid] ?? previewPhoto?.src;\n const previewAffine = regMap[vid] ?? IDENTITY_AFFINE;\n const previewMesh = v.mirror\n ? `translate(${vbW} 0) scale(-1 1) ${affineToString(previewAffine)}`\n : affineToString(previewAffine);\n const previewAnnotations = annMap[vid] ?? EMPTY_ANNOTATIONS;\n return (\n <Card variant=\"elevated\" interactive asChild>\n <button\n type=\"button\"\n data-testid=\"face-scheme-preview\"\n data-view-preview={vid}\n aria-label={t(`faceScheme.view.${v.labelKey}`)}\n onClick={() => setView(vid)}\n className=\"ds:mx-auto ds:block ds:w-full ds:min-w-0 ds:max-w-[28rem] ds:appearance-none ds:p-0 ds:transition-opacity ds:[transition-duration:var(--animation-duration)] ds:hover:opacity-90\"\n >\n <svg\n viewBox={\n previewSrc\n ? autoFrameViewBox(\n v.meshContentBox,\n previewAffine,\n { width: vbW, height: vbH },\n { mirror: v.mirror },\n )\n : v.schematicViewBox\n }\n aria-hidden=\"true\"\n className=\"ds:block ds:h-auto ds:w-full\"\n >\n {previewSrc && (\n <image\n href={previewSrc}\n x={0}\n y={0}\n width={vbW}\n height={vbH}\n preserveAspectRatio=\"xMidYMid slice\"\n />\n )}\n {/* Registered mesh — read-only zones (no interaction/tooltip). */}\n <g transform={previewMesh}>\n {v.zones.map((zone) => {\n const findings = chart[zone.id] ?? [];\n const marked = findings.length > 0;\n return (\n <g key={zone.id}>\n <path\n d={zone.d}\n className={zoneVariants({\n interactive: false,\n marked,\n // Cross-view selection stays visible on the\n // three-up previews (decorative, aria-hidden svg).\n selected:\n zoneSelectMode && zoneSelectionSet.has(zone.id),\n })}\n />\n {findings.map((f, i) => {\n const m = FACE_FINDING_MARKER[f.type];\n const offset = (i - (findings.length - 1) / 2) * 26;\n return (\n <path\n key={f.type}\n d={markerPath(\n m.shape,\n zone.cx + offset,\n zone.cy,\n 11,\n )}\n className={markerToneFill[m.tone]}\n />\n );\n })}\n </g>\n );\n })}\n </g>\n {/* Committed annotations — visual only (no focus targets). */}\n <g>\n {previewAnnotations.map((a) => (\n <g key={a.id}>{renderAnnotationVisual(a)}</g>\n ))}\n </g>\n </svg>\n </button>\n </Card>\n );\n }\n return (\n <RadixTooltip.Provider delayDuration={200}>\n <Card\n variant=\"elevated\"\n data-testid=\"face-scheme-figure\"\n data-focused={isThreeUp ? 'true' : undefined}\n className={\n isThreeUp\n ? // Accent border marks the active tile in the three-up row\n // (2px width doubles as the non-colour cue; ~3.2:1 ≥ 3:1).\n 'ds:mx-auto ds:w-full ds:max-w-[28rem] ds:border-2 ds:border-[color:var(--accent)] ds:forced-colors:border-[Highlight]'\n : 'ds:mx-auto ds:w-full ds:max-w-[28rem]'\n }\n >\n <svg\n ref={svgRef}\n data-testid=\"face-scheme-svg\"\n viewBox={zoomedWindow}\n role=\"group\"\n aria-label={t(`faceScheme.view.${view.labelKey}`)}\n className={\n panEligible\n ? 'ds:block ds:h-auto ds:w-full ds:touch-none ds:cursor-grab'\n : 'ds:block ds:h-auto ds:w-full ds:touch-none'\n }\n onPointerDown={\n interactive\n ? (e: ReactPointerEvent<SVGSVGElement>) => {\n const el = e.target as Element;\n // Pointer-down anywhere off a mark clears the selection.\n if (\n selectedAnnotationIdRef.current !== null &&\n !el.closest?.('[data-annotation]')\n )\n selectAnnotationFn(null);\n // Pan from empty space while zoomed in with no tool\n // active; interactive children keep their clicks.\n if (\n panEligible &&\n !el.closest?.(\n '[data-zone],[data-annotation],[data-annotation-hit],[data-testid=\"face-scheme-handles\"]',\n )\n ) {\n panRef.current = {\n id: e.pointerId,\n x: e.clientX,\n y: e.clientY,\n };\n try {\n e.currentTarget.setPointerCapture(e.pointerId);\n } catch {\n /* capture is an enhancement — pan works without it */\n }\n }\n }\n : undefined\n }\n onPointerMove={\n effectiveZoomable\n ? (e: ReactPointerEvent<SVGSVGElement>) => {\n const pan = panRef.current;\n if (!pan || pan.id !== e.pointerId) return;\n const rect = e.currentTarget.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return;\n const base = parseViewBox(baseWindowRef.current);\n const cur = composeZoomWindow(base, zoomStateRef.current);\n const dx = ((e.clientX - pan.x) * cur.width) / rect.width;\n const dy =\n ((e.clientY - pan.y) * cur.height) / rect.height;\n panRef.current = {\n id: pan.id,\n x: e.clientX,\n y: e.clientY,\n };\n setZoomState((z) => panZoomWindow(base, z, dx, dy));\n }\n : undefined\n }\n onPointerUp={effectiveZoomable ? endPan : undefined}\n onPointerCancel={effectiveZoomable ? endPan : undefined}\n onKeyDown={\n zoneSelectMode\n ? (e: KeyboardEvent<SVGSVGElement>) => {\n // A mark's own Escape stops propagation, so reaching\n // here means only the zone selection is left to clear.\n if (e.key === 'Escape') clearZoneSelectionFn();\n }\n : undefined\n }\n >\n {effectiveSrc && (\n <image\n href={effectiveSrc}\n x={0}\n y={0}\n width={vbW}\n height={vbH}\n preserveAspectRatio=\"xMidYMid slice\"\n role=\"img\"\n aria-label={photoAlt}\n />\n )}\n\n {/* Registered mesh — the affine maps the canonical zones onto the photo. */}\n <g transform={meshTransform}>\n {view.zones.map((zone) => {\n const findings = chart[zone.id] ?? [];\n const marked = findings.length > 0;\n const zoneSelected =\n zoneSelectMode && zoneSelectionSet.has(zone.id);\n return (\n <RadixTooltip.Root key={zone.id}>\n <RadixTooltip.Trigger asChild>\n <g\n data-zone={zone.id}\n data-side={zone.side}\n data-zone-selected={zoneSelected ? 'true' : undefined}\n role={interactive || onSelectZone ? 'button' : 'img'}\n aria-label={zoneLabel(zone)}\n // One meaning per mode: multi-select → pressed =\n // selected; stamp mode → pressed = carries the armed\n // finding.\n aria-pressed={\n zoneSelectMode\n ? zoneSelected\n : interactive && activeFinding\n ? marked\n : undefined\n }\n // Suppress the UA focus box on the <g>; draw the ring on the\n // zone path itself. forced-colors re-asserts a system stroke.\n className=\"ds:outline-none ds:[&:focus-visible>*:first-child]:[stroke:var(--ring)] ds:[&:focus-visible>*:first-child]:[stroke-width:var(--focus-ring-width)] ds:[&:focus-visible>*:first-child]:[stroke-opacity:1] ds:forced-colors:[&:focus-visible>*:first-child]:[stroke:CanvasText]\"\n tabIndex={interactive || onSelectZone ? 0 : -1}\n onClick={() => handleActivate(zone)}\n onKeyDown={(e: KeyboardEvent<SVGGElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleActivate(zone);\n } else if (e.key === 'Escape' && zoneSelectMode) {\n clearZoneSelectionFn();\n }\n }}\n >\n <path\n d={zone.d}\n className={zoneVariants({\n interactive,\n marked,\n selected: zoneSelected,\n })}\n />\n {findings.map((f, i) => {\n const m = FACE_FINDING_MARKER[f.type];\n const offset = (i - (findings.length - 1) / 2) * 26;\n return (\n <path\n key={f.type}\n d={markerPath(\n m.shape,\n zone.cx + offset,\n zone.cy,\n 11,\n )}\n aria-hidden=\"true\"\n className={markerToneFill[m.tone]}\n />\n );\n })}\n </g>\n </RadixTooltip.Trigger>\n <RadixTooltip.Portal>\n <RadixTooltip.Content\n sideOffset={4}\n className=\"ds:z-50 ds:rounded-[var(--radius-sm)] ds:bg-[var(--popover)] ds:px-2 ds:py-1 ds:text-[length:var(--font-size-xs)] ds:text-[var(--popover-foreground)] ds:shadow-[var(--shadow-md)]\"\n >\n {zoneLabel(zone)}\n <RadixTooltip.Arrow className=\"ds:[fill:var(--popover)]\" />\n </RadixTooltip.Content>\n </RadixTooltip.Portal>\n </RadixTooltip.Root>\n );\n })}\n </g>\n\n {/* Free-form annotation layer — in the photo's own viewBox space,\n OUTSIDE the mesh transform, so marks stay pinned to the photo when\n the zone overlay is re-fitted. */}\n <g data-testid=\"face-scheme-annotations\">\n {viewAnnotations.map((a) => {\n const bbox = annotationBBox(a);\n const selected = selectedAnnotationId === a.id;\n return (\n <g\n key={a.id}\n data-annotation={a.id}\n data-annotation-kind={a.kind}\n data-annotation-zone={a.zoneId ?? undefined}\n data-selected={selected ? 'true' : undefined}\n role={interactive ? 'button' : 'img'}\n aria-label={annotationLabel(a)}\n aria-pressed={interactive ? selected : undefined}\n tabIndex={interactive ? 0 : -1}\n className=\"ds:outline-none ds:[&:focus-visible>*:first-child]:[stroke-opacity:1] ds:[&[data-selected=true]>*:first-child]:[stroke-opacity:1] ds:[&[data-selected=true]>*:first-child]:[stroke-dasharray:6_4] ds:forced-colors:[&:focus-visible>*:first-child]:[stroke:CanvasText] ds:forced-colors:[&[data-selected=true]>*:first-child]:[stroke:CanvasText]\"\n onClick={\n interactive && tool === null\n ? (e: ReactMouseEvent<SVGGElement>) => {\n e.currentTarget.focus();\n if (selectedAnnotationIdRef.current === a.id) {\n // Second activation: text opens its editor,\n // anything else toggles the selection off.\n if (a.kind === 'text') setEditingTextId(a.id);\n else selectAnnotationFn(null);\n } else {\n selectAnnotationFn(a.id);\n }\n }\n : undefined\n }\n onKeyDown={(e: KeyboardEvent<SVGGElement>) => {\n if (!interactive) return;\n if (e.key === 'Delete' || e.key === 'Backspace') {\n e.preventDefault();\n removeAnnotationFn(a.id);\n } else if (e.key === 'Escape') {\n // Wins the first Escape; with nothing selected it\n // bubbles on to the svg's zone-selection clearing.\n if (selectedAnnotationIdRef.current !== null) {\n e.stopPropagation();\n selectAnnotationFn(null);\n }\n } else if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n if (a.kind === 'text') setEditingTextId(a.id);\n else if (selectedAnnotationIdRef.current === a.id)\n selectAnnotationFn(null);\n else selectAnnotationFn(a.id);\n }\n }}\n >\n {/* ring (first child) — solid on :focus-visible, dashed when selected */}\n <rect\n x={bbox.x - ANN_FOCUS_PAD}\n y={bbox.y - ANN_FOCUS_PAD}\n width={bbox.width + ANN_FOCUS_PAD * 2}\n height={bbox.height + ANN_FOCUS_PAD * 2}\n rx={8}\n fill=\"none\"\n pointerEvents=\"none\"\n className=\"ds:[stroke:var(--ring)] ds:[stroke-width:var(--focus-ring-width)] ds:[stroke-opacity:0] ds:[vector-effect:non-scaling-stroke]\"\n />\n {renderAnnotationVisual(a)}\n {interactive && tool === null && renderAnnotationHit(a)}\n </g>\n );\n })}\n {draft && (\n <g aria-hidden=\"true\" data-testid=\"face-scheme-draft\">\n {renderAnnotationVisual(draft)}\n </g>\n )}\n </g>\n\n {/* Pointer draw surface — a transparent full-viewBox capture rect, on\n top so it intercepts drawing; pointer-events off (falls through to\n the zones / annotations below) when no tool is selected. Keyboard\n users annotate via the zone flow, so this is aria-hidden (a\n pointer-only enhancement). */}\n <rect\n data-testid=\"face-scheme-draw-surface\"\n x={0}\n y={0}\n width={vbW}\n height={vbH}\n fill=\"transparent\"\n aria-hidden=\"true\"\n className={\n drawingEnabled\n ? 'ds:cursor-crosshair ds:touch-none'\n : 'ds:[pointer-events:none]'\n }\n onPointerDown={drawingEnabled ? beginDraw : undefined}\n onPointerMove={drawingEnabled ? moveDraw : undefined}\n onPointerUp={drawingEnabled ? endDraw : undefined}\n onPointerCancel={drawingEnabled ? endDraw : undefined}\n />\n\n {/* Landmark handles — pointer-only fitting affordance (the numeric\n sliders below are the accessible, keyboard-operable equivalent).\n Hidden while a draw tool is active (fitting + drawing are\n mutually exclusive pointer modes). */}\n {adjusting && effectiveSrc && tool === null && (\n <g aria-hidden=\"true\" data-testid=\"face-scheme-handles\">\n {view.landmarks.map((lm, i) => {\n const tg =\n targets[i] ?? mirrorPt(applyAffine(activeAffine, lm));\n return (\n <g key={lm.id}>\n <circle\n cx={tg.x}\n cy={tg.y}\n r={13}\n data-handle={lm.id}\n onPointerDown={handlePointerDown(i)}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n className=\"ds:[fill:var(--background)] ds:[fill-opacity:0.9] ds:[stroke:var(--accent)] ds:[stroke-width:2.5] ds:[vector-effect:non-scaling-stroke] ds:cursor-grab ds:touch-none\"\n />\n <path\n d={`M ${tg.x - 5} ${tg.y} H ${tg.x + 5} M ${tg.x} ${tg.y - 5} V ${tg.y + 5}`}\n className=\"ds:[stroke:var(--accent)] ds:[stroke-width:2] ds:[vector-effect:non-scaling-stroke]\"\n pointerEvents=\"none\"\n />\n </g>\n );\n })}\n </g>\n )}\n </svg>\n </Card>\n </RadixTooltip.Provider>\n );\n };\n\n // Flat child list for the joined control bar — view buttons, then the\n // capture pair, then the fit-settings gear. Built as an array (not inline\n // conditionals) so the ButtonGroup's roving tabindex never lands on a\n // skipped/null child (the first real button always owns tabIndex 0).\n const barChildren: ReactElement[] = [];\n if (showViewButtons) {\n for (const vid of VIEW_RENDER_ORDER) {\n const selected = layout === 'single' && viewId === vid;\n barChildren.push(\n <Button\n key={vid}\n size=\"sm\"\n intent={selected ? 'primary' : undefined}\n aria-pressed={selected}\n startIcon={VIEW_ICON[vid]}\n onClick={() => {\n setView(vid);\n setLayout('single');\n }}\n >\n {t(`faceScheme.viewShort.${FACE_VIEWS[vid].labelKey}`)}\n </Button>,\n );\n }\n barChildren.push(\n <Button\n key=\"all\"\n size=\"sm\"\n intent={layout === 'all' ? 'primary' : undefined}\n aria-pressed={layout === 'all'}\n startIcon={<Columns3 aria-hidden=\"true\" />}\n onClick={() => setLayout('all')}\n >\n {t('faceScheme.viewShort.all')}\n </Button>,\n );\n }\n if (captureEnabled) {\n barChildren.push(\n <Button\n key=\"capture\"\n ref={captureButtonRef}\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Camera aria-hidden=\"true\" />}\n data-overflow-pin\n onClick={() => void startCapture()}\n disabled={captureState === 'requesting'}\n >\n {t(\n effectiveSrc\n ? 'faceScheme.capture.retake'\n : 'faceScheme.capture.take',\n )}\n </Button>,\n );\n barChildren.push(\n <Button\n key=\"upload\"\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Upload aria-hidden=\"true\" />}\n onClick={() => fileInputRef.current?.click()}\n >\n {t('faceScheme.capture.upload')}\n </Button>,\n );\n }\n if (panelToggle) barChildren.push(panelToggle);\n\n return (\n <div\n ref={rootRef}\n data-component=\"face-scheme\"\n data-component-id={instanceId}\n data-view={viewId}\n data-layout={isThreeUp ? 'all' : 'single'}\n className={[containerClass, className].filter(Boolean).join(' ')}\n role=\"group\"\n aria-label={ariaLabel ?? t('faceScheme.ariaLabel')}\n >\n {/* Figure column — control bar, figure(s) (or the live viewfinder\n while streaming), and the finding legend. */}\n <div className={figureColClass}>\n {/* Joined control bar — view buttons + capture + the fit-settings\n gear, as a WAI-ARIA toolbar. Hidden while the viewfinder streams. */}\n {!captureStreaming && barHasContent && (\n <ButtonGroup\n toolbar\n label={t('faceScheme.viewSwitcherLabel')}\n overflow=\"menu\"\n collapseToIcons\n className=\"ds:text-center\"\n >\n {barChildren}\n </ButtonGroup>\n )}\n\n {/* Hidden file input (upload fallback) + the capture error live\n region — mounted whenever capture is enabled so the polite region\n exists before its first message. */}\n {captureEnabled && (\n <div className=\"ds:mx-auto ds:flex ds:w-full ds:max-w-[28rem] ds:flex-col\">\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n capture={captureFacingMode}\n onChange={onPickFile}\n className=\"ds:sr-only\"\n aria-hidden=\"true\"\n tabIndex={-1}\n data-testid=\"face-scheme-file-input\"\n />\n <span\n role=\"status\"\n aria-live=\"polite\"\n className={\n captureState === 'requesting'\n ? 'ds:text-start ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)] ds:empty:hidden'\n : 'ds:text-start ds:text-[length:var(--font-size-xs)] ds:text-[var(--destructive)] ds:empty:hidden'\n }\n >\n {captureState === 'requesting'\n ? t(\n 'faceScheme.capture.requesting',\n 'Waiting for camera permission…',\n )\n : captureState === 'error' && captureError\n ? t(CAPTURE_ERROR_KEY[captureError])\n : ''}\n </span>\n </div>\n )}\n\n {/* Live camera viewfinder — replaces the figure while streaming. */}\n {captureStreaming && (\n <div\n data-testid=\"face-scheme-viewfinder\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n {/* eslint-disable-next-line jsx-a11y/media-has-caption -- live self-view, not media content */}\n <video\n ref={videoRef}\n autoPlay\n playsInline\n muted\n aria-label={t('faceScheme.capture.viewfinder')}\n className=\"ds:mx-auto ds:block ds:w-full ds:max-w-[28rem] ds:[border-radius:var(--radius-md)] ds:[transform:scaleX(-1)]\"\n />\n <div className=\"ds:flex ds:flex-wrap ds:justify-center ds:gap-[var(--spacing-xs)]\">\n <Button\n size=\"sm\"\n intent=\"primary\"\n onClick={() => capturePhoto()}\n >\n {t('faceScheme.capture.capture')}\n </Button>\n <Button size=\"sm\" intent=\"outline\" onClick={cancelCapture}>\n {t('faceScheme.capture.cancel')}\n </Button>\n </div>\n </div>\n )}\n\n {/* Figure(s) — the focused interactive figure, or (in three-up) all\n three views with the focused one interactive and the rest as\n read-only, clickable previews. */}\n {!captureStreaming &&\n (isThreeUp ? (\n // Equal columns in every case: the three cards stay the same\n // size, and the photoless schematic crops give the maps\n // matching aspects within them.\n <div className=\"ds:grid ds:grid-cols-1 ds:items-center ds:gap-[var(--spacing-md)] ds:md:grid-cols-3\">\n {VIEW_RENDER_ORDER.map((vid) => (\n <div key={vid} className=\"ds:min-w-0\">\n {renderFigure(vid)}\n </div>\n ))}\n </div>\n ) : (\n renderFigure(viewId)\n ))}\n\n {/* Finding legend — its own card below the figure(s), gated by the\n Show-legend toggle at the edit panel's root. */}\n {legend && showLegend && (\n <Card variant=\"elevated\" data-testid=\"face-scheme-legend\">\n <Card.Body>\n <ul\n aria-label={t('faceScheme.legendLabel')}\n className=\"ds:m-0 ds:flex ds:flex-wrap ds:gap-x-4 ds:gap-y-1 ds:p-0 ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)]\"\n >\n {FACE_FINDING_TYPES.map((type) => {\n const m = FACE_FINDING_MARKER[type];\n return (\n <li\n key={type}\n className=\"ds:flex ds:list-none ds:items-center\"\n >\n <AnnotationMarker\n shape={m.shape}\n tone={m.tone}\n size=\"sm\"\n label={t(`faceScheme.finding.${type}`)}\n />\n </li>\n );\n })}\n </ul>\n </Card.Body>\n </Card>\n )}\n </div>\n\n {hasSidePanel && (\n <div className={sidePanelClass}>\n {/* Edit panel — ONE card, fixed section order everywhere:\n Zones (multi-select) → Draw (annotation palette) → Fit overlay\n (numeric fit sliders), plus the Show-legend switch at root. */}\n <Card\n variant=\"elevated\"\n data-testid=\"face-scheme-panel\"\n id={panelId}\n className={panelCardClass}\n >\n <Card.Body className={panelBodyClass}>\n {zonesSection}\n {zoneSelectMode && (annotationToolbarEnabled || adjusting) && (\n <Separator />\n )}\n {drawSection}\n {annotationToolbarEnabled && adjusting && <Separator />}\n {adjusting && (\n <div\n data-testid=\"face-scheme-registration\"\n role=\"group\"\n aria-labelledby={fitLabelId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <span id={fitLabelId} className={panelLabelClass}>\n {t('faceScheme.panel.fit')}\n </span>\n <p className=\"ds:m-0 ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)]\">\n {t('faceScheme.registration.hint')}\n </p>\n <div className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-xs)] ds:sm:grid-cols-2\">\n {SLIDER_FIELDS.map((field) => {\n const range = SLIDER_RANGES[field];\n const isScale =\n field === 'scaleX' || field === 'scaleY';\n return (\n <div\n key={field}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:text-[length:var(--font-size-xs)] ds:text-[var(--foreground)]\"\n >\n <span>{t(`faceScheme.registration.${field}`)}</span>\n <Slider\n aria-label={t(`faceScheme.registration.${field}`)}\n value={[parts[field]]}\n min={range.min}\n max={range.max}\n step={range.step}\n formatValue={(v) =>\n isScale\n ? `${Math.round(v * 100)}%`\n : field === 'rotation' || field === 'shear'\n ? `${v.toFixed(1)}°`\n : `${Math.round(v)}`\n }\n onValueChange={(vals) => {\n const v = vals[0];\n if (typeof v === 'number') updatePart(field, v);\n }}\n />\n </div>\n );\n })}\n </div>\n <div className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-xs)]\">\n {detectEnabled && (\n <Button\n size=\"sm\"\n intent=\"primary\"\n onClick={() => void runDetect()}\n disabled={\n detectStatus === 'loading' ||\n detectStatus === 'detecting'\n }\n >\n {t('faceScheme.registration.autoDetect')}\n </Button>\n )}\n <Button\n size=\"sm\"\n intent=\"outline\"\n onClick={() => commitReg(IDENTITY_AFFINE)}\n >\n {t('faceScheme.registration.reset')}\n </Button>\n {/* Always mounted so a polite region exists before its first\n message — some SRs miss a live region created in the same\n mutation as its initial text. */}\n {detectEnabled && (\n <span\n role=\"status\"\n aria-live=\"polite\"\n className=\"ds:self-center ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)]\"\n >\n {detectStatus === 'idle'\n ? ''\n : t(`faceScheme.detect.${detectStatus}`)}\n </span>\n )}\n </div>\n </div>\n )}\n {/* Zoom row — wheel/drag work on the figure; these are the\n keyboard-operable equivalents plus the live level readout. */}\n {effectiveZoomable && (\n <>\n {(zoneSelectMode ||\n annotationToolbarEnabled ||\n adjusting) && <Separator />}\n <div\n data-testid=\"face-scheme-zoom\"\n role=\"group\"\n aria-labelledby={zoomLabelId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <span id={zoomLabelId} className={panelLabelClass}>\n {t('faceScheme.zoomLabel')}\n </span>\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n <IconButton\n size=\"sm\"\n icon={<ZoomOut aria-hidden=\"true\" />}\n aria-label={t('faceScheme.zoomOut')}\n disabled={zoomState.k <= 1}\n onClick={() => zoomBy(1 / 1.3)}\n />\n <span\n role=\"status\"\n aria-live=\"polite\"\n aria-label={t('faceScheme.zoomLevel')}\n className=\"ds:min-w-[3.5rem] ds:text-center ds:text-[length:var(--font-size-xs)] ds:text-[var(--muted-foreground)]\"\n >\n {Math.round(zoomState.k * 100)}%\n </span>\n <IconButton\n size=\"sm\"\n icon={<ZoomIn aria-hidden=\"true\" />}\n aria-label={t('faceScheme.zoomIn')}\n disabled={zoomState.k >= FACE_ZOOM_MAX}\n onClick={() => zoomBy(1.3)}\n />\n <Button\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Maximize2 aria-hidden=\"true\" />}\n disabled={zoomState.k <= 1}\n onClick={resetZoomFn}\n >\n {t('faceScheme.resetView')}\n </Button>\n </div>\n </div>\n </>\n )}\n {/* Show-legend toggle — panel root, reachable whenever the\n legend is configured (independent of adjust mode). */}\n {legend && (\n <>\n <Separator />\n <Switch\n size=\"sm\"\n label={t('faceScheme.showLegend')}\n checked={showLegend}\n onCheckedChange={setShowLegend}\n />\n </>\n )}\n </Card.Body>\n </Card>\n </div>\n )}\n </div>\n );\n },\n);\n\nFaceScheme.displayName = 'FaceScheme';\n"],"names":["__iconNode","Columns3","createLucideIcon","MousePointer2","Pen","PencilRuler","Undo2","UserRoundArrowLeft","UserRound","TOOL_SCHEMA","ZONE_SCHEMA","VIEW_SCHEMA","FINDING_SCHEMA","faceSchemeAgent","handle","zone","findings","f","acc","a","key","args","DEFAULT_VISION_MODULE","DEFAULT_WASM_BASE","DEFAULT_MODEL","ANCHOR_INDICES","landmarkerCache","getLandmarker","visionModuleUrl","wasmBaseUrl","modelAssetPath","onStage","cached","promise","mod","fileset","loadImage","src","img","detectFaceLandmarks","options","viewWidth","viewHeight","image","landmarker","face","imgW","imgH","scale","offsetX","offsetY","toView","lm","pairs","id","indices","sx","sy","count","idx","v","DEFAULT_ORT_MODULE","DEFAULT_ORT_WASM_BASE","NET_SIZE","STRIDES","KEYPOINT_IDS","sessionCache","getSession","ortModuleUrl","ortWasmBaseUrl","modelUrl","ort","model","session","defaultModelUrl","preprocess","Tensor","w","h","dw","dh","padX","padY","canvas","ctx","data","n","i","sigmoid","x","decode","out","scoreThreshold","needSigmoid","probe","best","s","cls","obj","kps","cols","rows","cv","ov","score","c","r","keypoints","j","detectFaceYuNet","tensor","result","coverScale","kx","ky","px","py","FRONT_VIEWBOX","FRONT_PIVOT","FRONT_CONTOUR","FRONT_ZONES","FRONT_LANDMARKS","PROFILE_ZONE_PATHS","PROFILE_CONTOUR","z","PROFILE_ZONES","PROFILE_LANDMARKS","FACE_VIEWS","FACE_VIEW_IDS","FACE_FINDING_TYPES","FACE_FINDING_MARKER","FACE_ANNOTATION_TOOLS","ANNOTATION_TOOL_KIND","isShapeTool","tool","isInkTool","isPointTool","inkPath","points","first","d","p","shapePath","kind","from","to","y","cx","cy","rx","ry","arrowHeadPath","size","dx","dy","len","ux","uy","ang","cos","sin","b1x","b1y","b2x","b2y","annotationBBox","minX","minY","maxX","maxY","annotationAnchor","ANN_HIT_STROKE","ANN_HIT_RADIUS","annotationHitGeometry","textSize","width","IDENTITY_AFFINE","affineToString","m","applyAffine","invertAffine","det","ia","ib","ic","AUTO_FRAME_FRACTION","autoFrameViewBox","meshBox","affine","opts","full","fraction","corners","mirroredMin","bw","bh","aspect","FACE_ZOOM_MIN","FACE_ZOOM_MAX","FACE_ZOOM_RESET","clamp01","parseViewBox","vb","height","boxToViewBox","b","composeZoomWindow","base","zoomWindowAround","factor","k","cur","u","rangeX","rangeY","panZoomWindow","DEG","composeAffine","parts","pivot","rad","ca","sa","e","decomposeAffine","scaleX","rotation","scaleY","shear","translateX","translateY","solveAffine","dst","Sxx","Sxy","Sx","Syy","Sy","bx0","bx1","bx2","by0","by1","by2","t","i00","i01","i02","i11","i12","i22","solve","r0","r1","r2","profileTriangleFromYuNet","photoOf","_a","nose","rightEye","leftEye","rightMouth","leftMouth","farther","mediaDevicesAvailable","classifyMediaError","err","name","CAPTURE_ERROR_KEY","markerToneFill","annotationToneStroke","ANN_MARKER_R","ANN_PEN_WIDTH","ANN_HIGHLIGHTER_WIDTH","ANN_SHAPE_WIDTH","ANN_ARROW_HEAD","ANN_TEXT_SIZE","ANN_FOCUS_PAD","EMPTY_ANNOTATIONS","DRAFT_ID","VIEW_RENDER_ORDER","VIEW_ICON","jsx","TOOL_ICON","MapPin","Highlighter","ArrowUpRight","Minus","SquareIcon","CircleIcon","TypeIcon","ANNOTATION_TONES","zoneVariants","cva","SLIDER_RANGES","SLIDER_FIELDS","FaceScheme","forwardRef","patientPhoto","viewPhotos","viewProp","defaultView","onViewChange","showViewSwitcher","defaultLayout","mode","value","defaultValue","onChange","onSelectZone","activeFinding","zoneSelect","selectedZonesProp","defaultSelectedZones","onSelectedZonesChange","annotations","defaultAnnotations","onAnnotationsChange","onAnnotationSelect","showAnnotationToolbar","zoomable","defaultPanelOpen","activeTool","defaultTool","onToolChange","defaultAnnotationShape","defaultAnnotationColor","registration","defaultRegistration","onRegistrationChange","registrationMode","autoDetect","onDetectStatus","allowCapture","captureFacingMode","onCapture","legend","ariaLabel","className","ref","useTranslation","reactId","useId","instanceId","rootRef","useRef","svgRef","videoRef","streamRef","fileInputRef","captureButtonRef","unmountedRef","isViewControlled","internalView","setInternalView","useState","viewId","viewIdRef","setView","useCallback","next","panelOpen","setPanelOpen","panelId","layout","setLayout","showLegend","setShowLegend","view","vbW","vbH","interactive","adjusting","isControlled","internal","setInternal","chart","chartRef","commitChart","addFinding","zoneId","type","note","current","removeFindingFn","copy","toggleFinding","zoneSelectMode","isZoneSelControlled","internalZoneSel","setInternalZoneSel","zoneSelection","zoneSelectionRef","zoneSelectionSet","useMemo","commitZoneSelection","ids","toggleZoneSelected","clearZoneSelectionFn","bulkNote","setBulkNote","setFindingBulkFn","changed","removeFindingBulkFn","rest","isRegControlled","internalReg","setInternalReg","regMap","activeAffine","affineRef","affineRefMap","commitReg","mirrorPt","targets","setTargets","draggingRef","frozenFrame","setFrozenFrame","frameNowRef","zoomState","setZoomState","zoomStateRef","baseWindowRef","panRef","useEffect","fitFromPairs","pair","anchor","l","toSvgPoint","clientX","clientY","svg","pt","ctm","local","zoomAtCentre","zoomAtCentreRef","zoomBy","setZoomTo","resetZoomFn","endPan","handlePointerDown","index","handlePointerMove","tg","handlePointerUp","captureState","setCaptureState","captureError","setCaptureError","capturedByView","setCapturedByView","viewPhoto","effectiveSrc","isAnnotationsControlled","internalAnnotations","setInternalAnnotations","annMap","annMapRef","viewAnnotations","commitAnnotations","nextForView","annIdRef","nextAnnId","selectedAnnotationId","setSelectedAnnotationId","selectedAnnotationIdRef","selectAnnotationFn","hitTestZone","photoPoint","meshPt","paths","zoneEl","addAnnotationFn","input","newId","withId","ann","list","removeAnnotationFn","annId","setAnnotationZoneFn","undoAnnotationFn","clearAnnotationsFn","isToolControlled","internalTool","setInternalTool","toolRef","setToolFn","annShape","setAnnShape","annTone","setAnnTone","annShapeRef","annToneRef","draft","setDraft","draftRef","drawingRef","editingTextId","setEditingTextId","editingTextIdRef","prevZoneSelCount","prevToolRef","prevViewRef","selId","drawingEnabled","beginDraw","active","_b","moveDraw","prev","endDraw","_draftId","editingText","updateEditingText","nextText","finishEditingText","stopStream","track","video","cancelCapture","startCapture","stream","playResult","commitCaptured","capturePhoto","vw","vh","onPickFile","file","reader","captureStreaming","wasStreamingRef","detectStatus","setDetectStatus","setStatus","runDetect","stage","raw","focusZoneEl","useImperativeHandle","useAgentRegistration","zoneLabel","findingNames","handleActivate","photoAlt","meshTransform","updatePart","field","val","detectEnabled","captureEnabled","hasViewSwitcher","annotationToolbarEnabled","effectiveZoomable","panelAvailable","hasSidePanel","isThreeUp","onWheel","sideBeside","containerClass","figureColClass","sidePanelClass","panelCardClass","panelBodyClass","showViewButtons","barHasContent","panelToggle","IconButton","open","toolbarValue","drawLabelId","fitLabelId","zoomLabelId","toolLabelId","toneLabelId","shapeLabelId","zoneRowLabelId","selectedAnnotation","zoneOptions","panelLabelClass","zonesLabelId","zonesApplyLabelId","zonesSection","jsxs","allHave","zid","Button","markerPath","TextInput","drawSection","IconButtonGroup","tv","Icon","nextTone","toneOpt","MARKER_SHAPES","shapeOpt","Combobox","Eraser","Trash2","annotationLabel","renderAnnotationVisual","tone","renderAnnotationHit","hit","focusedFrame","baseWindow","zoomedIn","zoomedWindow","panEligible","renderFigure","vid","previewPhoto","previewSrc","previewAffine","previewMesh","previewAnnotations","Card","marked","offset","RadixTooltip","el","pan","rect","zoneSelected","bbox","selected","barChildren","Camera","Upload","ButtonGroup","AnnotationMarker","Separator","range","isScale","Slider","vals","Fragment","ZoomOut","ZoomIn","Maximize2","Switch"],"mappings":"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","x_google_ignoreList":[0,1,2,3,4,5,6]}