@alfadocs/ui-kit-debug 0.50.0 → 0.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/{agenda-card-BaSfVfrL.js → agenda-card-Bl-SBiCh.js} +55 -45
- package/dist/_chunks/agenda-card-Bl-SBiCh.js.map +1 -0
- package/dist/_chunks/agenda-tray-DA6qj8BL.js +203 -0
- package/dist/_chunks/agenda-tray-DA6qj8BL.js.map +1 -0
- package/dist/_chunks/{ai-consent-banner-F2md5JD3.js → ai-consent-banner-DBKV27je.js} +2 -2
- package/dist/_chunks/{ai-consent-banner-F2md5JD3.js.map → ai-consent-banner-DBKV27je.js.map} +1 -1
- package/dist/_chunks/ai-tools-rail-7tC3GT4h.js +340 -0
- package/dist/_chunks/ai-tools-rail-7tC3GT4h.js.map +1 -0
- package/dist/_chunks/{alert-CUTxnym2.js → alert-_mUKLmwA.js} +54 -44
- package/dist/_chunks/alert-_mUKLmwA.js.map +1 -0
- package/dist/_chunks/{audio-recorder-DVJXV7_k.js → audio-recorder-D6OVfNiZ.js} +2 -2
- package/dist/_chunks/{audio-recorder-DVJXV7_k.js.map → audio-recorder-D6OVfNiZ.js.map} +1 -1
- package/dist/_chunks/{bishop-score-2MzAz8NE.js → bishop-score-CMQxsdy4.js} +2 -2
- package/dist/_chunks/{bishop-score-2MzAz8NE.js.map → bishop-score-CMQxsdy4.js.map} +1 -1
- package/dist/_chunks/{bmi-calculator-DdylQzT6.js → bmi-calculator-DuUneHuZ.js} +2 -2
- package/dist/_chunks/{bmi-calculator-DdylQzT6.js.map → bmi-calculator-DuUneHuZ.js.map} +1 -1
- package/dist/_chunks/{booking-DljH0JkS.js → booking-BUV9fspj.js} +2 -2
- package/dist/_chunks/{booking-DljH0JkS.js.map → booking-BUV9fspj.js.map} +1 -1
- package/dist/_chunks/{cycle-calculator-oOkj5wlB.js → cycle-calculator-vTtZZAmn.js} +2 -2
- package/dist/_chunks/{cycle-calculator-oOkj5wlB.js.map → cycle-calculator-vTtZZAmn.js.map} +1 -1
- package/dist/_chunks/{document-scanner-Cxqvq7GR.js → document-scanner-biBS_f6c.js} +2 -2
- package/dist/_chunks/{document-scanner-Cxqvq7GR.js.map → document-scanner-biBS_f6c.js.map} +1 -1
- package/dist/_chunks/dropdown-menu-DwwPovMZ.js +354 -0
- package/dist/_chunks/dropdown-menu-DwwPovMZ.js.map +1 -0
- package/dist/_chunks/{due-date-calculator-DykajWzh.js → due-date-calculator-CUm5KJbf.js} +2 -2
- package/dist/_chunks/{due-date-calculator-DykajWzh.js.map → due-date-calculator-CUm5KJbf.js.map} +1 -1
- package/dist/_chunks/{editable-currency-cell-renderer-Bh48OHRv.js → editable-currency-cell-renderer-D5C5tCfu.js} +3 -3
- package/dist/_chunks/{editable-currency-cell-renderer-Bh48OHRv.js.map → editable-currency-cell-renderer-D5C5tCfu.js.map} +1 -1
- package/dist/_chunks/{fetal-weight-Da-B4P4k.js → fetal-weight-Xf8-ZoDy.js} +2 -2
- package/dist/_chunks/{fetal-weight-Da-B4P4k.js.map → fetal-weight-Xf8-ZoDy.js.map} +1 -1
- package/dist/_chunks/{freemium-paywall-BWaLWje-.js → freemium-paywall-gHGA44dW.js} +2 -2
- package/dist/_chunks/{freemium-paywall-BWaLWje-.js.map → freemium-paywall-gHGA44dW.js.map} +1 -1
- package/dist/_chunks/{gestational-age-calculator-Bc55hq6t.js → gestational-age-calculator-830KJql3.js} +2 -2
- package/dist/_chunks/{gestational-age-calculator-Bc55hq6t.js.map → gestational-age-calculator-830KJql3.js.map} +1 -1
- package/dist/_chunks/{hcg-doubling-DAnpbale.js → hcg-doubling-kVOpDfny.js} +2 -2
- package/dist/_chunks/{hcg-doubling-DAnpbale.js.map → hcg-doubling-kVOpDfny.js.map} +1 -1
- package/dist/_chunks/{header-settings-Bx0Biimh.js → header-settings-D5Z2B_Yz.js} +3 -3
- package/dist/_chunks/{header-settings-Bx0Biimh.js.map → header-settings-D5Z2B_Yz.js.map} +1 -1
- package/dist/_chunks/insert-result-njqBthzT.js +742 -0
- package/dist/_chunks/insert-result-njqBthzT.js.map +1 -0
- package/dist/_chunks/{marketplace-app-shell-UKSLx9K_.js → marketplace-app-shell-Dmo1S9av.js} +6 -6
- package/dist/_chunks/{marketplace-app-shell-UKSLx9K_.js.map → marketplace-app-shell-Dmo1S9av.js.map} +1 -1
- package/dist/_chunks/{patient-search-BJOmTmDA.js → patient-search-CArmRKeg.js} +3 -3
- package/dist/_chunks/{patient-search-BJOmTmDA.js.map → patient-search-CArmRKeg.js.map} +1 -1
- package/dist/_chunks/{patient-shell-DUmhXnFq.js → patient-shell-c2YixkQw.js} +4 -4
- package/dist/_chunks/{patient-shell-DUmhXnFq.js.map → patient-shell-c2YixkQw.js.map} +1 -1
- package/dist/_chunks/{payment-form-xmeCkxas.js → payment-form-DJ9vnzrT.js} +2 -2
- package/dist/_chunks/{payment-form-xmeCkxas.js.map → payment-form-DJ9vnzrT.js.map} +1 -1
- package/dist/_chunks/{pdf-viewer-q1D3Uion.js → pdf-viewer-4odMFuFW.js} +2 -2
- package/dist/_chunks/{pdf-viewer-q1D3Uion.js.map → pdf-viewer-4odMFuFW.js.map} +1 -1
- package/dist/_chunks/{practice-results-Cq1y8JFD.js → practice-results-CtfciF2v.js} +3 -3
- package/dist/_chunks/{practice-results-Cq1y8JFD.js.map → practice-results-CtfciF2v.js.map} +1 -1
- package/dist/_chunks/{pregnancy-dating-48Gfvod1.js → pregnancy-dating-BA37LSkF.js} +16 -16
- package/dist/_chunks/{pregnancy-dating-48Gfvod1.js.map → pregnancy-dating-BA37LSkF.js.map} +1 -1
- package/dist/_chunks/{pregnancy-weight-gain-CCGrvarh.js → pregnancy-weight-gain-BMRBeA8V.js} +2 -2
- package/dist/_chunks/{pregnancy-weight-gain-CCGrvarh.js.map → pregnancy-weight-gain-BMRBeA8V.js.map} +1 -1
- package/dist/_chunks/{recaptcha-widget-CFYyLSEX.js → recaptcha-widget-BCNHsgqt.js} +2 -2
- package/dist/_chunks/{recaptcha-widget-CFYyLSEX.js.map → recaptcha-widget-BCNHsgqt.js.map} +1 -1
- package/dist/_chunks/{sidebar-h78cTNLh.js → sidebar-DPEHzxLZ.js} +397 -346
- package/dist/_chunks/sidebar-DPEHzxLZ.js.map +1 -0
- package/dist/_chunks/{sign-document-CZkAf28g.js → sign-document-Bzld9jVM.js} +2 -2
- package/dist/_chunks/{sign-document-CZkAf28g.js.map → sign-document-Bzld9jVM.js.map} +1 -1
- package/dist/_chunks/{task-card-CPyQ5AXC.js → task-card-BwY9jaV1.js} +48 -42
- package/dist/_chunks/task-card-BwY9jaV1.js.map +1 -0
- package/dist/_chunks/task-tray-Cb_hK4yb.js +234 -0
- package/dist/_chunks/task-tray-Cb_hK4yb.js.map +1 -0
- package/dist/_chunks/{theme-toggle-ClATnY4Q.js → theme-toggle-DAW7uC0B.js} +3 -3
- package/dist/_chunks/{theme-toggle-ClATnY4Q.js.map → theme-toggle-DAW7uC0B.js.map} +1 -1
- package/dist/_chunks/{unit-converter-jWp3Z85y.js → unit-converter-BQ6lEYvd.js} +2 -2
- package/dist/_chunks/{unit-converter-jWp3Z85y.js.map → unit-converter-BQ6lEYvd.js.map} +1 -1
- package/dist/_chunks/use-edge-resize-ZnGG7gyO.js +139 -0
- package/dist/_chunks/use-edge-resize-ZnGG7gyO.js.map +1 -0
- package/dist/_chunks/use-theme-CAuo6EYT.js +159 -0
- package/dist/_chunks/use-theme-CAuo6EYT.js.map +1 -0
- package/dist/_chunks/{warning-stack-CXfoAT-_.js → warning-stack-Cv4fr5zo.js} +2 -2
- package/dist/_chunks/{warning-stack-CXfoAT-_.js.map → warning-stack-Cv4fr5zo.js.map} +1 -1
- package/dist/_chunks/{workflow-map-DzX_LI4y.js → workflow-map-BJDUNYlX.js} +3 -3
- package/dist/_chunks/{workflow-map-DzX_LI4y.js.map → workflow-map-BJDUNYlX.js.map} +1 -1
- package/dist/agent-catalog.json +1 -1
- package/dist/components/_shared/insert-result.d.ts.map +1 -1
- package/dist/components/agenda-card/agenda-card.d.ts +19 -2
- package/dist/components/agenda-card/agenda-card.d.ts.map +1 -1
- package/dist/components/agenda-card/index.js +1 -1
- package/dist/components/agenda-tray/agenda-tray.d.ts +24 -1
- package/dist/components/agenda-tray/agenda-tray.d.ts.map +1 -1
- package/dist/components/agenda-tray/index.js +1 -1
- package/dist/components/ai-consent-banner/index.js +1 -1
- package/dist/components/ai-tools-rail/ai-tools-rail.d.ts +8 -0
- package/dist/components/ai-tools-rail/ai-tools-rail.d.ts.map +1 -1
- package/dist/components/ai-tools-rail/index.js +1 -1
- package/dist/components/alert/index.js +1 -1
- package/dist/components/audio-recorder/index.js +1 -1
- package/dist/components/bishop-score/index.js +1 -1
- package/dist/components/bmi-calculator/index.js +1 -1
- package/dist/components/booking/index.js +1 -1
- package/dist/components/button-group/button-group.d.ts +1 -1
- package/dist/components/checkbox-group/checkbox-group.d.ts +1 -1
- package/dist/components/cycle-calculator/index.js +1 -1
- package/dist/components/data-table/index.js +1 -1
- package/dist/components/document-scanner/index.js +1 -1
- package/dist/components/dropdown-menu/dropdown-menu.d.ts +2 -0
- package/dist/components/dropdown-menu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/dropdown-menu/index.js +1 -1
- package/dist/components/due-date-calculator/index.js +1 -1
- package/dist/components/fetal-weight/index.js +1 -1
- package/dist/components/form-field/form-field.d.ts +1 -1
- package/dist/components/freemium-paywall/index.js +1 -1
- package/dist/components/gestational-age-calculator/index.js +1 -1
- package/dist/components/hcg-doubling/index.js +1 -1
- package/dist/components/header-settings/index.js +1 -1
- package/dist/components/icon-button-group/icon-button-group.d.ts +15 -15
- package/dist/components/key-value-pair/key-value-pair.d.ts +1 -1
- package/dist/components/patient-search/index.js +1 -1
- package/dist/components/payment-form/index.js +1 -1
- package/dist/components/pdf-viewer/index.js +1 -1
- package/dist/components/practice-results/index.js +1 -1
- package/dist/components/pregnancy-dating/index.js +1 -1
- package/dist/components/pregnancy-dating/pregnancy-dating.d.ts.map +1 -1
- package/dist/components/pregnancy-weight-gain/index.js +1 -1
- package/dist/components/radio-group/radio-group.d.ts +1 -1
- package/dist/components/recaptcha-widget/index.js +1 -1
- package/dist/components/separator/separator.d.ts +1 -1
- package/dist/components/sidebar/index.js +1 -1
- package/dist/components/sidebar/sidebar.d.ts +8 -0
- package/dist/components/sidebar/sidebar.d.ts.map +1 -1
- package/dist/components/sign-document/index.js +1 -1
- package/dist/components/tabs/tabs.d.ts +2 -2
- package/dist/components/task-card/index.js +1 -1
- package/dist/components/task-card/task-card.d.ts +15 -1
- package/dist/components/task-card/task-card.d.ts.map +1 -1
- package/dist/components/task-tray/index.js +1 -1
- package/dist/components/task-tray/task-tray.d.ts +24 -1
- package/dist/components/task-tray/task-tray.d.ts.map +1 -1
- package/dist/components/theme-toggle/index.js +1 -1
- package/dist/components/unit-converter/index.js +1 -1
- package/dist/components/warning-stack/index.js +1 -1
- package/dist/components/workflow/index.js +1 -1
- package/dist/components/workflow/workflow-map.d.ts +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +12 -10
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/use-edge-resize.d.ts +78 -0
- package/dist/hooks/use-edge-resize.d.ts.map +1 -0
- package/dist/hooks/use-theme.d.ts.map +1 -1
- package/dist/i18n/locales/ar.d.ts +4 -0
- package/dist/i18n/locales/ar.d.ts.map +1 -1
- package/dist/i18n/locales/ar.js +7 -3
- package/dist/i18n/locales/ar.js.map +1 -1
- package/dist/i18n/locales/de.d.ts +4 -0
- package/dist/i18n/locales/de.d.ts.map +1 -1
- package/dist/i18n/locales/de.js +7 -3
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/el.d.ts +4 -0
- package/dist/i18n/locales/el.d.ts.map +1 -1
- package/dist/i18n/locales/el.js +7 -3
- package/dist/i18n/locales/el.js.map +1 -1
- package/dist/i18n/locales/en.d.ts +4 -0
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +7 -3
- package/dist/i18n/locales/en.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +4 -0
- package/dist/i18n/locales/es.d.ts.map +1 -1
- package/dist/i18n/locales/es.js +7 -3
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +4 -0
- package/dist/i18n/locales/fr.d.ts.map +1 -1
- package/dist/i18n/locales/fr.js +7 -3
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hi.d.ts +4 -0
- package/dist/i18n/locales/hi.d.ts.map +1 -1
- package/dist/i18n/locales/hi.js +7 -3
- package/dist/i18n/locales/hi.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +4 -0
- package/dist/i18n/locales/it.d.ts.map +1 -1
- package/dist/i18n/locales/it.js +7 -3
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/ja.d.ts +4 -0
- package/dist/i18n/locales/ja.d.ts.map +1 -1
- package/dist/i18n/locales/ja.js +7 -3
- package/dist/i18n/locales/ja.js.map +1 -1
- package/dist/i18n/locales/nl.d.ts +4 -0
- package/dist/i18n/locales/nl.d.ts.map +1 -1
- package/dist/i18n/locales/nl.js +7 -3
- package/dist/i18n/locales/nl.js.map +1 -1
- package/dist/i18n/locales/pl.d.ts +4 -0
- package/dist/i18n/locales/pl.d.ts.map +1 -1
- package/dist/i18n/locales/pl.js +7 -3
- package/dist/i18n/locales/pl.js.map +1 -1
- package/dist/i18n/locales/pt.d.ts +4 -0
- package/dist/i18n/locales/pt.d.ts.map +1 -1
- package/dist/i18n/locales/pt.js +7 -3
- package/dist/i18n/locales/pt.js.map +1 -1
- package/dist/i18n/locales/ro.d.ts +4 -0
- package/dist/i18n/locales/ro.d.ts.map +1 -1
- package/dist/i18n/locales/ro.js +7 -3
- package/dist/i18n/locales/ro.js.map +1 -1
- package/dist/i18n/locales/ru.d.ts +4 -0
- package/dist/i18n/locales/ru.d.ts.map +1 -1
- package/dist/i18n/locales/ru.js +7 -3
- package/dist/i18n/locales/ru.js.map +1 -1
- package/dist/i18n/locales/sq.d.ts +4 -0
- package/dist/i18n/locales/sq.d.ts.map +1 -1
- package/dist/i18n/locales/sq.js +7 -3
- package/dist/i18n/locales/sq.js.map +1 -1
- package/dist/i18n/locales/sv.d.ts +4 -0
- package/dist/i18n/locales/sv.d.ts.map +1 -1
- package/dist/i18n/locales/sv.js +7 -3
- package/dist/i18n/locales/sv.js.map +1 -1
- package/dist/i18n/locales/tr.d.ts +4 -0
- package/dist/i18n/locales/tr.d.ts.map +1 -1
- package/dist/i18n/locales/tr.js +7 -3
- package/dist/i18n/locales/tr.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +4 -0
- package/dist/i18n/locales/zh.d.ts.map +1 -1
- package/dist/i18n/locales/zh.js +7 -3
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.js +37 -37
- package/dist/locales/ar.json +7 -3
- package/dist/locales/de.json +7 -3
- package/dist/locales/el.json +7 -3
- package/dist/locales/en.json +7 -3
- package/dist/locales/es.json +7 -3
- package/dist/locales/fr.json +7 -3
- package/dist/locales/hi.json +7 -3
- package/dist/locales/it.json +7 -3
- package/dist/locales/ja.json +7 -3
- package/dist/locales/nl.json +7 -3
- package/dist/locales/pl.json +7 -3
- package/dist/locales/pt.json +7 -3
- package/dist/locales/ro.json +7 -3
- package/dist/locales/ru.json +7 -3
- package/dist/locales/sq.json +7 -3
- package/dist/locales/sv.json +7 -3
- package/dist/locales/tr.json +7 -3
- package/dist/locales/zh.json +7 -3
- package/dist/patterns/marketplace-app-shell/index.js +1 -1
- package/dist/patterns/patient-shell/index.js +1 -1
- package/dist/tokens.css +1 -1
- package/package.json +1 -1
- package/dist/_chunks/agenda-card-BaSfVfrL.js.map +0 -1
- package/dist/_chunks/agenda-tray-DQayYmQ0.js +0 -165
- package/dist/_chunks/agenda-tray-DQayYmQ0.js.map +0 -1
- package/dist/_chunks/ai-tools-rail-CYLWrRmm.js +0 -280
- package/dist/_chunks/ai-tools-rail-CYLWrRmm.js.map +0 -1
- package/dist/_chunks/alert-CUTxnym2.js.map +0 -1
- package/dist/_chunks/circle-arrow-up-CC_85SuH.js +0 -16
- package/dist/_chunks/circle-arrow-up-CC_85SuH.js.map +0 -1
- package/dist/_chunks/dropdown-menu-CUEXqKis.js +0 -299
- package/dist/_chunks/dropdown-menu-CUEXqKis.js.map +0 -1
- package/dist/_chunks/insert-result-DNdi_JYW.js +0 -683
- package/dist/_chunks/insert-result-DNdi_JYW.js.map +0 -1
- package/dist/_chunks/sidebar-h78cTNLh.js.map +0 -1
- package/dist/_chunks/task-card-CPyQ5AXC.js.map +0 -1
- package/dist/_chunks/task-tray-B8jFv5FV.js +0 -196
- package/dist/_chunks/task-tray-B8jFv5FV.js.map +0 -1
- package/dist/_chunks/use-theme-C2dHKUAN.js +0 -145
- package/dist/_chunks/use-theme-C2dHKUAN.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"insert-result-DNdi_JYW.js","sources":["../../node_modules/lucide-react/dist/esm/icons/type.js","../../src/components/_shared/banded-gauge.tsx","../../src/components/_shared/insert-result.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.8.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.js';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 4v16\", key: \"1654pz\" }],\n [\"path\", { d: \"M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2\", key: \"e0r10z\" }],\n [\"path\", { d: \"M9 20h6\", key: \"s66wpe\" }]\n];\nconst Type = createLucideIcon(\"type\", __iconNode);\n\nexport { __iconNode, Type as default };\n//# sourceMappingURL=type.js.map\n","/* ------------------------------------------------------------------ */\n/* Shared banded-linear gauge — a horizontal track split into coloured */\n/* zones with a marker at the value's position. */\n/* */\n/* Two surfaces, one geometry: */\n/* */\n/* • the INSERT CARD bakes a PNG (`<img>` → `<canvas>` → `toBlob`), */\n/* so it needs concrete colours embedded in an SVG STRING. It calls */\n/* {@link buildBandedGaugeSvgString} with a resolver that maps a */\n/* token NAME to the probe-resolved `rgb(...)` (same path the donut */\n/* gauge uses in `insert-result.tsx`). */\n/* */\n/* • the ON-SCREEN widget renders {@link BandedGauge} as JSX. Its */\n/* resolver returns `var(<token>)` so the live CSS theme resolves */\n/* each band fill — it tracks a theme switch with no JS re-sample. */\n/* */\n/* Both surfaces derive every coordinate from */\n/* {@link computeBandedGaugeGeometry}, so the card raster and the live */\n/* widget are pixel-equivalent for the same model — no drift. */\n/* */\n/* Native SVG only: `<rect>` / `<line>` / `<polygon>` / `<path>` / */\n/* `<text>` / `<title>`. NEVER `<foreignObject>` (it silently drops in */\n/* the `<img>` raster) and no charting library. */\n/* */\n/* RTL: the numeric scale ALWAYS runs low→high left-to-right, even under */\n/* `dir=\"rtl\"` — a measurement axis is not a reading axis, so the gauge */\n/* root pins `dir=\"ltr\"`. Logical properties govern only the SURROUNDING */\n/* layout (the card/widget that hosts the gauge), never the axis itself. */\n/* ------------------------------------------------------------------ */\n\nimport { forwardRef } from 'react';\n\n/* ------------------------------------------------------------------ */\n/* Model + WHO BMI source-of-truth */\n/* ------------------------------------------------------------------ */\n\n/** One coloured zone of the track, filled up to (and excluding) `upTo`. */\nexport interface BandedGaugeBand {\n /**\n * Upper boundary of the band on the scale (exclusive). The final band's\n * `upTo` is conventionally the scale `max` so it fills to the bar end.\n */\n upTo: number;\n /**\n * DS token NAME for the band fill — e.g. `'--info'`, `'--success'`,\n * `'--warning-readable'`, `'--destructive'`. Resolved by the surface's\n * `resolve` callback (concrete `rgb()` for the card, `var(<token>)` for the\n * widget). Never a hex/rgb literal in source.\n */\n colorToken: string;\n}\n\n/**\n * A banded-linear gauge. Every visible string (`valueLabel`, `categoryLabel`,\n * `rangeLabel`, `ariaLabel`) arrives ALREADY TRANSLATED — this module is\n * i18n-agnostic; the BMI calculator supplies `t()`-resolved text.\n */\nexport interface BandedGaugeModel {\n /** The true value (printed verbatim even when clamped to a bar end). */\n value: number;\n /** Ascending coloured zones; the last `upTo` should equal `max`. */\n bands: BandedGaugeBand[];\n /** Low end of the drawn scale (maps to the bar's inline start). */\n min: number;\n /** High end of the drawn scale (maps to the bar's inline end). */\n max: number;\n /** Big number rendered above the marker (e.g. `'24.6'`). */\n valueLabel: string;\n /** Band name shown beside the value (e.g. `'normal'`). Pre-translated. */\n categoryLabel?: string;\n /** Range string for the band (e.g. `'18.5–24.9'`). Pre-translated. */\n rangeLabel?: string;\n /** Full accessible name, e.g. `'BMI 24.6 — normal (18.5–24.9)'`. */\n ariaLabel: string;\n /** Threshold tick values drawn under the bar (e.g. `[18.5, 25, 30]`). */\n ticks?: number[];\n}\n\n/* ---- WHO BMI bands — shared source of truth for both surfaces -------- */\n\n/** Drawn BMI scale: 15 (deep underweight) → 40 (deep obesity). */\nexport const BMI_BANDED_MIN = 15;\nexport const BMI_BANDED_MAX = 40;\n\n/** WHO adult cut-offs drawn as ticks under the bar. */\nexport const BMI_BAND_THRESHOLDS = [18.5, 25, 30] as const;\n\n/**\n * The four WHO zones as `{ upTo, colorToken }`, plus the scale + ticks, so\n * both the on-screen widget and the insert card share ONE definition:\n *\n * underweight < 18.5 → `--info`\n * normal 18.5–24.9 → `--success`\n * overweight 25–29.9 → `--warning-readable` (contrast-safe orange)\n * obese ≥ 30 → `--destructive` (one obese zone)\n *\n * `--warning-readable` is the kit's contrast-safe orange token — it already\n * resolves correctly per theme (orange-600 in light/non-accessible, `--warning`\n * elsewhere), so NO `document.documentElement` JS override is needed here.\n */\nexport function bmiBands(): {\n bands: BandedGaugeBand[];\n min: number;\n max: number;\n ticks: number[];\n} {\n return {\n bands: [\n { upTo: 18.5, colorToken: '--info' },\n { upTo: 25, colorToken: '--success' },\n { upTo: 30, colorToken: '--warning-readable' },\n { upTo: BMI_BANDED_MAX, colorToken: '--destructive' },\n ],\n min: BMI_BANDED_MIN,\n max: BMI_BANDED_MAX,\n ticks: [...BMI_BAND_THRESHOLDS],\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Geometry — single source of positional truth */\n/* ------------------------------------------------------------------ */\n\n/** One filled zone rect in card/widget coordinates. */\nexport interface BandRect {\n /** Inline-start x of the zone. */\n x: number;\n /** Zone width. */\n w: number;\n /** Token NAME to fill it with (resolved by the surface). */\n colorToken: string;\n}\n\n/** The value marker: its drawn x plus the clamp envelope it lives in. */\nexport interface MarkerGeometry {\n /** Drawn x of the marker (clamped into `[clampedStart, clampedEnd]`). */\n x: number;\n /** Inline-start x the marker can reach (bar start). */\n clampedStart: number;\n /** Inline-end x the marker can reach (bar end). */\n clampedEnd: number;\n /**\n * `'start'` when the true value sits below `min` (marker pinned to the bar\n * start), `'end'` when it sits above `max`, `null` when it's in range. Drives\n * the out-of-range caret/chevron.\n */\n overflow: 'start' | 'end' | null;\n}\n\n/** A threshold tick: its x plus the scale value it marks. */\nexport interface TickGeometry {\n x: number;\n value: number;\n}\n\n/** Everything the two builders need, derived once. */\nexport interface BandedGaugeGeometry {\n /** Outer SVG width. */\n width: number;\n /** Outer SVG height. */\n height: number;\n /** Inline-start x of the bar. */\n barStart: number;\n /** Inline-end x of the bar. */\n barEnd: number;\n /** Bar top y. */\n barY: number;\n /** Bar thickness. */\n barH: number;\n /** Bar corner radius. */\n barRadius: number;\n /** Coloured zones, left → right. */\n bands: BandRect[];\n /** The value marker. */\n marker: MarkerGeometry;\n /** Threshold ticks under the bar. */\n ticks: TickGeometry[];\n /** Baseline y for the value label above the bar. */\n valueLabelY: number;\n /** Baseline y for the tick number labels under the bar. */\n tickLabelY: number;\n /** Pre-translated value label (verbatim from the model). */\n valueLabel: string;\n /** Optional `category (range)` summary shown beside the value. */\n summaryLabel: string;\n /** Full accessible name for `<title>` / `aria-label`. */\n ariaLabel: string;\n}\n\n/** Layout knobs for {@link computeBandedGaugeGeometry}. */\nexport interface BandedGaugeLayoutOptions {\n /** Outer SVG width. */\n width: number;\n /** Outer SVG height. */\n height: number;\n}\n\n/* Internal layout constants — the inset of the bar within the SVG box, the\n bar thickness, and the vertical rhythm. Pure numbers (no design tokens) —\n these are geometry, not colours/spacing-from-CSS. */\nexport const INSET_X = 14;\nconst BAR_H = 12;\nconst BAR_RADIUS = BAR_H / 2;\nconst VALUE_LABEL_BASELINE = 18; // y of the value label baseline\nconst BAR_TOP_GAP = 12; // gap below the value label to the bar\nconst TICK_LABEL_GAP = 16; // gap below the bar to the tick numbers\n\n/** Linear map of a scale value to a bar x, NOT clamped. */\nfunction scaleToX(\n value: number,\n min: number,\n max: number,\n barStart: number,\n barEnd: number,\n): number {\n if (max <= min) return barStart;\n const t = (value - min) / (max - min);\n return barStart + t * (barEnd - barStart);\n}\n\n/**\n * Pure geometry pass — the ONE place value→x mapping, band widths, marker\n * clamping, and tick positions are computed. Both the SVG-string builder and\n * the JSX component consume this so the two surfaces never drift.\n *\n * The marker x is CLAMPED to `[barStart, barEnd]`, but `valueLabel` always\n * prints the true value; `marker.overflow` flags an out-of-range value so the\n * surface can draw a caret at the clamped end.\n */\nexport function computeBandedGaugeGeometry(\n model: BandedGaugeModel,\n { width, height }: BandedGaugeLayoutOptions,\n): BandedGaugeGeometry {\n const barStart = INSET_X;\n const barEnd = width - INSET_X;\n const barY = VALUE_LABEL_BASELINE + BAR_TOP_GAP;\n const valueLabelY = VALUE_LABEL_BASELINE;\n const tickLabelY = barY + BAR_H + TICK_LABEL_GAP;\n\n // Bands fill consecutively from the scale min up to each `upTo`, the last\n // capping at `max`. A band whose range falls outside the scale collapses to\n // zero width rather than spilling past the bar.\n let cursor = model.min;\n const bands: BandRect[] = model.bands.map((band) => {\n const lower = Math.max(model.min, Math.min(cursor, model.max));\n const upper = Math.max(model.min, Math.min(band.upTo, model.max));\n cursor = band.upTo;\n const x = scaleToX(lower, model.min, model.max, barStart, barEnd);\n const xEnd = scaleToX(upper, model.min, model.max, barStart, barEnd);\n return { x, w: Math.max(0, xEnd - x), colorToken: band.colorToken };\n });\n\n // Marker: true x, then clamp into the bar, flagging out-of-range.\n const rawX = scaleToX(model.value, model.min, model.max, barStart, barEnd);\n const overflow: MarkerGeometry['overflow'] =\n model.value < model.min ? 'start' : model.value > model.max ? 'end' : null;\n const markerX = Math.min(barEnd, Math.max(barStart, rawX));\n\n const ticks: TickGeometry[] = (model.ticks ?? [])\n .filter((value) => value >= model.min && value <= model.max)\n .map((value) => ({\n x: scaleToX(value, model.min, model.max, barStart, barEnd),\n value,\n }));\n\n const summaryLabel = model.categoryLabel\n ? model.rangeLabel\n ? `${model.categoryLabel} (${model.rangeLabel})`\n : model.categoryLabel\n : '';\n\n return {\n width,\n height,\n barStart,\n barEnd,\n barY,\n barH: BAR_H,\n barRadius: BAR_RADIUS,\n bands,\n marker: {\n x: markerX,\n clampedStart: barStart,\n clampedEnd: barEnd,\n overflow,\n },\n ticks,\n valueLabelY,\n tickLabelY,\n valueLabel: model.valueLabel,\n summaryLabel,\n ariaLabel: model.ariaLabel,\n };\n}\n\n/** Round to 2dp so emitted coordinates stay compact + deterministic. */\nconst r2 = (n: number): number => Math.round(n * 100) / 100;\n\n/* ------------------------------------------------------------------ */\n/* SVG-string builder (insert card surface) */\n/* ------------------------------------------------------------------ */\n\n/** XML-escape a string for safe insertion into the SVG markup. */\nconst escapeXml = (s: string): string =>\n s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n\n/** A token-name → concrete-colour resolver supplied by each surface. */\nexport type ColorResolver = (colorToken: string) => string;\n\n/** Theme colours + font + resolver for {@link buildBandedGaugeSvgString}. */\nexport interface BandedGaugeSvgOptions {\n /**\n * Maps a band token NAME to the colour string painted into the markup. The\n * card passes a probe-resolved `rgb(...)` resolver so the baked PNG carries\n * theme-correct colours; never a literal in source.\n */\n resolve: ColorResolver;\n /** Font family for the text (resolved from the theme, e.g. `--font-sans`). */\n font: string;\n /** Foreground colour for the value label + marker (concrete). */\n fg: string;\n /** Muted colour for the tick numbers + summary (concrete). */\n muted: string;\n /** Track / unfilled-rail colour, also used for tick rules (concrete). */\n track: string;\n}\n\n/**\n * Build the banded gauge as a native-SVG `<g>` STRING the card can place at an\n * arbitrary offset. Pure native SVG (`<rect>`/`<line>`/`<polygon>`/`<text>`) —\n * no `<foreignObject>`. The bands fill from the resolver; the marker is a thin\n * vertical rule + a downward triangle; an out-of-range value adds a caret at\n * the clamped end.\n *\n * Returns just the `<g>…</g>` group (origin at 0,0) so the card can translate\n * it; the card wraps the whole gauge with the accessible name on its own\n * `role=\"img\"` group, but this group also carries a `<title>` for standalone\n * use (e.g. when rendered as a complete SVG in a test).\n */\n/**\n * Path for a band with independently rounded left/right corners. `<rect rx>`\n * rounds ALL four corners, which notches the inner band boundaries — so the\n * strip rounds only its OUTER corners (first band on the left, last on the\n * right) while every inner boundary stays a crisp vertical seam.\n */\nfunction bandPath(\n x: number,\n y: number,\n w: number,\n h: number,\n rL: number,\n rR: number,\n): string {\n const x2 = x + w;\n const y2 = y + h;\n const tr = rR > 0 ? `A${rR} ${rR} 0 0 1 ${r2(x2)} ${r2(y + rR)}` : '';\n const br = rR > 0 ? `A${rR} ${rR} 0 0 1 ${r2(x2 - rR)} ${r2(y2)}` : '';\n const bl = rL > 0 ? `A${rL} ${rL} 0 0 1 ${r2(x)} ${r2(y2 - rL)}` : '';\n const tl = rL > 0 ? `A${rL} ${rL} 0 0 1 ${r2(x + rL)} ${r2(y)}` : '';\n return `M${r2(x + rL)} ${r2(y)} H${r2(x2 - rR)} ${tr} V${r2(\n y2 - rR,\n )} ${br} H${r2(x + rL)} ${bl} V${r2(y + rL)} ${tl} Z`;\n}\n\nexport function buildBandedGaugeSvgString(\n geometry: BandedGaugeGeometry,\n options: BandedGaugeSvgOptions,\n): string {\n const { resolve, font, fg, muted, track } = options;\n const fontFamily = escapeXml(font);\n\n // Track rail behind the bands (so any inter-band gap reads as a rail, and the\n // rounded ends are consistent).\n const rail = `<rect x=\"${r2(geometry.barStart)}\" y=\"${r2(\n geometry.barY,\n )}\" width=\"${r2(geometry.barEnd - geometry.barStart)}\" height=\"${\n geometry.barH\n }\" rx=\"${geometry.barRadius}\" fill=\"${track}\"/>`;\n\n // Band zones. Only the strip's outer corners round (first band on the left,\n // last on the right) via `bandPath`; every inner boundary is a crisp seam.\n const bandCount = geometry.bands.length;\n const bandRects = geometry.bands\n .map((band, i) => {\n const fill = resolve(band.colorToken);\n const rL = i === 0 ? geometry.barRadius : 0;\n const rR = i === bandCount - 1 ? geometry.barRadius : 0;\n return `<path d=\"${bandPath(\n band.x,\n geometry.barY,\n band.w,\n geometry.barH,\n rL,\n rR,\n )}\" fill=\"${fill}\"/>`;\n })\n .join('');\n\n // Threshold ticks: a short hairline under the bar + the value number.\n const tickY1 = geometry.barY + geometry.barH;\n const tickY2 = tickY1 + 4;\n const ticks = geometry.ticks\n .map((tick) => {\n const rule = `<line x1=\"${r2(tick.x)}\" y1=\"${r2(tickY1)}\" x2=\"${r2(\n tick.x,\n )}\" y2=\"${r2(tickY2)}\" stroke=\"${track}\" stroke-width=\"1\"/>`;\n const label = `<text x=\"${r2(\n tick.x,\n )}\" y=\"${r2(geometry.tickLabelY)}\" text-anchor=\"middle\" font-family=\"${fontFamily}\" font-size=\"9\" fill=\"${muted}\">${escapeXml(\n String(tick.value),\n )}</text>`;\n return rule + label;\n })\n .join('');\n\n // Marker: thin vertical rule spanning the bar + a downward triangle resting\n // on the bar top. Drawn in the foreground colour so it reads over any band.\n const mx = r2(geometry.marker.x);\n const ruleTop = geometry.barY - 3;\n const ruleBottom = geometry.barY + geometry.barH + 3;\n const markerRule = `<line x1=\"${mx}\" y1=\"${r2(ruleTop)}\" x2=\"${mx}\" y2=\"${r2(\n ruleBottom,\n )}\" stroke=\"${fg}\" stroke-width=\"2\" stroke-linecap=\"round\"/>`;\n const triTop = geometry.barY - 4;\n const triangle = `<polygon points=\"${mx},${r2(geometry.barY + 1)} ${r2(\n geometry.marker.x - 4,\n )},${r2(triTop)} ${r2(geometry.marker.x + 4)},${r2(triTop)}\" fill=\"${fg}\"/>`;\n\n // Out-of-range caret: a chevron at the clamped end pointing outward.\n let caret = '';\n if (geometry.marker.overflow) {\n const cy = geometry.barY + geometry.barH / 2;\n if (geometry.marker.overflow === 'start') {\n const tipX = geometry.barStart - 2;\n caret = `<polyline points=\"${r2(tipX + 5)},${r2(cy - 4)} ${r2(\n tipX,\n )},${r2(cy)} ${r2(tipX + 5)},${r2(\n cy + 4,\n )}\" fill=\"none\" stroke=\"${fg}\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>`;\n } else {\n const tipX = geometry.barEnd + 2;\n caret = `<polyline points=\"${r2(tipX - 5)},${r2(cy - 4)} ${r2(\n tipX,\n )},${r2(cy)} ${r2(tipX - 5)},${r2(\n cy + 4,\n )}\" fill=\"none\" stroke=\"${fg}\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>`;\n }\n }\n\n // Value label (bold) + the muted category(range) summary trailing it.\n const valueLabel = `<text x=\"${r2(\n geometry.barStart,\n )}\" y=\"${r2(geometry.valueLabelY)}\" font-family=\"${fontFamily}\" font-size=\"13\" font-weight=\"700\" fill=\"${fg}\">${escapeXml(\n geometry.valueLabel,\n )}</text>`;\n const summary = geometry.summaryLabel\n ? `<text x=\"${r2(geometry.barEnd)}\" y=\"${r2(\n geometry.valueLabelY,\n )}\" text-anchor=\"end\" font-family=\"${fontFamily}\" font-size=\"10\" fill=\"${muted}\">${escapeXml(\n geometry.summaryLabel,\n )}</text>`\n : '';\n\n const title = `<title>${escapeXml(geometry.ariaLabel)}</title>`;\n\n return `<g role=\"img\" aria-label=\"${escapeXml(\n geometry.ariaLabel,\n )}\">${title}${rail}${bandRects}${ticks}${markerRule}${triangle}${caret}${valueLabel}${summary}</g>`;\n}\n\n/* ------------------------------------------------------------------ */\n/* React component (on-screen widget surface) */\n/* ------------------------------------------------------------------ */\n\n/** Default on-screen gauge box. */\nconst DEFAULT_WIDTH = 260;\nexport const DEFAULT_HEIGHT = 64;\n\n/**\n * The on-screen resolver: a token NAME → `var(<token>)`. The live CSS theme\n * resolves it, so a theme switch repaints the bands with no JS re-sample. This\n * mirrors the card's concrete-colour resolver one-for-one on geometry.\n */\nfunction cssVarResolver(colorToken: string): string {\n return `var(${colorToken})`;\n}\n\nexport interface BandedGaugeProps {\n /** The gauge model (value, bands, scale, pre-translated labels). */\n model: BandedGaugeModel;\n /** SVG width. Defaults to {@link DEFAULT_WIDTH}. */\n width?: number;\n /** SVG height. Defaults to {@link DEFAULT_HEIGHT}. */\n height?: number;\n /** Extra class names on the root `<svg>`. */\n className?: string;\n}\n\n/**\n * Presentational banded-linear gauge for the on-screen widget. Renders the SAME\n * geometry as {@link buildBandedGaugeSvgString} but as JSX, filling each band\n * with `fill=\"var(<token>)\"` so the live theme resolves the colour (and a theme\n * switch repaints with no re-sample). Visually equivalent to the card string.\n *\n * The track + marker are decorative; the accessible name on the root carries\n * the meaning (`role=\"img\"` + `aria-label`, mirrored in `<title>`). All text in\n * the model is pre-translated by the caller.\n *\n * The measurement axis runs low→high left-to-right regardless of document\n * direction — SVG coordinates are inherently LTR (a `<rect x>` is unaffected by\n * `direction`), and `direction=\"ltr\"` is pinned on the root to keep any nested\n * `<text>` directionality explicit. Logical properties govern the surrounding\n * layout, never this axis.\n */\nexport const BandedGauge = forwardRef<SVGSVGElement, BandedGaugeProps>(\n function BandedGauge(\n { model, width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT, className },\n ref,\n ) {\n const g = computeBandedGaugeGeometry(model, { width, height });\n const tickY1 = g.barY + g.barH;\n const tickY2 = tickY1 + 4;\n const ruleTop = g.barY - 3;\n const ruleBottom = g.barY + g.barH + 3;\n const triTop = g.barY - 4;\n const bandCount = g.bands.length;\n const caretCy = g.barY + g.barH / 2;\n\n return (\n <svg\n ref={ref}\n data-component=\"banded-gauge\"\n direction=\"ltr\"\n role=\"img\"\n aria-label={g.ariaLabel}\n width={width}\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n className={['ds:[font-family:var(--font-sans)]', className]\n .filter(Boolean)\n .join(' ')}\n >\n <title>{g.ariaLabel}</title>\n\n {/* Track rail behind the zones. */}\n <rect\n x={r2(g.barStart)}\n y={r2(g.barY)}\n width={r2(g.barEnd - g.barStart)}\n height={g.barH}\n rx={g.barRadius}\n className=\"ds:fill-[color:var(--muted)]\"\n />\n\n {/* Coloured band zones — fill via the live CSS var. Only the strip's\n outer corners round; inner boundaries stay crisp (see bandPath). */}\n {g.bands.map((band, i) => (\n <path\n key={`${band.colorToken}-${i}`}\n d={bandPath(\n band.x,\n g.barY,\n band.w,\n g.barH,\n i === 0 ? g.barRadius : 0,\n i === bandCount - 1 ? g.barRadius : 0,\n )}\n fill={cssVarResolver(band.colorToken)}\n />\n ))}\n\n {/* Threshold ticks: hairline + number. */}\n {g.ticks.map((tick) => (\n <g key={tick.value}>\n <line\n x1={r2(tick.x)}\n y1={r2(tickY1)}\n x2={r2(tick.x)}\n y2={r2(tickY2)}\n strokeWidth={1}\n className=\"ds:stroke-[color:var(--border)]\"\n />\n <text\n x={r2(tick.x)}\n y={r2(g.tickLabelY)}\n textAnchor=\"middle\"\n fontSize={9}\n className=\"ds:fill-[color:var(--muted-foreground)]\"\n >\n {tick.value}\n </text>\n </g>\n ))}\n\n {/* Marker: vertical rule + triangle. */}\n <line\n x1={r2(g.marker.x)}\n y1={r2(ruleTop)}\n x2={r2(g.marker.x)}\n y2={r2(ruleBottom)}\n strokeWidth={2}\n strokeLinecap=\"round\"\n className=\"ds:stroke-[color:var(--foreground)]\"\n />\n <polygon\n points={`${r2(g.marker.x)},${r2(g.barY + 1)} ${r2(\n g.marker.x - 4,\n )},${r2(triTop)} ${r2(g.marker.x + 4)},${r2(triTop)}`}\n className=\"ds:fill-[color:var(--foreground)]\"\n />\n\n {/* Out-of-range caret at the clamped end. */}\n {g.marker.overflow === 'start' ? (\n <polyline\n points={`${r2(g.barStart + 3)},${r2(caretCy - 4)} ${r2(\n g.barStart - 2,\n )},${r2(caretCy)} ${r2(g.barStart + 3)},${r2(caretCy + 4)}`}\n fill=\"none\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"ds:stroke-[color:var(--foreground)]\"\n />\n ) : null}\n {g.marker.overflow === 'end' ? (\n <polyline\n points={`${r2(g.barEnd - 3)},${r2(caretCy - 4)} ${r2(\n g.barEnd + 2,\n )},${r2(caretCy)} ${r2(g.barEnd - 3)},${r2(caretCy + 4)}`}\n fill=\"none\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"ds:stroke-[color:var(--foreground)]\"\n />\n ) : null}\n\n {/* Value label + muted summary. */}\n <text\n x={r2(g.barStart)}\n y={r2(g.valueLabelY)}\n fontSize={13}\n fontWeight={700}\n className=\"ds:fill-[color:var(--foreground)]\"\n >\n {g.valueLabel}\n </text>\n {g.summaryLabel ? (\n <text\n x={r2(g.barEnd)}\n y={r2(g.valueLabelY)}\n textAnchor=\"end\"\n fontSize={10}\n className=\"ds:fill-[color:var(--muted-foreground)]\"\n >\n {g.summaryLabel}\n </text>\n ) : null}\n </svg>\n );\n },\n);\n\nBandedGauge.displayName = 'BandedGauge';\n","/* ------------------------------------------------------------------ */\n/* InsertButton — shared \"use this result\" control for the calculator */\n/* toolset. */\n/* */\n/* Two variants, one set of payload builders: */\n/* */\n/* • `insert` (default) — editor-extension context. Each button hands */\n/* the built InsertPayload to `onInsert`, who drops it into whatever */\n/* editor they use. The kit never touches an editor. */\n/* */\n/* • `copy` — app-shell context. Each button writes the chosen */\n/* representation(s) to the clipboard as a multi-format ClipboardItem */\n/* so a single copy serves any paste target. The image format is a */\n/* REAL raster PNG (the SVG card rasterised to a canvas) — clipboards */\n/* reject SVG as an image, so copying the data-URI as text is the */\n/* exact \"copied text without the image\" bug this variant fixes. */\n/* */\n/* Three inline buttons, one per mode (text / image / text + image). */\n/* */\n/* The SVG card embeds CONCRETE colours so it renders standalone as an */\n/* <img>. To stay within the \"no hardcoded colours\" rule, those colours */\n/* are sampled at click time from hidden probe spans that carry the */\n/* token utility classes — i.e. resolved from the live theme, never */\n/* written as literals in source. */\n/* ------------------------------------------------------------------ */\n\nimport { forwardRef, useRef } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { cva } from 'class-variance-authority';\nimport { Type, Image as ImageIcon, Layers } from 'lucide-react';\nimport { Button, type ButtonProps } from '../button';\nimport {\n computeBandedGaugeGeometry,\n buildBandedGaugeSvgString,\n INSET_X as BANDED_GAUGE_INSET_X,\n DEFAULT_HEIGHT as BANDED_GAUGE_HEIGHT,\n type BandedGaugeBand,\n} from './banded-gauge';\n\nexport type InsertMode = 'text' | 'image' | 'text-image';\n\nexport type InsertVariant = 'insert' | 'copy';\n\n/**\n * The handful of lucide glyphs the result-card header can carry. Each maps to a\n * static native-SVG geometry string in {@link ICON_GEOMETRY}, hand-transcribed\n * from lucide-react 1.8.0's `__iconNode` arrays (pinned to that version so the\n * paths match the on-screen React glyphs exactly). We do NOT import the lucide\n * React components into the raster path — they can't be serialised into the\n * `<img>` data-URI — so the geometry is inlined as raw `<path>` elements.\n */\nexport type IconKey =\n | 'activity'\n | 'scale'\n | 'ruler'\n | 'calendar'\n | 'calendar-heart'\n | 'baby'\n | 'heart'\n | 'droplets'\n | 'clock'\n | 'tag'\n | 'trending-up'\n | 'percent';\n\n/** lucide native authoring grid — every glyph is drawn on a 24×24 viewBox. */\nconst ICON_VIEWBOX = 24;\n/** Header glyph render size (px in card space). */\nconst ICON_SLOT = 18;\n/** Leading field-row glyph render size (px in card space). */\nconst FIELD_ICON_SLOT = 12;\n\n/**\n * Inner SVG element strings for each glyph, copied verbatim from lucide-react\n * 1.8.0 `__iconNode` (the `key` attr dropped — it's React-only). Rendered inside\n * a `<g>` carrying lucide's canonical presentation attrs (`fill=\"none\"`,\n * `stroke-width=\"2\"`, round caps/joins), scaled `slot/24` to the target size.\n * Pure `<path>`/`<rect>`/`<circle>` — native SVG, raster-safe, no `<foreignObject>`.\n */\nconst ICON_GEOMETRY: Record<IconKey, string> = {\n activity:\n '<path d=\"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2\"/>',\n scale:\n '<path d=\"M12 3v18\"/><path d=\"m19 8 3 8a5 5 0 0 1-6 0zV7\"/><path d=\"M3 7h1a17 17 0 0 0 8-2 17 17 0 0 0 8 2h1\"/><path d=\"m5 8 3 8a5 5 0 0 1-6 0zV7\"/><path d=\"M7 21h10\"/>',\n ruler:\n '<path d=\"M21.3 15.3a2.4 2.4 0 0 1 0 3.4l-2.6 2.6a2.4 2.4 0 0 1-3.4 0L2.7 8.7a2.41 2.41 0 0 1 0-3.4l2.6-2.6a2.41 2.41 0 0 1 3.4 0Z\"/><path d=\"m14.5 12.5 2-2\"/><path d=\"m11.5 9.5 2-2\"/><path d=\"m8.5 6.5 2-2\"/><path d=\"m17.5 15.5 2-2\"/>',\n calendar:\n '<path d=\"M8 2v4\"/><path d=\"M16 2v4\"/><rect width=\"18\" height=\"18\" x=\"3\" y=\"4\" rx=\"2\"/><path d=\"M3 10h18\"/>',\n 'calendar-heart':\n '<path d=\"M12.127 22H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v5.125\"/><path d=\"M14.62 18.8A2.25 2.25 0 1 1 18 15.836a2.25 2.25 0 1 1 3.38 2.966l-2.626 2.856a.998.998 0 0 1-1.507 0z\"/><path d=\"M16 2v4\"/><path d=\"M3 10h18\"/><path d=\"M8 2v4\"/>',\n baby: '<path d=\"M10 16c.5.3 1.2.5 2 .5s1.5-.2 2-.5\"/><path d=\"M15 12h.01\"/><path d=\"M19.38 6.813A9 9 0 0 1 20.8 10.2a2 2 0 0 1 0 3.6 9 9 0 0 1-17.6 0 2 2 0 0 1 0-3.6A9 9 0 0 1 12 3c2 0 3.5 1.1 3.5 2.5s-.9 2.5-2 2.5c-.8 0-1.5-.4-1.5-1\"/><path d=\"M9 12h.01\"/>',\n heart:\n '<path d=\"M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5\"/>',\n droplets:\n '<path d=\"M7 16.3c2.2 0 4-1.83 4-4.05 0-1.16-.57-2.26-1.71-3.19S7.29 6.75 7 5.3c-.29 1.45-1.14 2.84-2.29 3.76S3 11.1 3 12.25c0 2.22 1.8 4.05 4 4.05z\"/><path d=\"M12.56 6.6A10.97 10.97 0 0 0 14 3.02c.5 2.5 2 4.9 4 6.5s3 3.5 3 5.5a6.98 6.98 0 0 1-11.91 4.97\"/>',\n clock: '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 6v6l4 2\"/>',\n tag: '<path d=\"M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z\"/><circle cx=\"7.5\" cy=\"7.5\" r=\".5\" fill=\"currentColor\"/>',\n 'trending-up': '<path d=\"M16 7h6v6\"/><path d=\"m22 7-8.5 8.5-5-5L2 17\"/>',\n percent:\n '<line x1=\"19\" x2=\"5\" y1=\"5\" y2=\"19\"/><circle cx=\"6.5\" cy=\"6.5\" r=\"2.5\"/><circle cx=\"17.5\" cy=\"17.5\" r=\"2.5\"/>',\n};\n\n/** True when `key` is a known {@link IconKey} with embedded geometry. */\nfunction isIconKey(key: string): key is IconKey {\n return Object.prototype.hasOwnProperty.call(ICON_GEOMETRY, key);\n}\n\n/**\n * Emit a glyph as a translated + scaled `<g>` carrying lucide's canonical\n * presentation attrs. `slot` is the on-card render size; the group scales the\n * 24-grid geometry down to it (so `stroke-width=\"2\"` in the grid yields a\n * proportionally lighter visual stroke, matching lucide's optical weight).\n * Returns `''` for an unknown key so an unmapped card simply omits the glyph.\n */\nfunction buildIconGroup(\n icon: string,\n colour: string,\n x: number,\n y: number,\n slot: number,\n): string {\n if (!isIconKey(icon)) return '';\n const scale = slot / ICON_VIEWBOX;\n // `color` is set alongside `stroke` so the rare glyph that fills a detail with\n // `currentColor` (e.g. `tag`'s centre dot) resolves to the same glyph colour.\n return `<g transform=\"translate(${x} ${y}) scale(${scale})\" fill=\"none\" color=\"${colour}\" stroke=\"${colour}\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">${ICON_GEOMETRY[icon]}</g>`;\n}\n\nexport interface InsertCardField {\n label: string;\n value: string;\n /**\n * Optional leading glyph for the row, drawn at {@link FIELD_ICON_SLOT} in\n * place of the default bullet dot. One of the known {@link IconKey} names; an\n * unknown / omitted value falls back to the muted bullet (fully\n * back-compatible — a field without an icon renders exactly as before).\n */\n icon?: IconKey;\n}\n\n/**\n * Radial gauge — a hand-rolled native-SVG donut (track `<circle>` + value arc\n * via `stroke-dasharray`) drawn in the card's inline-end corner box. Survives\n * the `<img>` → `<canvas>` → `toBlob` raster. No `<foreignObject>`, no charting\n * lib.\n *\n * This is the original gauge shape; `variant` is optional and defaults to\n * `'radial'`, so a gauge object authored before the banded variant existed\n * renders exactly as before.\n */\nexport interface InsertCardRadialGauge {\n /** Discriminant. Optional — omitted means `'radial'` (back-compat). */\n variant?: 'radial';\n /** Big number rendered in the gauge centre (e.g. `'22.4'`). */\n value: string;\n /**\n * Filled fraction of the ring, `0`–`1`. Takes precedence when supplied;\n * otherwise derived from a `value`/`max` numeric parse (falling back to a\n * full ring when neither is numeric).\n */\n fraction?: number;\n /** Denominator used to derive `fraction` when `fraction` is omitted. */\n max?: number;\n /**\n * Number of evenly-spaced segment gaps to notch into the ring (e.g. `4` for\n * a quartered dial). `0`/omitted draws a continuous arc.\n */\n segments?: number;\n /**\n * DS token NAME for the arc colour — e.g. `'--success'`, `'--warning'`,\n * `'--destructive'`, `'--info'`, or the light-orange overweight override.\n * Resolved to a concrete colour from a probe span at raster time; never a\n * hex literal in source.\n */\n colorToken: string;\n /** Small category label under the value inside the ring. */\n label?: string;\n}\n\n/**\n * Banded gauge — a full-width horizontal track split into coloured zones with a\n * marker at the value's position (the WHO BMI dial, drawn via the shared\n * `banded-gauge` module). It spans the card edge-to-edge below the field rows.\n * Same raster-safety guarantees as the radial donut: pure native SVG, no\n * `<foreignObject>`.\n *\n * Every visible string (`valueLabel`, `categoryLabel`, `rangeLabel`,\n * `ariaLabel`) arrives ALREADY TRANSLATED — the calculator supplies `t()`-\n * resolved text. Every band's `colorToken` is registered for probe sampling so\n * the baked raster carries theme-correct fills.\n */\nexport interface InsertCardBandedGauge {\n /** Discriminant for the banded layout. */\n variant: 'banded';\n /** The true value (printed verbatim even when clamped to a bar end). */\n value: number;\n /** Ascending coloured zones; the last `upTo` should equal `max`. */\n bands: BandedGaugeBand[];\n /** Low end of the drawn scale (maps to the bar's inline start). */\n min: number;\n /** High end of the drawn scale (maps to the bar's inline end). */\n max: number;\n /** Big number rendered above the marker (e.g. `'24.6'`). */\n valueLabel: string;\n /** Band name shown beside the value (e.g. `'normal'`). Pre-translated. */\n categoryLabel?: string;\n /** Range string for the band (e.g. `'18.5–24.9'`). Pre-translated. */\n rangeLabel?: string;\n /** Full accessible name, e.g. `'BMI 24.6 — normal (18.5–24.9)'`. */\n ariaLabel: string;\n /** Threshold tick values drawn under the bar (e.g. `[18.5, 25, 30]`). */\n ticks?: number[];\n}\n\n/**\n * Optional in-card gauge. A discriminated union on `variant`:\n *\n * • `'radial'` (default when `variant` is omitted) — the corner-box donut.\n * • `'banded'` — a full-width horizontal banded bar below the fields.\n */\nexport type InsertCardGauge = InsertCardRadialGauge | InsertCardBandedGauge;\n\n/** True when the gauge is the full-width banded variant. */\nfunction isBandedGauge(gauge: InsertCardGauge): gauge is InsertCardBandedGauge {\n return gauge.variant === 'banded';\n}\n\nexport interface InsertCardData {\n /** Card heading. */\n title: string;\n /** Key/value rows. */\n fields: InsertCardField[];\n /**\n * Optional header glyph drawn inline-end of the title, tinted with the card's\n * category colour ({@link InsertCardData.highlightToken}). One of the known\n * {@link IconKey} names; an unknown / omitted value simply skips the glyph\n * (fully back-compatible — a card without an icon renders as before).\n */\n icon?: IconKey;\n /** Optional highlighted line, rendered as a category chip (pill). */\n highlight?: string;\n /**\n * DS token NAME for the highlight chip fill. Defaults to the accent token\n * (`--primary`). The chip text uses the matching `<token>-foreground` when it\n * resolves, else falls back to the card background for contrast.\n */\n highlightToken?: string;\n /** Optional radial gauge drawn natively in the card. */\n gauge?: InsertCardGauge;\n /**\n * Optional brand wordmark line printed at the foot of the card.\n *\n * - omitted / `false` → no brand line and no footer at all; the card ends\n * after the fields/gauge.\n * - a string → that wordmark, rendered as a single quiet line (no hairline\n * rule above it).\n *\n * A `brand` passed to {@link SvgCardToPngOptions} overrides this per-render.\n */\n brand?: string | false;\n}\n\nexport interface InsertPayload {\n /** Which button the user chose. */\n mode: InsertMode;\n /** Plain-text summary. Always present. */\n text: string;\n /** Rich HTML summary (heading + list). Always present. */\n html: string;\n /**\n * Branded SVG result-card markup. Empty for mode `'text'`.\n *\n * Kept for back-compat and for callers that need the live, copy-pasteable\n * vector. NOTE: SVG can carry `<script>` and is routinely stripped by\n * rich-text sanitisers, so it is NOT the format to insert into an editor —\n * use {@link InsertPayload.pngDataUri} for that.\n */\n svg: string;\n /**\n * SVG as an `image/svg+xml` data URI for `<img src>`. Empty for `'text'`.\n *\n * Same caveat as {@link InsertPayload.svg}: fine for a preview `<img>`, but a\n * sanitiser-stripped vector once it reaches an editor. Prefer\n * {@link InsertPayload.pngDataUri}.\n */\n imageDataUri: string;\n /**\n * Async thunk that resolves the result-card raster — the format intended for\n * editor insertion. PNG is a flat raster: it carries no script and survives\n * the rich-text sanitiser that strips SVG.\n *\n * Resolves to `{ dataUri, width, height }` where `width`/`height` are the\n * **logical (un-scaled) CSS pixel** dimensions: set them on the inserted\n * `<img width height>` and the supersampled (`>= 2×`) PNG renders crisp with\n * no consumer-side shim. For mode `'text'` resolves to an empty\n * `{ dataUri: '', width: 0, height: 0 }`. Rendered lazily so the synchronous\n * payload stays cheap; `await payload.pngDataUri()` only when you need it.\n *\n * @since 0.43.0 — this return shape changed from a bare `Promise<string>` to\n * `Promise<{ dataUri; width; height }>` (see CHANGELOG).\n */\n pngDataUri: () => Promise<InsertPngResult>;\n}\n\n/** Resolved PNG raster plus its logical (un-scaled) `<img>` dimensions. */\nexport interface InsertPngResult {\n /** `image/png` data URI, or `''` for the text-only mode. */\n dataUri: string;\n /** Logical (CSS px) width to set on the inserted `<img>`. `0` when empty. */\n width: number;\n /** Logical (CSS px) height to set on the inserted `<img>`. `0` when empty. */\n height: number;\n}\n\nexport interface InsertButtonProps {\n /** Structured result used to build every payload representation. */\n card: InsertCardData;\n /**\n * Verb the buttons perform. Defaults to `'insert'`.\n *\n * - `'insert'` — fires `onInsert(payload)` (editor-extension context).\n * - `'copy'` — writes the chosen representation(s) to the clipboard as a\n * multi-format `ClipboardItem` (app-shell context).\n */\n variant?: InsertVariant;\n /**\n * Receives the built payload when a button is pressed.\n *\n * Required for the `insert` variant; optional (and ignored) for `copy`.\n */\n onInsert?: (payload: InsertPayload) => void;\n /** `copy` variant only — fired after a successful clipboard write. */\n onCopy?: (mode: InsertMode) => void;\n /** `copy` variant only — fired if the clipboard write can't proceed. */\n onError?: (error: unknown) => void;\n /** Trigger size. Defaults to `'sm'`. */\n size?: 'sm' | 'md' | 'lg';\n /**\n * Visual intent of the three trigger buttons (text / image / text+image).\n * Mirrors the `Button` `intent` prop and applies to every trigger uniformly\n * so the three stay visually consistent. Defaults to `'primary'`.\n */\n intent?: ButtonProps['intent'];\n}\n\ninterface ThemeColours {\n fg: string;\n muted: string;\n accent: string;\n border: string;\n bg: string;\n font: string;\n /**\n * Concrete colours resolved from arbitrary DS token names, keyed by the token\n * name the caller passed (e.g. `'--success'`). Populated for the gauge arc\n * and the highlight chip; consulted by {@link buildResultCardSvg} via\n * {@link resolveToken}.\n */\n tokens?: Record<string, string>;\n}\n\n/* Fixed probe keys → the resolved colour they sample. */\nconst PROBE_KEYS = ['fg', 'muted', 'accent', 'border', 'bg'] as const;\n\n/** Default DS token names driving the chip and the on-token text colours. */\nconst DEFAULT_HIGHLIGHT_TOKEN = '--primary';\n\nconst SVG_W = 380;\n\n/** Strip a leading `--`/whitespace so a token name is a safe class/probe id. */\nconst tokenName = (token: string): string => token.trim().replace(/^--/, '');\n\n/**\n * The probe-span utility class that resolves a given token to a concrete colour\n * at sample time: the token is read as `var(<token>)` so `getComputedStyle`\n * returns the live theme's concrete `rgb()` — never a literal in source.\n */\nfunction probeClassForToken(token: string): string {\n return `ds:text-[color:var(${token})]`;\n}\n\n/**\n * The card's category fill token: the chip token when one is set, otherwise the\n * default highlight token. Drives the left accent rule, header icon, and\n * primary-value colour even on cards without a chip.\n */\nfunction categoryFillToken(card: InsertCardData): string {\n return card.highlightToken ?? DEFAULT_HIGHLIGHT_TOKEN;\n}\n\n/**\n * Extra `<token>` → resolved-colour probes a given card needs beyond the five\n * fixed keys: the gauge arc colour, the highlight chip fill (+ its `-foreground`\n * companion for contrasting on-token text), and the category solid that tints\n * the left-rule/header-icon/primary-value.\n */\nfunction extraTokensForCard(card: InsertCardData): string[] {\n const wanted = new Set<string>();\n if (card.highlight) {\n const fill = card.highlightToken ?? DEFAULT_HIGHLIGHT_TOKEN;\n wanted.add(fill);\n wanted.add(`${fill}-foreground`);\n }\n // The category accents (left rule, header icon, primary value) all use the\n // card's category solid — requested even without a chip.\n const category = categoryFillToken(card);\n wanted.add(category);\n // Gauge colours: the radial arc's single token, or EVERY banded zone token so\n // each band fill resolves to a probe-sampled rgb in the baked raster.\n if (card.gauge) {\n if (isBandedGauge(card.gauge)) {\n for (const band of card.gauge.bands) wanted.add(band.colorToken);\n } else {\n wanted.add(card.gauge.colorToken);\n }\n }\n return [...wanted];\n}\n\nfunction readThemeColours(\n probe: HTMLElement | null,\n extraTokens: string[] = [],\n): ThemeColours {\n const fallback: ThemeColours = {\n fg: 'currentColor',\n muted: 'currentColor',\n accent: 'currentColor',\n border: 'currentColor',\n bg: 'transparent',\n font: 'sans-serif',\n tokens: {},\n };\n if (!probe) return fallback;\n const read = (key: string): string => {\n const el = probe.querySelector<HTMLElement>(`[data-k=\"${key}\"]`);\n if (!el) return 'currentColor';\n return getComputedStyle(el).color || 'currentColor';\n };\n const tokens: Record<string, string> = {};\n for (const token of extraTokens) {\n const el = probe.querySelector<HTMLElement>(\n `[data-token=\"${tokenName(token)}\"]`,\n );\n if (el) {\n const colour = getComputedStyle(el).color;\n if (colour) tokens[token] = colour;\n }\n }\n return {\n fg: read('fg'),\n muted: read('muted'),\n accent: read('accent'),\n border: read('border'),\n bg: read('bg'),\n font: getComputedStyle(probe).fontFamily || 'sans-serif',\n tokens,\n };\n}\n\n/**\n * Internal resolved-colour shape, re-exported for tests that construct a card\n * raster without a live DOM probe. Not part of the public component API.\n */\nexport type ThemeColoursForTest = ThemeColours;\n\n/** Resolve a token NAME to a concrete colour, or a fallback when unsampled. */\nfunction resolveToken(\n c: ThemeColours,\n token: string | undefined,\n fallback: string,\n): string {\n if (!token) return fallback;\n return c.tokens?.[token] ?? fallback;\n}\n\nconst escapeXml = (s: string): string =>\n s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n\nexport function buildResultText(card: InsertCardData): string {\n const lines = [card.title];\n if (card.highlight) lines.push(card.highlight);\n for (const f of card.fields) lines.push(`• ${f.label}: ${f.value}`);\n return lines.join('\\n');\n}\n\nexport function buildResultHtml(card: InsertCardData): string {\n const items = card.fields\n .map((f) => `<li>${escapeXml(f.label)}: ${escapeXml(f.value)}</li>`)\n .join('');\n const highlight = card.highlight\n ? `<p><strong>${escapeXml(card.highlight)}</strong></p>`\n : '';\n return `<p><strong>${escapeXml(card.title)}</strong></p>${highlight}<ul>${items}</ul>`;\n}\n\n/* Layout constants — shared by the height calc and the markup builder. */\nconst PAD = 20;\nconst TITLE_BASELINE = PAD + 18;\nconst CHIP_H = 22;\nconst CHIP_GAP = 10;\nconst ROW_H = 22;\nconst FIELDS_GAP = 16;\nconst FOOTER_GAP = 12;\nconst FOOTER_H = 12;\nconst GAUGE_R = 34; // outer radius\nconst GAUGE_STROKE = 9;\nconst GAUGE_BOX = (GAUGE_R + GAUGE_STROKE) * 2; // gauge group bounding box\n\n/* Banded gauge — a full-width horizontal bar drawn BELOW the field rows. The\n bar inset (BANDED_GAUGE_INSET_X) and total occupied height (BANDED_GAUGE_HEIGHT)\n are imported from the shared module so the card and the gauge can't drift. */\nconst BANDED_GAUGE_GAP = 16; // gap between the fields block and the bar\n\n/* Accent geometry — additive \"pop\" elements that don't move existing baselines. */\nconst HEADER_ICON_BOX = ICON_SLOT; // header glyph render box\nconst FIELD_ICON_GAP = 6; // gap between a field-row glyph and its label text\n\n/**\n * Resolve the brand line for a render: option override wins over card field.\n * The default is **no brand** — an omitted brand renders no footer at all; a\n * string opts a single quiet wordmark line in.\n */\nfunction resolveBrand(\n card: InsertCardData,\n override: string | false | undefined,\n): string | false {\n const value = override !== undefined ? override : card.brand;\n if (typeof value === 'string') return value;\n return false;\n}\n\n/** Filled fraction `0`–`1` for a radial gauge, from `fraction` or `value`/`max`. */\nfunction gaugeFraction(gauge: InsertCardRadialGauge): number {\n if (typeof gauge.fraction === 'number') {\n return Math.min(1, Math.max(0, gauge.fraction));\n }\n const v = parseFloat(gauge.value);\n if (Number.isFinite(v) && typeof gauge.max === 'number' && gauge.max > 0) {\n return Math.min(1, Math.max(0, v / gauge.max));\n }\n return 1;\n}\n\ninterface CardLayout {\n hasChip: boolean;\n chipY: number;\n firstFieldY: number;\n fieldsEndY: number;\n /**\n * Top y of the banded-gauge group when the card carries a banded gauge, else\n * `null`. The radial gauge is `null` here — it lives in the corner box, not\n * the full-width band below the fields.\n */\n bandedGaugeY: number | null;\n footerY: number;\n height: number;\n}\n\n/** Compute the vertical layout once; reused by height + markup. */\nfunction layoutCard(card: InsertCardData, hasBrand: boolean): CardLayout {\n const hasChip = Boolean(card.highlight);\n const chipY = TITLE_BASELINE + CHIP_GAP; // chip top\n const firstFieldY =\n (hasChip ? chipY + CHIP_H + FIELDS_GAP : TITLE_BASELINE + FIELDS_GAP) +\n ROW_H -\n 6;\n const fieldsEndY = firstFieldY + Math.max(0, card.fields.length - 1) * ROW_H;\n\n const banded = card.gauge && isBandedGauge(card.gauge);\n const radial = card.gauge && !isBandedGauge(card.gauge);\n\n // Radial gauge: keep the body at least as tall as the corner donut so it\n // never clips. Banded gauge does NOT use the corner floor — it lives below.\n const bodyTop = hasChip ? chipY : TITLE_BASELINE;\n const gaugeFloor = radial ? bodyTop + GAUGE_BOX : 0;\n\n // Banded gauge: a full-width bar slung below the fields, then the footer/\n // height grow to clear it.\n const bandedGaugeY = banded ? fieldsEndY + BANDED_GAUGE_GAP : null;\n const bandedBottom =\n bandedGaugeY !== null ? bandedGaugeY + BANDED_GAUGE_HEIGHT : 0;\n\n const contentBottom = Math.max(fieldsEndY, gaugeFloor, bandedBottom);\n const footerY = hasBrand\n ? contentBottom + FOOTER_GAP + FOOTER_H - 4\n : contentBottom;\n const height = Math.round(footerY + (hasBrand ? FOOTER_GAP : PAD));\n return {\n hasChip,\n chipY,\n firstFieldY,\n fieldsEndY,\n bandedGaugeY,\n footerY,\n height,\n };\n}\n\n/** Result-card SVG height for a given card — kept in sync with the markup. */\nfunction svgHeight(card: InsertCardData, brand: string | false): number {\n return layoutCard(card, brand !== false).height;\n}\n\n/**\n * Build the radial gauge group: a track `<circle>` plus a value arc drawn with\n * `stroke-dasharray`/`stroke-dashoffset` (optionally notched into `segments`),\n * a centred value + label, and a `<title>` accessible name. Pure native SVG —\n * never `<foreignObject>`.\n */\nfunction buildGauge(\n gauge: InsertCardRadialGauge,\n c: ThemeColours,\n font: string,\n cx: number,\n cy: number,\n): string {\n const r = GAUGE_R;\n const circumference = 2 * Math.PI * r;\n const frac = gaugeFraction(gauge);\n const arc = resolveToken(c, gauge.colorToken, c.accent);\n const segments =\n typeof gauge.segments === 'number' && gauge.segments > 1\n ? gauge.segments\n : 0;\n // Notch the ring into evenly-spaced segments via a dasharray pattern.\n const gap = segments ? 3 : 0;\n const segLen = segments ? circumference / segments - gap : circumference;\n const trackDash = segments ? `${segLen} ${gap}` : '';\n const valueDash = `${circumference * frac} ${circumference}`;\n const rotate = `transform=\"rotate(-90 ${cx} ${cy})\"`;\n const title = escapeXml(\n gauge.label ? `${gauge.value} — ${gauge.label}` : gauge.value,\n );\n const track = `<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" fill=\"none\" stroke=\"${c.border}\" stroke-width=\"${GAUGE_STROKE}\"${\n trackDash ? ` stroke-dasharray=\"${trackDash}\"` : ''\n } ${rotate}/>`;\n const valueArc = `<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" fill=\"none\" stroke=\"${arc}\" stroke-width=\"${GAUGE_STROKE}\" stroke-linecap=\"round\" stroke-dasharray=\"${valueDash}\" ${rotate}/>`;\n const centreValue = `<text x=\"${cx}\" y=\"${cy + 1}\" text-anchor=\"middle\" dominant-baseline=\"middle\" font-family=\"${font}\" font-size=\"16\" font-weight=\"700\" fill=\"${c.fg}\">${escapeXml(\n gauge.value,\n )}</text>`;\n const centreLabel = gauge.label\n ? `<text x=\"${cx}\" y=\"${cy + 15}\" text-anchor=\"middle\" dominant-baseline=\"middle\" font-family=\"${font}\" font-size=\"9\" fill=\"${c.muted}\">${escapeXml(\n gauge.label,\n )}</text>`\n : '';\n return `<g role=\"img\" aria-label=\"${title}\"><title>${title}</title>${track}${valueArc}${centreValue}${centreLabel}</g>`;\n}\n\n/**\n * Build the full-width banded gauge group via the shared `banded-gauge` module.\n * Geometry is computed for the card's full content width (`PAD..W-PAD`), then\n * emitted as a native-SVG `<g>` translated to the band's top y. The resolver is\n * bound to the card's probe-resolved colours — each band token falls back to the\n * accent when unsampled (the SSR / no-probe path) — so the baked raster carries\n * theme-correct fills with no literal in source. Pure native SVG; never a\n * `<foreignObject>`.\n */\nfunction buildBandedGauge(\n gauge: InsertCardBandedGauge,\n c: ThemeColours,\n cardWidth: number,\n y: number,\n): string {\n // The shared module insets its bar by a fixed INSET_X (14) from the geometry\n // box edges. To land the bar precisely on the card's PAD..(W-PAD) content\n // edges, hand it a slightly narrower box and translate by the inset delta so\n // INSET_X + offset === PAD. The bar then spans the full card content width.\n const offsetX = PAD - BANDED_GAUGE_INSET_X;\n const geometryWidth = cardWidth - 2 * offsetX;\n const geometry = computeBandedGaugeGeometry(\n {\n value: gauge.value,\n bands: gauge.bands,\n min: gauge.min,\n max: gauge.max,\n valueLabel: gauge.valueLabel,\n categoryLabel: gauge.categoryLabel,\n rangeLabel: gauge.rangeLabel,\n ariaLabel: gauge.ariaLabel,\n ticks: gauge.ticks,\n },\n { width: geometryWidth, height: BANDED_GAUGE_HEIGHT },\n );\n const group = buildBandedGaugeSvgString(geometry, {\n resolve: (token) => resolveToken(c, token, c.accent),\n // Raw theme font — buildBandedGaugeSvgString escapes it once. Passing the\n // card's already-escaped `font` here would double-escape and break it.\n font: c.font,\n fg: c.fg,\n muted: c.muted,\n track: c.border,\n });\n return `<g transform=\"translate(${offsetX} ${y})\">${group}</g>`;\n}\n\n/**\n * Parse a `getComputedStyle().color` string (`rgb(r, g, b)` / `rgba(...)`) to an\n * `[r, g, b]` triple, or `null` for the SSR placeholders (`currentColor` /\n * `transparent`) where no concrete colour is available.\n */\nfunction parseRgb(colour: string): [number, number, number] | null {\n const m = colour.match(/rgba?\\(\\s*(\\d+)[,\\s]+(\\d+)[,\\s]+(\\d+)/i);\n return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;\n}\n\n/** WCAG relative luminance of an sRGB triple (0–255 channels). */\nfunction relativeLuminance([r, g, b]: [number, number, number]): number {\n const lin = (v: number) => {\n const s = v / 255;\n return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n };\n return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);\n}\n\n/**\n * WCAG contrast ratio between two `getComputedStyle` colour strings. Returns 0\n * when either side isn't a concrete rgb (the SSR path), so callers fall back.\n */\nfunction contrastRatio(a: string, b: string): number {\n const ca = parseRgb(a);\n const cb = parseRgb(b);\n if (!ca || !cb) return 0;\n const la = relativeLuminance(ca);\n const lb = relativeLuminance(cb);\n return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);\n}\n\n/** Build the highlight chip: rounded `<rect>` pill + centred `<text>`. */\nfunction buildChip(\n card: InsertCardData,\n c: ThemeColours,\n font: string,\n y: number,\n): string {\n const text = card.highlight as string;\n const fillToken = card.highlightToken ?? DEFAULT_HIGHLIGHT_TOKEN;\n const fill = resolveToken(c, fillToken, c.accent);\n // Chip label colour: the card surface (`c.bg`, white in light theme) reads as\n // crisp knockout text on the saturated fill when it clears 3:1. In dark /\n // accessible themes the surface is dark and the fills are lighter, so this\n // flips to a dark label automatically. Falls back to the card foreground when\n // the surface can't beat the fill, or colours aren't probe-resolved (SSR).\n const textColour = contrastRatio(c.bg, fill) >= 3 ? c.bg : c.fg;\n // Rough monospace-free width estimate: glyph ≈ 7.2px at 12px + 28px padding.\n const chipW = Math.round(text.length * 7.2 + 28);\n const textX = PAD + chipW / 2;\n const textY = y + CHIP_H / 2 + 1;\n return `<rect x=\"${PAD}\" y=\"${y}\" width=\"${chipW}\" height=\"${CHIP_H}\" rx=\"${\n CHIP_H / 2\n }\" fill=\"${fill}\"/><text x=\"${textX}\" y=\"${textY}\" text-anchor=\"middle\" dominant-baseline=\"middle\" font-family=\"${font}\" font-size=\"12\" font-weight=\"600\" fill=\"${textColour}\">${escapeXml(\n text,\n )}</text>`;\n}\n\nexport function buildResultCardSvg(\n card: InsertCardData,\n c: ThemeColours,\n brand: string | false = false,\n): string {\n const W = SVG_W;\n const L = layoutCard(card, brand !== false);\n const H = L.height;\n const font = escapeXml(c.font);\n\n const categoryToken = categoryFillToken(card);\n // Category solid drives the header icon, the field-row glyphs, and the primary\n // value. It is the same resolved colour the chip uses, so the card stays\n // AA-safe upstream (each calculator passes a contrast-checked highlightToken).\n const categorySolid = resolveToken(c, categoryToken, c.accent);\n\n // Header glyph — drawn inline-end of the title row, vertically centred on the\n // title cap-height, tinted with the category solid. Omitted for an unset /\n // unknown icon (fully back-compatible).\n const headerIcon = card.icon\n ? buildIconGroup(\n card.icon,\n categorySolid,\n W - PAD - HEADER_ICON_BOX,\n TITLE_BASELINE - HEADER_ICON_BOX + 2,\n ICON_SLOT,\n )\n : '';\n\n // Fields flow on the inline-start edge; when a gauge is present it sits on\n // the inline-end edge so the rows don't run under it. Each row carries a small\n // leading marker so the list stays scannable: a per-field glyph when one is\n // set, else the quiet muted bullet dot (back-compat); the label/value text\n // indents past it.\n const fieldTextX = PAD + FIELD_ICON_SLOT + FIELD_ICON_GAP;\n const rows = card.fields\n .map((f, i) => {\n const y = L.firstFieldY + i * ROW_H;\n // The first row's value is the primary metric: heavier + category colour.\n const isPrimary = i === 0;\n const valueSize = isPrimary ? 14 : 13;\n const valueWeight = isPrimary ? 700 : 500;\n const valueFill = isPrimary ? categorySolid : c.fg;\n // Leading marker: a per-field glyph in the category solid (every row, so\n // all glyphs — header + fields — share one colour) drawn in the\n // FIELD_ICON_SLOT box centred on the text baseline, else the muted bullet\n // dot for a field with no icon.\n const markerCy = y - 4; // visual centre of the row's cap-height\n let marker: string;\n if (f.icon && isIconKey(f.icon)) {\n const iconColour = categorySolid;\n marker = buildIconGroup(\n f.icon,\n iconColour,\n PAD,\n markerCy - FIELD_ICON_SLOT / 2,\n FIELD_ICON_SLOT,\n );\n } else {\n const dotCx = PAD + FIELD_ICON_SLOT / 2;\n marker = `<circle cx=\"${dotCx}\" cy=\"${markerCy}\" r=\"2\" fill=\"${c.muted}\"/>`;\n }\n return `${marker}<text x=\"${fieldTextX}\" y=\"${y}\" font-family=\"${font}\" font-size=\"13\"><tspan fill=\"${c.muted}\">${escapeXml(\n f.label,\n )}: </tspan><tspan font-size=\"${valueSize}\" font-weight=\"${valueWeight}\" fill=\"${valueFill}\">${escapeXml(\n f.value,\n )}</tspan></text>`;\n })\n .join('');\n\n const chip = L.hasChip ? buildChip(card, c, font, L.chipY) : '';\n\n // Gauge: the banded variant is a full-width bar below the fields; the radial\n // variant is the inline-end corner donut. The radial path is unchanged.\n let gauge = '';\n if (card.gauge) {\n if (isBandedGauge(card.gauge) && L.bandedGaugeY !== null) {\n gauge = buildBandedGauge(card.gauge, c, W, L.bandedGaugeY);\n } else if (!isBandedGauge(card.gauge)) {\n gauge = buildGauge(\n card.gauge,\n c,\n font,\n W - PAD - GAUGE_BOX / 2,\n (L.hasChip ? L.chipY : TITLE_BASELINE) + GAUGE_BOX / 2,\n );\n }\n }\n\n // Brand wordmark — an opt-in single quiet line at the foot of the card. No\n // hairline rule above it; an omitted / `false` brand renders no footer at all.\n const footer =\n brand !== false\n ? `<text x=\"${PAD}\" y=\"${\n L.footerY\n }\" font-family=\"${font}\" font-size=\"10\" font-weight=\"500\" fill=\"${c.muted}\">${escapeXml(\n brand,\n )}</text>`\n : '';\n\n const title = `<text x=\"${PAD}\" y=\"${TITLE_BASELINE}\" font-family=\"${font}\" font-size=\"16\" font-weight=\"700\" fill=\"${c.fg}\">${escapeXml(\n card.title,\n )}</text>`;\n\n // Layer order: surface fill → content → bordered outline LAST (fill=\"none\")\n // so the rx=\"12\" stroke draws cleanly over the plain card surface.\n const surface = `<rect x=\"0.5\" y=\"0.5\" width=\"${W - 1}\" height=\"${\n H - 1\n }\" rx=\"12\" fill=\"${c.bg}\"/>`;\n const outline = `<rect x=\"0.5\" y=\"0.5\" width=\"${W - 1}\" height=\"${\n H - 1\n }\" rx=\"12\" fill=\"none\" stroke=\"${c.border}\"/>`;\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${W}\" height=\"${H}\" viewBox=\"0 0 ${W} ${H}\" role=\"img\" aria-label=\"${escapeXml(\n card.title,\n )}\">${surface}${title}${headerIcon}${chip}${gauge}${rows}${footer}${outline}</svg>`;\n}\n\n/* ------------------------------------------------------------------ */\n/* Clipboard helpers (copy variant) */\n/* ------------------------------------------------------------------ */\n\n/** True when a multi-format clipboard write is reachable in this context. */\nfunction canWriteRichClipboard(): boolean {\n return (\n typeof navigator !== 'undefined' &&\n typeof navigator.clipboard?.write === 'function' &&\n typeof ClipboardItem !== 'undefined'\n );\n}\n\n/**\n * Rasterise the result-card SVG data-URI to a PNG Blob. Clipboards reject\n * SVG as an image, so we load the SVG into an <img>, paint it onto a canvas\n * at the SVG's intrinsic size, and read the canvas back as `image/png`.\n */\nfunction rasteriseSvgToPng(\n imageDataUri: string,\n width: number,\n height: number,\n): Promise<Blob> {\n return new Promise<Blob>((resolve, reject) => {\n const img = new Image();\n img.decoding = 'async';\n img.onload = () => {\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n reject(new Error('2D canvas context unavailable'));\n return;\n }\n ctx.drawImage(img, 0, 0, width, height);\n canvas.toBlob((blob) => {\n if (blob) resolve(blob);\n else reject(new Error('canvas.toBlob produced no PNG'));\n }, 'image/png');\n };\n img.onerror = () => reject(new Error('SVG failed to decode as an image'));\n img.src = imageDataUri;\n });\n}\n\n/** Options for {@link svgCardToPngDataUri}. */\nexport interface SvgCardToPngOptions {\n /**\n * Resolved theme colours to paint into the card. When omitted, the card\n * renders with `currentColor` / transparent fallbacks (see\n * {@link buildResultCardSvg}) — pass sampled colours for a branded raster.\n */\n colours?: ThemeColours;\n /**\n * Device-pixel scale factor for the raster. `2` yields a retina-sharp PNG.\n * Defaults to `Math.max(2, devicePixelRatio)` so the inserted image is crisp\n * without a consumer-side supersampling shim.\n */\n scale?: number;\n /**\n * Brand wordmark for the footer. Omitted → the card's own `brand` (then the\n * default `'AlfaDocs'`); a string overrides it; `false` removes it.\n */\n brand?: string | false;\n}\n\n/** dpr-aware default raster scale — never below 2× so the PNG stays crisp. */\nfunction defaultRasterScale(): number {\n const dpr =\n typeof window !== 'undefined' && typeof window.devicePixelRatio === 'number'\n ? window.devicePixelRatio\n : 1;\n return Math.max(2, dpr);\n}\n\n/**\n * Render an {@link InsertCardData} result card to an `image/png` data URI.\n *\n * This is the format intended for editor insertion: a flat raster carries no\n * `<script>` and survives the rich-text sanitiser that strips inline SVG. The\n * card is built as SVG, loaded into an `<img>`, painted onto a canvas at the\n * card's intrinsic size (optionally scaled), and read back as `image/png`.\n *\n * Browser-only — relies on `Image`, `<canvas>`, and `canvas.toBlob`. Throws if\n * called in a non-DOM context or if the SVG fails to decode.\n */\nexport async function svgCardToPngDataUri(\n card: InsertCardData,\n opts: SvgCardToPngOptions = {},\n): Promise<string> {\n return (await svgCardToPng(card, opts)).dataUri;\n}\n\n/**\n * Like {@link svgCardToPngDataUri} but also returns the **logical (un-scaled)**\n * card dimensions so consumers can size the inserted `<img width height>` and\n * drop their own supersampling shim. The PNG itself is rasterised at `scale`\n * (default `Math.max(2, devicePixelRatio)`) for crispness.\n */\nexport async function svgCardToPng(\n card: InsertCardData,\n opts: SvgCardToPngOptions = {},\n): Promise<InsertPngResult> {\n const { colours, scale = defaultRasterScale() } = opts;\n const resolved: ThemeColours = colours ?? readThemeColours(null);\n const brand = resolveBrand(card, opts.brand);\n const svg = buildResultCardSvg(card, resolved, brand);\n const imageDataUri = `data:image/svg+xml,${encodeURIComponent(svg)}`;\n const logicalW = SVG_W;\n const logicalH = svgHeight(card, brand);\n const blob = await rasteriseSvgToPng(\n imageDataUri,\n Math.round(logicalW * scale),\n Math.round(logicalH * scale),\n );\n const dataUri = await blobToDataUri(blob);\n return { dataUri, width: logicalW, height: logicalH };\n}\n\n/** Read a Blob back as a `data:` URI string. */\nfunction blobToDataUri(blob: Blob): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(String(reader.result));\n reader.onerror = () =>\n reject(reader.error ?? new Error('FileReader error'));\n reader.readAsDataURL(blob);\n });\n}\n\n/** Build the per-mode ClipboardItem contents map for a copy. */\nasync function buildClipboardItem(\n mode: InsertMode,\n card: InsertCardData,\n colours: ThemeColours,\n): Promise<ClipboardItem> {\n const text = buildResultText(card);\n const textBlob = new Blob([text], { type: 'text/plain' });\n\n if (mode === 'text') {\n return new ClipboardItem({ 'text/plain': textBlob });\n }\n\n const brand = resolveBrand(card, undefined);\n const svg = buildResultCardSvg(card, colours, brand);\n const imageDataUri = `data:image/svg+xml,${encodeURIComponent(svg)}`;\n const scale = defaultRasterScale();\n const pngBlob = await rasteriseSvgToPng(\n imageDataUri,\n Math.round(SVG_W * scale),\n Math.round(svgHeight(card, brand) * scale),\n );\n\n if (mode === 'image') {\n return new ClipboardItem({ 'image/png': pngBlob, 'text/plain': textBlob });\n }\n\n const htmlBlob = new Blob([buildResultHtml(card)], { type: 'text/html' });\n return new ClipboardItem({\n 'text/html': htmlBlob,\n 'image/png': pngBlob,\n 'text/plain': textBlob,\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nconst rowVariants = cva(\n 'ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]',\n {\n variants: {\n variant: {\n insert: '',\n copy: '',\n },\n },\n defaultVariants: { variant: 'insert' },\n },\n);\n\nconst MODES: readonly InsertMode[] = ['text', 'image', 'text-image'] as const;\n\nconst MODE_ICON: Record<InsertMode, React.ReactNode> = {\n text: <Type aria-hidden />,\n image: <ImageIcon aria-hidden />,\n 'text-image': <Layers aria-hidden />,\n};\n\n/* i18n leaf keys per variant × mode — bare keys against the `ui` namespace. */\nconst LABEL_KEY: Record<InsertVariant, Record<InsertMode, string>> = {\n insert: {\n text: 'insert.text',\n image: 'insert.image',\n 'text-image': 'insert.textImage',\n },\n copy: {\n text: 'insert.copyText',\n image: 'insert.copyImage',\n 'text-image': 'insert.copyTextImage',\n },\n};\n\nexport const InsertButton = forwardRef<HTMLDivElement, InsertButtonProps>(\n function InsertButton(\n {\n card,\n variant = 'insert',\n onInsert,\n onCopy,\n onError,\n size = 'sm',\n intent = 'primary',\n },\n ref,\n ) {\n const { t } = useTranslation();\n const probeRef = useRef<HTMLSpanElement>(null);\n\n const buildPayload = (mode: InsertMode): InsertPayload => {\n const text = buildResultText(card);\n const html = buildResultHtml(card);\n let svg = '';\n let imageDataUri = '';\n // Sample the live theme once, at click time (including any gauge/chip\n // token colours the card needs), so both the SVG fields and the lazy PNG\n // thunk paint with the same resolved colours.\n const colours =\n mode === 'text'\n ? null\n : readThemeColours(probeRef.current, extraTokensForCard(card));\n if (colours) {\n svg = buildResultCardSvg(card, colours, resolveBrand(card, undefined));\n imageDataUri = `data:image/svg+xml,${encodeURIComponent(svg)}`;\n }\n const pngDataUri = (): Promise<InsertPngResult> =>\n colours\n ? svgCardToPng(card, { colours })\n : Promise.resolve({ dataUri: '', width: 0, height: 0 });\n return { mode, text, html, svg, imageDataUri, pngDataUri };\n };\n\n const handleInsert = (mode: InsertMode): void => {\n onInsert?.(buildPayload(mode));\n };\n\n const handleCopy = (mode: InsertMode): void => {\n if (!canWriteRichClipboard()) {\n onError?.(new Error('Clipboard write unavailable in this context'));\n return;\n }\n const colours = readThemeColours(\n probeRef.current,\n extraTokensForCard(card),\n );\n void (async () => {\n try {\n const item = await buildClipboardItem(mode, card, colours);\n await navigator.clipboard.write([item]);\n onCopy?.(mode);\n } catch (error) {\n onError?.(error);\n }\n })();\n };\n\n const onActivate = variant === 'copy' ? handleCopy : handleInsert;\n\n return (\n <div\n ref={ref}\n data-component=\"insert-result\"\n data-variant={variant}\n className={rowVariants({ variant })}\n >\n {/* Hidden colour probes — sampled at click time so the SVG card uses\n the live theme's resolved colours (no literals in source). The\n fixed five plus any per-card gauge/chip token colours. */}\n <span ref={probeRef} aria-hidden className=\"ds:sr-only\">\n {PROBE_KEYS.map((k) => (\n <span\n key={k}\n data-k={k}\n className={\n k === 'fg'\n ? 'ds:text-foreground'\n : k === 'muted'\n ? 'ds:text-muted-foreground'\n : k === 'accent'\n ? 'ds:text-[color:var(--primary)]'\n : k === 'border'\n ? 'ds:text-[color:var(--border)]'\n : 'ds:text-[color:var(--card)]'\n }\n />\n ))}\n {extraTokensForCard(card).map((token) => (\n <span\n key={token}\n data-token={tokenName(token)}\n className={probeClassForToken(token)}\n />\n ))}\n </span>\n {MODES.map((mode) => (\n <Button\n key={mode}\n type=\"button\"\n intent={intent}\n size={size}\n startIcon={MODE_ICON[mode]}\n aria-label={t(LABEL_KEY[variant][mode])}\n onClick={() => onActivate(mode)}\n >\n {t(LABEL_KEY[variant][mode])}\n </Button>\n ))}\n </div>\n );\n },\n);\n\nInsertButton.displayName = 'InsertButton';\n"],"names":["__iconNode","Type","createLucideIcon","BMI_BANDED_MIN","BMI_BANDED_MAX","BMI_BAND_THRESHOLDS","bmiBands","INSET_X","BAR_H","BAR_RADIUS","VALUE_LABEL_BASELINE","BAR_TOP_GAP","TICK_LABEL_GAP","scaleToX","value","min","max","barStart","barEnd","t","computeBandedGaugeGeometry","model","width","height","barY","valueLabelY","tickLabelY","cursor","bands","band","lower","upper","x","xEnd","rawX","overflow","markerX","ticks","summaryLabel","r2","n","escapeXml","s","bandPath","y","w","h","rL","rR","x2","y2","tr","br","bl","tl","buildBandedGaugeSvgString","geometry","options","resolve","font","fg","muted","track","fontFamily","rail","bandCount","bandRects","i","fill","tickY1","tickY2","tick","rule","label","mx","ruleTop","ruleBottom","markerRule","triTop","triangle","caret","cy","tipX","valueLabel","summary","title","DEFAULT_WIDTH","DEFAULT_HEIGHT","cssVarResolver","colorToken","BandedGauge","forwardRef","className","ref","g","caretCy","jsxs","jsx","ICON_VIEWBOX","ICON_SLOT","FIELD_ICON_SLOT","ICON_GEOMETRY","isIconKey","key","buildIconGroup","icon","colour","slot","scale","isBandedGauge","gauge","PROBE_KEYS","DEFAULT_HIGHLIGHT_TOKEN","SVG_W","tokenName","token","probeClassForToken","categoryFillToken","card","extraTokensForCard","wanted","category","readThemeColours","probe","extraTokens","fallback","read","el","tokens","resolveToken","c","_a","buildResultText","lines","f","buildResultHtml","items","highlight","PAD","TITLE_BASELINE","CHIP_H","CHIP_GAP","ROW_H","FIELDS_GAP","FOOTER_GAP","FOOTER_H","GAUGE_R","GAUGE_STROKE","GAUGE_BOX","BANDED_GAUGE_GAP","HEADER_ICON_BOX","FIELD_ICON_GAP","resolveBrand","override","gaugeFraction","v","layoutCard","hasBrand","hasChip","chipY","firstFieldY","fieldsEndY","banded","gaugeFloor","bandedGaugeY","bandedBottom","BANDED_GAUGE_HEIGHT","contentBottom","footerY","svgHeight","brand","buildGauge","cx","r","circumference","frac","arc","segments","gap","segLen","trackDash","valueDash","rotate","valueArc","centreValue","centreLabel","buildBandedGauge","cardWidth","offsetX","BANDED_GAUGE_INSET_X","geometryWidth","group","parseRgb","m","relativeLuminance","b","lin","contrastRatio","a","ca","cb","la","lb","buildChip","text","fillToken","textColour","chipW","textX","textY","buildResultCardSvg","W","L","H","categoryToken","categorySolid","headerIcon","fieldTextX","rows","isPrimary","valueSize","valueWeight","valueFill","markerCy","marker","iconColour","chip","footer","surface","outline","canWriteRichClipboard","rasteriseSvgToPng","imageDataUri","reject","img","canvas","ctx","blob","defaultRasterScale","dpr","svgCardToPngDataUri","opts","svgCardToPng","colours","resolved","svg","logicalW","logicalH","blobToDataUri","reader","buildClipboardItem","mode","textBlob","pngBlob","htmlBlob","rowVariants","cva","MODES","MODE_ICON","ImageIcon","Layers","LABEL_KEY","InsertButton","variant","onInsert","onCopy","onError","size","intent","useTranslation","probeRef","useRef","buildPayload","html","onActivate","item","error","k","Button"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar-h78cTNLh.js","sources":["../../node_modules/lucide-react/dist/esm/icons/panel-left-close.js","../../node_modules/lucide-react/dist/esm/icons/panel-left-open.js","../../src/components/sidebar/sidebar.agent.ts","../../src/components/sidebar/sidebar.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.8.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.js';\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: \"m16 15-3-3 3-3\", key: \"14y99z\" }]\n];\nconst PanelLeftClose = createLucideIcon(\"panel-left-close\", __iconNode);\n\nexport { __iconNode, PanelLeftClose as default };\n//# sourceMappingURL=panel-left-close.js.map\n","/**\n * @license lucide-react v1.8.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.js';\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: \"m14 9 3 3-3 3\", key: \"8010ee\" }]\n];\nconst PanelLeftOpen = createLucideIcon(\"panel-left-open\", __iconNode);\n\nexport { __iconNode, PanelLeftOpen as default };\n//# sourceMappingURL=panel-left-open.js.map\n","import type { AgentAdapter } from '../../agent/types';\nimport type { SidebarHandle } from './sidebar';\n\nexport const sidebarAgent: AgentAdapter<SidebarHandle> = {\n id: 'sidebar',\n capabilities: ['expand'],\n state: {\n isCollapsed: {\n type: 'boolean',\n description: 'True when the sidebar is in its collapsed (rail) state.',\n read: (handle) => handle.getIsCollapsed(),\n },\n },\n actions: {\n toggle_collapsed: {\n safety: 'read',\n description: 'Toggle the sidebar between collapsed and expanded.',\n invoke: (handle) => {\n handle.toggleCollapsed();\n },\n },\n },\n domHooks: {\n root: { attr: 'data-component', value: 'sidebar' },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n item: {\n attr: 'data-nav-id',\n description: 'Each Sidebar.Item emits its key as data-nav-id.',\n },\n },\n};\n","import {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type AnchorHTMLAttributes,\n type ComponentPropsWithoutRef,\n type KeyboardEvent as ReactKeyboardEvent,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n} from 'react';\nimport * as RadixDialog from '@radix-ui/react-dialog';\nimport * as RadixCollapsible from '@radix-ui/react-collapsible';\nimport * as RadixAccordion from '@radix-ui/react-accordion';\nimport * as RadixTooltip from '@radix-ui/react-tooltip';\nimport { AccordionContent } from '../accordion';\nimport { Slot } from '@radix-ui/react-slot';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport {\n ChevronRight,\n CircleArrowUp,\n GripVertical,\n PanelLeftClose,\n PanelLeftOpen,\n Star,\n X,\n} from 'lucide-react';\nimport { useAgentRegistration } from '../../agent';\nimport { sidebarAgent } from './sidebar.agent';\n\n/* -------------------------------------------------------------------- */\n/* Types & context */\n/* -------------------------------------------------------------------- */\n\nexport type SidebarMode = 'expanded' | 'icon' | 'overlay';\nexport type SidebarDensity = 'default' | 'compact';\n\nexport interface SidebarContextValue {\n mode: SidebarMode;\n density: SidebarDensity;\n /** Transition the sidebar to a new mode from an internal toggle. */\n transitionTo?: (next: SidebarMode) => void;\n}\n\nconst SidebarContext = createContext<SidebarContextValue>({\n mode: 'expanded',\n density: 'default',\n});\n\nexport const useSidebar = () => useContext(SidebarContext);\n\n/* -------------------------------------------------------------------- */\n/* localStorage helpers (SSR-safe) */\n/* -------------------------------------------------------------------- */\n\nconst STORAGE_KEY = 'ui.sidebar.state';\n\nfunction readStoredState(defaultMode: SidebarMode): SidebarMode {\n if (typeof window === 'undefined') return defaultMode;\n try {\n const v = window.localStorage.getItem(STORAGE_KEY);\n if (v === 'expanded' || v === 'icon' || v === 'overlay') return v;\n } catch {\n /* noop */\n }\n return defaultMode;\n}\n\nfunction writeStoredState(value: SidebarMode) {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(STORAGE_KEY, value);\n } catch {\n /* noop */\n }\n}\n\n// `usePersistentState` was extracted to `src/hooks/use-persistent-state.ts`\n// so any consumer (sidebar or otherwise) can use it. Re-exported here so\n// `import { usePersistentState } from '@/components/sidebar'` keeps working.\nexport { usePersistentState } from '../../hooks/use-persistent-state';\n\n/* -------------------------------------------------------------------- */\n/* Root */\n/* -------------------------------------------------------------------- */\n\nconst railClasses = cva(\n [\n 'ds:flex ds:flex-col',\n // Sidebar sits at the page background in light mode (white-on-white\n // chrome separated by the inline-end border + --shadow-md). In dark\n // mode the Header already blends with --background, so we step the\n // sidebar one layer down (blue-600) to keep it visually distinct from\n // the header band — matches the PDF dark mockups' \"flat Dark Blue\n // surface with subtle depth via layering\" recipe.\n 'ds:bg-[var(--background)] ds:[.theme-dark_&]:bg-[color:var(--color-blue-600)] ds:text-[var(--foreground)]',\n 'ds:border-inline-end ds:border-[var(--border)]',\n // Resting-surface elevation — `--shadow-md` is deliberately lighter\n // than `--shadow-card` so it reads as chrome, not a floating card,\n // while still separating the rail from the page content on light\n // backgrounds. Forced-colors strips shadows globally, so the\n // `border-inline-end` above carries the separation cue for HCM.\n //\n // `relative z-[1]` lifts the rail above any sibling that paints a\n // solid background (e.g. AppFrame's `<main>` surface), otherwise\n // the shadow that projects towards the inline-end gets covered.\n 'ds:relative ds:z-[1] ds:shadow-[var(--shadow-md)]',\n 'ds:h-full',\n 'ds:transition-[inline-size] ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n ].join(' '),\n {\n variants: {\n mode: {\n // Tokenised widths modelled on Linear / Jira proportions.\n expanded: 'ds:w-[var(--sidebar-modern-expanded-size)]',\n icon: 'ds:w-[var(--sidebar-modern-icon-size)]',\n overlay: 'ds:w-[var(--sidebar-modern-expanded-size)]',\n },\n density: {\n default: '',\n compact: '',\n },\n },\n defaultVariants: { mode: 'expanded', density: 'default' },\n },\n);\n\n// Curated agent-readiness handle — see sidebar.agent.ts.\n// `activeItem` / `selectItem` are intentionally NOT exposed: the active\n// navigation item is owned by the consuming app (it sets `aria-current` on\n// each Sidebar.Item based on its router state). Surfacing setters here would\n// be lying about a write capability we can't actually perform.\nexport interface SidebarHandle {\n getIsCollapsed: () => boolean;\n toggleCollapsed: () => void;\n}\n\nexport interface SidebarProps extends ComponentPropsWithoutRef<'nav'> {\n /** Visual mode. Controlled via `onStateChange`. @default 'expanded' */\n state?: SidebarMode;\n /** Uncontrolled default mode. @default 'expanded' */\n defaultState?: SidebarMode;\n /** Fires when the mode changes (user toggle or overlay open/close). */\n onStateChange?: (state: SidebarMode) => void;\n /** Compact density shrinks inline padding. @default 'default' */\n density?: SidebarDensity;\n /** Overlay-only: controlled open state. */\n open?: boolean;\n /** Overlay-only: fires when the dialog opens/closes. */\n onOpenChange?: (open: boolean) => void;\n /** Override the nav aria-label. */\n 'aria-label'?: string;\n}\n\nconst Sidebar = forwardRef<HTMLElement, SidebarProps>(\n (\n {\n state,\n defaultState = 'expanded',\n onStateChange,\n density = 'default',\n open,\n onOpenChange,\n 'aria-label': ariaLabel,\n className,\n children,\n id,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation();\n const isControlled = state !== undefined;\n const [internalState, setInternalState] = useState<SidebarMode>(() =>\n isControlled ? state! : readStoredState(defaultState),\n );\n const resolved = isControlled ? state! : internalState;\n\n useEffect(() => {\n if (!isControlled) writeStoredState(internalState);\n }, [internalState, isControlled]);\n\n // Transition handler used by internal toggles. In controlled mode we\n // only fire `onStateChange` — the parent is responsible for updating\n // the `state` prop. In uncontrolled mode we also update local state.\n // Note: we intentionally do NOT echo the incoming `state` prop back to\n // `onStateChange` — that caused a feedback loop in controlled consumers.\n const transitionTo = useCallback(\n (next: SidebarMode) => {\n if (!isControlled) setInternalState(next);\n onStateChange?.(next);\n },\n [isControlled, onStateChange],\n );\n\n const label = ariaLabel ?? t('navigation.sidebar.label');\n\n // Agent handle — refs mirror state for fresh reads.\n const resolvedRef = useRef<SidebarMode>(resolved);\n useEffect(() => {\n resolvedRef.current = resolved;\n }, [resolved]);\n\n const agentHandle = useMemo<SidebarHandle>(\n () => ({\n getIsCollapsed: () => resolvedRef.current !== 'expanded',\n toggleCollapsed: () => {\n const next: SidebarMode =\n resolvedRef.current === 'expanded' ? 'icon' : 'expanded';\n transitionTo(next);\n },\n }),\n [transitionTo],\n );\n useAgentRegistration(sidebarAgent, agentHandle, id);\n\n if (resolved === 'overlay') {\n return (\n <SidebarContext.Provider\n value={{ mode: 'overlay', density, transitionTo }}\n >\n <RadixDialog.Root open={open} onOpenChange={onOpenChange}>\n <RadixDialog.Portal>\n <RadixDialog.Overlay\n className={[\n 'ds:fixed ds:inset-0 ds:z-[var(--z-modal-backdrop)]',\n 'ds:bg-[var(--foreground)]/20 ds:backdrop-blur-sm',\n 'ds:data-[state=open]:animate-in ds:data-[state=open]:fade-in',\n 'ds:data-[state=closed]:animate-out ds:data-[state=closed]:fade-out',\n 'ds:motion-reduce:animate-none',\n ].join(' ')}\n />\n <RadixDialog.Content\n aria-label={label}\n className={[\n 'ds:fixed ds:z-[var(--z-modal)]',\n 'ds:inset-inline-start-0 ds:inset-block-start-0',\n 'ds:h-dvh',\n railClasses({ mode: 'overlay', density }),\n 'ds:shadow-[var(--shadow-xl)]',\n 'ds:data-[state=open]:animate-in ds:data-[state=closed]:animate-out',\n 'ds:data-[state=open]:slide-in-from-left ds:data-[state=closed]:slide-out-to-left',\n 'ds:rtl:data-[state=open]:slide-in-from-right ds:rtl:data-[state=closed]:slide-out-to-right',\n 'ds:motion-reduce:animate-none',\n 'ds:focus:outline-none',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n <nav\n ref={ref}\n id={id}\n aria-label={label}\n data-component=\"sidebar\"\n data-component-id={id}\n className=\"ds:flex ds:flex-col ds:h-full\"\n {...rest}\n >\n {children}\n </nav>\n <RadixDialog.Close asChild>\n <button\n type=\"button\"\n aria-label={t('navigation.sidebar.close')}\n className={[\n 'ds:absolute ds:top-[var(--spacing-sm)] ds:end-[var(--spacing-sm)]',\n 'ds:inline-flex ds:items-center ds:justify-center',\n 'ds:min-w-[var(--min-target-size)] ds:min-h-[var(--min-target-size)]',\n 'ds:rounded-[var(--radius-sm)] ds:text-[var(--muted-foreground)]',\n 'ds:hover:bg-[var(--muted)]/20 ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid ds:focus-visible:outline-[var(--ring)]',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n ].join(' ')}\n >\n <X aria-hidden=\"true\" className=\"ds:size-4\" />\n </button>\n </RadixDialog.Close>\n </RadixDialog.Content>\n </RadixDialog.Portal>\n </RadixDialog.Root>\n </SidebarContext.Provider>\n );\n }\n\n return (\n <SidebarContext.Provider\n value={{ mode: resolved, density, transitionTo }}\n >\n <RadixTooltip.Provider delayDuration={300}>\n <nav\n ref={ref}\n id={id}\n aria-label={label}\n data-component=\"sidebar\"\n data-component-id={id}\n data-mode={resolved}\n data-density={density}\n className={[\n railClasses({ mode: resolved, density }),\n density === 'compact' ? 'ds:density-compact' : '',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n {children}\n </nav>\n </RadixTooltip.Provider>\n </SidebarContext.Provider>\n );\n },\n);\nSidebar.displayName = 'Sidebar';\n\n/* -------------------------------------------------------------------- */\n/* Header / Body / Footer */\n/* -------------------------------------------------------------------- */\n\nconst SidebarHeader = forwardRef<\n HTMLDivElement,\n ComponentPropsWithoutRef<'div'>\n>(({ className, ...rest }, ref) => {\n const { mode } = useSidebar();\n return (\n <div\n ref={ref}\n className={[\n 'ds:relative ds:flex ds:items-center ds:gap-[var(--spacing-xs)]',\n 'ds:min-h-[var(--min-target-size)]',\n // Icon-rail is 64px — shrink horizontal padding so a 44×44\n // control fits centred inside the header.\n mode === 'icon'\n ? 'ds:justify-center ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)]'\n : 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n 'ds:py-[var(--spacing-sm)]',\n // Hairline border + downward chrome shadow cast the header as a\n // sticky top band above the scrolling body.\n 'ds:border-block-end ds:border-[var(--border)]',\n 'ds:shadow-[var(--shadow-chrome-down)]',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n />\n );\n});\nSidebarHeader.displayName = 'SidebarHeader';\n\nconst SidebarBody = forwardRef<HTMLDivElement, ComponentPropsWithoutRef<'div'>>(\n ({ className, ...rest }, ref) => (\n <div\n ref={ref}\n className={[\n 'ds:flex-1 ds:overflow-auto',\n 'ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)]',\n 'ds:py-[var(--spacing-sm)]',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n />\n ),\n);\nSidebarBody.displayName = 'SidebarBody';\n\nconst SidebarFooter = forwardRef<\n HTMLDivElement,\n ComponentPropsWithoutRef<'div'>\n>(({ className, ...rest }, ref) => {\n const { mode } = useSidebar();\n return (\n <div\n ref={ref}\n className={[\n 'ds:relative ds:flex ds:items-center ds:gap-[var(--spacing-xs)]',\n // Icon-rail is 64px — two 44×44 controls can't sit side-by-side,\n // so switch to a vertical stack and let each row self-centre.\n mode === 'icon'\n ? 'ds:flex-col ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)]'\n : 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:py-[var(--spacing-sm)]',\n // Hairline border + upward chrome shadow cast the footer as a\n // sticky bottom band below the scrolling body.\n 'ds:border-block-start ds:border-[var(--border)]',\n 'ds:shadow-[var(--shadow-chrome-up)]',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n />\n );\n});\nSidebarFooter.displayName = 'SidebarFooter';\n\n/* -------------------------------------------------------------------- */\n/* Section */\n/* -------------------------------------------------------------------- */\n\nexport interface SidebarSectionProps extends ComponentPropsWithoutRef<'div'> {\n /** Section label shown in expanded / overlay modes. */\n label?: string;\n /**\n * Optional leading glyph rendered inline with the section label. Stays\n * visible in `icon` mode (when the label collapses to `sr-only`) so the\n * user still has a visual grouping cue. Decorative — the label carries\n * the accessible name, so the icon slot is `aria-hidden`.\n */\n icon?: ReactNode;\n /**\n * Make the label an accordion trigger that collapses its children.\n * @default true\n */\n collapsible?: boolean;\n /** Uncontrolled default open state for the accordion. @default true */\n defaultOpen?: boolean;\n /** Controlled open state. */\n open?: boolean;\n /** Fires when the accordion opens / closes. */\n onOpenChange?: (open: boolean) => void;\n}\n\nconst sectionLabelClasses = [\n 'ds:group/section-label ds:flex ds:w-full ds:items-center',\n 'type-eyebrow',\n 'ds:text-[var(--muted-foreground)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n 'ds:py-[var(--spacing-xs)]',\n 'ds:hover:text-[var(--foreground)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n].join(' ');\n\n// Leading icon rendered inside a section header (accordion trigger or plain\n// heading). `--accent` keeps it in the same tint as item-level icons so the\n// header reads as a grouping cue, not a control. `aria-hidden` because the\n// label carries the accessible name.\nconst sectionIconClasses = [\n 'ds:inline-flex ds:shrink-0 ds:items-center ds:justify-center',\n 'ds:size-4',\n 'ds:text-[var(--accent)]',\n 'ds:me-[var(--spacing-xs)]',\n].join(' ');\n\nconst SidebarSection = forwardRef<HTMLDivElement, SidebarSectionProps>(\n (\n {\n label,\n icon,\n collapsible = true,\n defaultOpen = true,\n open,\n onOpenChange,\n className,\n children,\n ...rest\n },\n ref,\n ) => {\n const { mode } = useSidebar();\n const isIconMode = mode === 'icon';\n // Collapsing the section in icon mode hides icons the user needs for\n // navigation — skip the accordion behaviour there.\n const isAccordion = collapsible && !isIconMode && Boolean(label);\n\n const wrapperClasses = [\n 'ds:flex ds:flex-col',\n 'ds:gap-[var(--spacing-xs)]',\n 'ds:mt-[var(--spacing-sm)]',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ');\n\n if (!isAccordion) {\n // In icon mode, if there's no icon and no label to render, skip the\n // heading altogether. If there is an icon, it stays visible as the\n // grouping cue and the label collapses to sr-only.\n const hasHeading = Boolean(label) || Boolean(icon);\n return (\n <div ref={ref} className={wrapperClasses} {...rest}>\n {hasHeading ? (\n <span\n className={[\n 'ds:flex ds:items-center',\n 'type-eyebrow',\n 'ds:text-[var(--muted-foreground)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n 'ds:py-[var(--spacing-xs)]',\n isIconMode && !icon ? 'ds:sr-only' : '',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {icon ? (\n <span aria-hidden=\"true\" className={sectionIconClasses}>\n {icon}\n </span>\n ) : null}\n {label ? (\n <span className={isIconMode ? 'ds:sr-only' : ''}>{label}</span>\n ) : null}\n </span>\n ) : null}\n {children}\n </div>\n );\n }\n\n // Use the Radix Accordion primitive + the DS `AccordionContent`\n // component so the sidebar inherits the exact open/close animation\n // defined in `accordion.tsx` (`accordion-down` / `accordion-up`\n // keyframes). Any tweak there propagates here automatically.\n const accordionValue = 'section';\n return (\n <RadixAccordion.Root\n type=\"single\"\n collapsible\n defaultValue={\n open === undefined && defaultOpen ? accordionValue : undefined\n }\n value={open === undefined ? undefined : open ? accordionValue : ''}\n onValueChange={\n onOpenChange ? (v) => onOpenChange(v === accordionValue) : undefined\n }\n asChild\n >\n <div ref={ref} className={wrapperClasses} {...rest}>\n <RadixAccordion.Item value={accordionValue}>\n <RadixAccordion.Header className=\"ds:flex\">\n <RadixAccordion.Trigger className={sectionLabelClasses}>\n {icon ? (\n <span aria-hidden=\"true\" className={sectionIconClasses}>\n {icon}\n </span>\n ) : null}\n <span className=\"ds:flex-1 ds:text-start\">{label}</span>\n <ChevronRight\n aria-hidden=\"true\"\n className=\"ds:size-3 ds:transition-transform ds:group-data-[state=open]/section-label:rotate-90 ds:rtl:-scale-x-100 ds:motion-reduce:transition-none\"\n />\n </RadixAccordion.Trigger>\n </RadixAccordion.Header>\n <AccordionContent\n aria-label={label}\n // Flatten the inner padding wrapper AccordionContent adds —\n // the sidebar sections don't want the 16px padding block\n // that Accordion cards use. `display: contents` strips the\n // wrapper from layout so our children flow directly into\n // the flex column with the gap we set here.\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:[&>div]:contents\"\n >\n {children}\n </AccordionContent>\n </RadixAccordion.Item>\n </div>\n </RadixAccordion.Root>\n );\n },\n);\nSidebarSection.displayName = 'SidebarSection';\n\n/* -------------------------------------------------------------------- */\n/* Group (collapsible) */\n/* -------------------------------------------------------------------- */\n\nexport interface SidebarGroupProps extends ComponentPropsWithoutRef<\n typeof RadixCollapsible.Root\n> {\n /** Visible label for the group trigger. */\n label: string;\n /** Optional leading icon. */\n icon?: ReactNode;\n}\n\nconst groupTriggerClasses = [\n 'ds:group ds:flex ds:w-full ds:items-center ds:gap-[var(--spacing-sm)]',\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:text-[var(--foreground)] ds:text-[var(--font-size-sm)]',\n 'ds:font-[var(--font-weight-medium)]',\n 'ds:hover:bg-[var(--muted)]/20',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n].join(' ');\n\nconst SidebarGroup = forwardRef<HTMLDivElement, SidebarGroupProps>(\n (\n {\n label,\n icon,\n children,\n className,\n defaultOpen,\n open,\n onOpenChange,\n ...rest\n },\n ref,\n ) => {\n const { mode } = useSidebar();\n return (\n <RadixCollapsible.Root\n ref={ref}\n defaultOpen={defaultOpen}\n open={open}\n onOpenChange={onOpenChange}\n className={className}\n {...rest}\n >\n <RadixCollapsible.Trigger className={groupTriggerClasses}>\n {icon ? (\n <span\n aria-hidden=\"true\"\n className=\"ds:inline-flex ds:items-center ds:text-[var(--accent)]\"\n >\n {icon}\n </span>\n ) : null}\n <span\n className={[\n 'ds:flex-1 ds:text-start',\n mode === 'icon' ? 'ds:sr-only' : '',\n ].join(' ')}\n >\n {label}\n </span>\n {mode !== 'icon' ? (\n <ChevronRight\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:transition-transform ds:group-data-[state=open]:rotate-90 ds:rtl:-scale-x-100 ds:motion-reduce:transition-none\"\n />\n ) : null}\n </RadixCollapsible.Trigger>\n <RadixCollapsible.Content\n className={[\n 'ds:overflow-hidden',\n 'ds:data-[state=open]:animate-in ds:data-[state=closed]:animate-out',\n 'ds:motion-reduce:animate-none',\n 'ds:ps-[var(--spacing-md)]',\n ].join(' ')}\n >\n {children}\n </RadixCollapsible.Content>\n </RadixCollapsible.Root>\n );\n },\n);\nSidebarGroup.displayName = 'SidebarGroup';\n\n/* -------------------------------------------------------------------- */\n/* Item */\n/* -------------------------------------------------------------------- */\n\nconst itemClasses = cva(\n [\n // Every row is a pin-hover parent so inline pin / reorder affordances can\n // fade in on hover of the whole row — keep `group/item` on this selector.\n // `!text-[var(--foreground)]` forces the label colour over the browser's\n // default `<a>` link colour (blue-violet) and any inherited hue. The\n // active variant also uses `!text-*` so it still wins when needed.\n 'ds:group/item ds:relative ds:flex ds:items-center',\n 'ds:gap-[var(--spacing-sm)]',\n 'ds:no-underline ds:!text-[var(--foreground)] ds:text-[length:var(--font-size-sm)]',\n 'ds:hover:bg-[var(--muted)]/12',\n 'ds:transition-colors ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n ].join(' '),\n {\n variants: {\n mode: {\n expanded: [\n 'ds:min-h-[var(--min-target-size)] ds:rounded-[var(--radius-sm)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n ].join(' '),\n // Icon-only: each item is a 44×44 pill tile centered in the rail.\n // The active / hover background fills just the tile rather than the\n // whole row — matching Linear / Asana chrome.\n icon: [\n 'ds:justify-center ds:ms-auto ds:me-auto',\n 'ds:w-[var(--min-target-size)] ds:h-[var(--min-target-size)]',\n 'ds:ps-0 ds:pe-0 ds:rounded-[var(--radius-md)]',\n ].join(' '),\n overlay: [\n 'ds:min-h-[var(--min-target-size)] ds:rounded-[var(--radius-sm)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n ].join(' '),\n },\n density: {\n default: '',\n compact: 'ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)]',\n },\n isActive: {\n // Filled pill — multi-carrier (bg + text + weight + aria-current at\n // render time) so colour is never the sole identifier. `!text-*`\n // forces the foreground over any inherited / base rule so the icon\n // and label read clearly against the primary fill in every theme.\n true: [\n 'ds:bg-[var(--primary)] ds:!text-[var(--primary-foreground)]',\n 'ds:font-[var(--font-weight-semibold)]',\n // Keep hover from dimming the active fill.\n 'ds:hover:bg-[var(--primary)]',\n ].join(' '),\n false: '',\n },\n },\n defaultVariants: {\n mode: 'expanded',\n density: 'default',\n isActive: false,\n },\n },\n);\n\nexport interface SidebarItemProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n /** Mark the item as the current page (`aria-current='page'`). */\n isActive?: boolean;\n /** Render through Radix `Slot` so a router link can take over. */\n asChild?: boolean;\n /**\n * Whether this item is currently pinned to Favourites. Only consulted\n * when `onPinChange` is supplied.\n */\n isPinned?: boolean;\n /**\n * Fires with the new pinned state when the user clicks the star. Passing\n * this prop opts the row into the always-on pin affordance — a star\n * outline fades in on row hover / focus and fills when pinned. Hidden in\n * icon-only mode where there is no room for trailing controls.\n */\n onPinChange?: (next: boolean) => void;\n /** Accessible label for the pin button. Defaults to the item's `aria-label`. */\n pinLabel?: string;\n}\n\nconst SidebarItem = forwardRef<HTMLAnchorElement, SidebarItemProps>(\n (\n {\n asChild = false,\n isActive = false,\n isPinned = false,\n onPinChange,\n pinLabel,\n className,\n children,\n 'aria-label': ariaLabel,\n ...rest\n },\n ref,\n ) => {\n const { mode, density } = useSidebar();\n const Comp = asChild ? Slot : 'a';\n const showPin = onPinChange !== undefined && mode !== 'icon';\n\n const anchor = (\n <Comp\n ref={ref as never}\n aria-current={isActive ? 'page' : undefined}\n aria-label={ariaLabel}\n className={itemClasses({\n mode,\n density,\n isActive,\n className: showPin ? 'ds:flex-1 ds:min-w-0' : className,\n })}\n {...rest}\n >\n {children}\n </Comp>\n );\n\n const body = showPin ? (\n <div\n className={[\n 'ds:group/item ds:flex ds:items-center ds:gap-[var(--spacing-2xs)]',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {anchor}\n <SidebarPinButton\n isPinned={isPinned}\n label={pinLabel ?? ariaLabel ?? ''}\n onPinChange={onPinChange}\n />\n </div>\n ) : (\n anchor\n );\n\n // In icon-only mode, wrap the item in a Radix Tooltip showing the label.\n if (mode === 'icon' && ariaLabel) {\n return (\n <RadixTooltip.Root>\n <RadixTooltip.Trigger asChild>{body}</RadixTooltip.Trigger>\n <RadixTooltip.Portal>\n <RadixTooltip.Content\n side=\"right\"\n sideOffset={6}\n className={[\n 'ds:z-[var(--z-tooltip)] ds:max-w-[16rem]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:bg-[var(--foreground)] ds:text-[var(--background)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:py-[var(--spacing-xs)] ds:text-[length:var(--font-size-xs)]',\n 'ds:animate-in ds:fade-in ds:zoom-in-95 ds:motion-reduce:animate-none',\n ].join(' ')}\n >\n {ariaLabel}\n <RadixTooltip.Arrow className=\"ds:fill-[var(--foreground)]\" />\n </RadixTooltip.Content>\n </RadixTooltip.Portal>\n </RadixTooltip.Root>\n );\n }\n\n return body;\n },\n);\nSidebarItem.displayName = 'SidebarItem';\n\n/* -------------------------------------------------------------------- */\n/* Item slots — Icon, Label, Badge */\n/* -------------------------------------------------------------------- */\n\nconst SidebarItemIcon = forwardRef<\n HTMLSpanElement,\n ComponentPropsWithoutRef<'span'>\n>(({ className, children, ...rest }, ref) => (\n <span\n ref={ref}\n aria-hidden=\"true\"\n className={[\n 'ds:inline-flex ds:shrink-0 ds:items-center ds:justify-center',\n 'ds:size-5',\n // Icons carry the accent tint by default so the rail reads less\n // monotone against the violet active pill. The active row sets\n // `aria-current=\"page\"` on the anchor (which is `group/item`), so\n // the icon flips to the primary-foreground (white) on the filled\n // pill — keeping it readable on the primary background.\n 'ds:text-[var(--accent)]',\n 'ds:group-aria-[current=page]/item:text-[var(--primary-foreground)]',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n {children}\n </span>\n));\nSidebarItemIcon.displayName = 'SidebarItemIcon';\n\nconst SidebarItemLabel = forwardRef<\n HTMLSpanElement,\n ComponentPropsWithoutRef<'span'>\n>(({ className, children, ...rest }, ref) => {\n const { mode } = useSidebar();\n return (\n <span\n ref={ref}\n className={[\n 'ds:flex-1',\n 'ds:overflow-hidden ds:text-ellipsis ds:whitespace-nowrap ds:break-normal',\n 'ds:text-start',\n mode === 'icon' ? 'ds:sr-only' : '',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n {children}\n </span>\n );\n});\nSidebarItemLabel.displayName = 'SidebarItemLabel';\n\nconst SidebarItemBadge = forwardRef<\n HTMLSpanElement,\n ComponentPropsWithoutRef<'span'>\n>(({ className, children, ...rest }, ref) => {\n const { mode } = useSidebar();\n const isIcon = mode === 'icon';\n // --accent on a light surface is magenta-500 (~3.2:1 on white) and\n // fails WCAG AA for `--font-size-xs` text per 05-accessibility §Accent.\n // Use --primary + its token-paired foreground so contrast is preserved\n // in every theme.\n //\n // In icon mode the pill collapses to a compact presence indicator: a\n // 10×10 dot perched on the top-end of the icon tile with a background-\n // coloured ring so it reads against any row fill. The numeric count is\n // hidden visually but stays in the accessible name via an sr-only span.\n return (\n <span\n ref={ref}\n aria-hidden={isIcon ? 'true' : undefined}\n className={[\n 'ds:inline-flex ds:items-center ds:justify-center',\n 'ds:font-[var(--font-weight-semibold)]',\n isIcon\n ? [\n 'ds:absolute ds:top-[2px] ds:end-[2px]',\n 'ds:min-w-0 ds:size-[10px] ds:ps-0 ds:pe-0',\n 'ds:rounded-[var(--radius-full)]',\n 'ds:bg-[var(--primary)] ds:text-transparent',\n 'ds:ring-2 ds:ring-[var(--background)]',\n 'ds:pointer-events-none',\n ].join(' ')\n : [\n 'ds:min-w-[var(--spacing-lg)] ds:h-[var(--spacing-lg)]',\n 'ds:rounded-[var(--radius-full)]',\n 'ds:bg-[var(--primary)] ds:text-[var(--primary-foreground)]',\n 'ds:text-[length:var(--font-size-xs)]',\n 'ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)]',\n ].join(' '),\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n {children}\n </span>\n );\n});\nSidebarItemBadge.displayName = 'SidebarItemBadge';\n\n/* -------------------------------------------------------------------- */\n/* Modern-only compound pieces */\n/* */\n/* These components ship styling that matches the modern aesthetic. */\n/* They are INTERACTION STUBS — they render the correct chrome but do */\n/* not open a DropdownMenu, because the DS <DropdownMenu> wrapper does */\n/* not exist yet (see review-findings/component-cohesion.mdx). Consumers */\n/* wire their own Radix DropdownMenu around these triggers until the DS */\n/* wrapper lands. Do NOT add aria-haspopup here — it would announce a */\n/* menu that never opens (screen-reader lie). */\n/* -------------------------------------------------------------------- */\n\nconst workspaceSwitcherClasses = cva(\n [\n 'ds:flex ds:items-center ds:gap-[var(--spacing-sm)]',\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n 'ds:rounded-[var(--radius-md)]',\n 'ds:text-[var(--foreground)] ds:text-[length:var(--font-size-sm)]',\n 'ds:hover:bg-[var(--muted)]/20',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n 'ds:no-underline',\n ].join(' '),\n);\n\nexport interface SidebarWorkspaceSwitcherProps extends ComponentPropsWithoutRef<'button'> {\n /** Workspace glyph — square <Avatar>, <img>, or <svg>. Required. */\n logo: ReactNode;\n /** Workspace name. Hidden in icon mode; always the accessible name. */\n name: string;\n /** Trailing chevron for the dropdown affordance. Defaults to true. */\n showChevron?: boolean;\n}\n\nconst SidebarWorkspaceSwitcher = forwardRef<\n HTMLButtonElement,\n SidebarWorkspaceSwitcherProps\n>(({ logo, name, showChevron = true, className, ...rest }, ref) => {\n const { mode } = useSidebar();\n const showLabel = mode !== 'icon';\n return (\n <button\n ref={ref}\n type=\"button\"\n aria-label={name}\n className={[workspaceSwitcherClasses(), className]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n <span\n aria-hidden=\"true\"\n className=\"ds:inline-flex ds:items-center ds:shrink-0\"\n >\n {logo}\n </span>\n {showLabel ? (\n <>\n <span className=\"ds:truncate ds:flex-1 ds:text-start ds:max-w-[var(--header-workspace-max-inline-size)]\">\n {name}\n </span>\n {showChevron ? (\n <ChevronRight\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:shrink-0 ds:rotate-90\"\n />\n ) : null}\n </>\n ) : null}\n </button>\n );\n});\nSidebarWorkspaceSwitcher.displayName = 'SidebarWorkspaceSwitcher';\n\n/* -- Primary action slot -------------------------------------------- */\n\nconst primaryActionClasses = cva(\n [\n 'ds:flex ds:items-center ds:justify-center ds:gap-[var(--spacing-xs)]',\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:rounded-[var(--radius-md)]',\n 'ds:bg-[var(--primary)] ds:text-[var(--primary-foreground)]',\n 'ds:font-[var(--font-weight-semibold)] ds:text-[length:var(--font-size-sm)]',\n 'ds:hover:bg-[var(--primary-hover)]',\n 'ds:transition-colors ds:motion-reduce:transition-none',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n ].join(' '),\n {\n variants: {\n mode: {\n expanded: 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n icon: 'ds:ps-0 ds:pe-0 ds:w-[var(--sidebar-modern-tile)] ds:h-[var(--sidebar-modern-tile)] ds:ms-auto ds:me-auto',\n overlay: 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n },\n },\n defaultVariants: { mode: 'expanded' },\n },\n);\n\nexport interface SidebarPrimaryActionProps extends ComponentPropsWithoutRef<'button'> {\n icon: ReactNode;\n /** Button label — hidden in icon mode, always the accessible name. */\n label: string;\n /** Optional keyboard shortcut displayed on inline-end in expanded mode. */\n shortcut?: string;\n}\n\nconst SidebarPrimaryAction = forwardRef<\n HTMLButtonElement,\n SidebarPrimaryActionProps\n>(({ icon, label, shortcut, className, ...rest }, ref) => {\n const { mode } = useSidebar();\n const showLabel = mode !== 'icon';\n return (\n <button\n ref={ref}\n type=\"button\"\n aria-label={label}\n aria-keyshortcuts={shortcut}\n className={[primaryActionClasses({ mode }), className]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n <span\n aria-hidden=\"true\"\n className=\"ds:inline-flex ds:size-4 ds:items-center ds:justify-center\"\n >\n {icon}\n </span>\n {showLabel ? (\n <>\n <span className=\"ds:truncate\">{label}</span>\n {shortcut ? (\n <kbd className=\"ds:ms-auto ds:text-[length:var(--font-size-xs)] ds:font-[family-name:var(--font-mono)] ds:opacity-80\">\n {shortcut}\n </kbd>\n ) : null}\n </>\n ) : null}\n </button>\n );\n});\nSidebarPrimaryAction.displayName = 'SidebarPrimaryAction';\n\n/* -- Pin button ----------------------------------------------------- */\n\n/**\n * Toggleable star button used to pin / unpin a nav item to the Favorites\n * section. Rendered inline alongside a `SidebarItem`'s content — hidden in\n * icon mode (pin affordances only make sense when the full row is visible).\n *\n * Controlled via `isPinned` + `onPinChange`. The consumer owns the list of\n * pinned items and mirrors them into `<SidebarFavorites>`.\n */\nexport interface SidebarPinButtonProps extends Omit<\n ComponentPropsWithoutRef<'button'>,\n 'onChange'\n> {\n /** Whether the associated item is currently pinned. */\n isPinned: boolean;\n /** Fires with the new pinned state. */\n onPinChange?: (next: boolean) => void;\n /**\n * Accessible label that names what is being pinned — e.g. the item's\n * label. Required so screen-readers can tell pin buttons apart.\n */\n label: string;\n}\n\nconst pinButtonClasses = [\n 'ds:inline-flex ds:items-center ds:justify-center ds:shrink-0',\n 'ds:size-6 ds:rounded-[var(--radius-sm)]',\n // Pin stars carry the accent tint to match every other icon in the rail.\n // Stays quiet via opacity — reveals only on row hover / focus.\n 'ds:text-[var(--accent)]',\n 'ds:opacity-0 ds:group-hover/item:opacity-100 ds:focus-visible:opacity-100',\n 'ds:hover:bg-[var(--muted)]/20',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n 'ds:transition-[color,opacity,background-color] ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n].join(' ');\n\nconst SidebarPinButton = forwardRef<HTMLButtonElement, SidebarPinButtonProps>(\n ({ isPinned, onPinChange, label, className, onClick, ...rest }, ref) => {\n const { t } = useTranslation();\n const { mode } = useSidebar();\n if (mode === 'icon') return null;\n const accessibleLabel = isPinned\n ? t('navigation.sidebar.unpinItem', 'Unpin {{label}}', { label })\n : t('navigation.sidebar.pinItem', 'Pin {{label}}', { label });\n return (\n <button\n ref={ref}\n type=\"button\"\n aria-label={accessibleLabel}\n aria-pressed={isPinned}\n className={[pinButtonClasses, className].filter(Boolean).join(' ')}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n onPinChange?.(!isPinned);\n onClick?.(event);\n }}\n {...rest}\n >\n <Star\n aria-hidden=\"true\"\n className=\"ds:size-4\"\n fill={isPinned ? 'currentColor' : 'none'}\n />\n </button>\n );\n },\n);\nSidebarPinButton.displayName = 'SidebarPinButton';\n\n/* -- Favorites — reorderable section -------------------------------- */\n\ninterface SidebarFavoritesContextValue {\n onReorder?: (from: number, to: number) => void;\n count: number;\n dragSource: number | null;\n setDragSource: (index: number | null) => void;\n announce: (message: string) => void;\n}\n\nconst SidebarFavoritesContext =\n createContext<SidebarFavoritesContextValue | null>(null);\n\nconst useFavoritesContext = () => useContext(SidebarFavoritesContext);\n\n/**\n * Renders `<SidebarSection heading={t('navigation.sidebar.favorites')}>` with an\n * empty-state prompt when no children are supplied. When `onReorder` is\n * provided, children rendered as `<SidebarFavoriteItem>` become drag-and-drop\n * and keyboard reorderable (Alt+↑ / Alt+↓).\n */\nexport interface SidebarFavoritesProps extends ComponentPropsWithoutRef<'div'> {\n heading?: string;\n /** Shown when `children` is empty. */\n emptyMessage?: string;\n /**\n * Called when a favorite item is moved from `from` index to `to` index.\n * Providing this opts the section into drag-and-drop + keyboard reorder.\n */\n onReorder?: (from: number, to: number) => void;\n}\n\nconst SidebarFavorites = forwardRef<HTMLDivElement, SidebarFavoritesProps>(\n ({ heading, emptyMessage, onReorder, className, children, ...rest }, ref) => {\n const { t } = useTranslation();\n const resolvedHeading =\n heading ?? t('navigation.sidebar.favorites', 'Favourites');\n const childArray = Array.isArray(children)\n ? children.filter(Boolean)\n : children\n ? [children]\n : [];\n const count = childArray.length;\n const hasChildren = count > 0;\n const [dragSource, setDragSource] = useState<number | null>(null);\n const [liveMessage, setLiveMessage] = useState('');\n // Re-emit identical announcements by toggling an invisible suffix so\n // screen-readers treat repeated moves as distinct.\n const announceToggle = useRef(false);\n const announce = useCallback((message: string) => {\n announceToggle.current = !announceToggle.current;\n setLiveMessage(announceToggle.current ? message : `${message}\\u200b`);\n }, []);\n\n const value = useMemo<SidebarFavoritesContextValue>(\n () => ({ onReorder, count, dragSource, setDragSource, announce }),\n [onReorder, count, dragSource, announce],\n );\n\n // When there are no pinned items, render nothing by default — no\n // heading, no empty-state copy. Consumers that want an explicit empty\n // state can pass `emptyMessage` to opt in.\n if (!hasChildren && !emptyMessage) return null;\n\n return (\n <SidebarFavoritesContext.Provider value={value}>\n <SidebarSection\n ref={ref}\n label={resolvedHeading}\n className={className}\n {...rest}\n >\n {hasChildren ? (\n childArray\n ) : (\n <p className=\"ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] type-meta ds:text-[color:var(--muted-foreground)]\">\n {emptyMessage}\n </p>\n )}\n <span role=\"status\" aria-live=\"polite\" className=\"ds:sr-only\">\n {liveMessage}\n </span>\n </SidebarSection>\n </SidebarFavoritesContext.Provider>\n );\n },\n);\nSidebarFavorites.displayName = 'SidebarFavorites';\n\n/* -- Favorite item with drag handle + keyboard reorder -------------- */\n\nexport interface SidebarFavoriteItemProps extends SidebarItemProps {\n /** Zero-based position of this item within its `<SidebarFavorites>`. */\n index: number;\n /**\n * Accessible name used by the drag handle and live-region announcements.\n * Defaults to the `aria-label` of the underlying `SidebarItem`.\n */\n reorderLabel?: string;\n}\n\nconst favoriteRowClasses = cva(\n [\n 'ds:group/item ds:relative ds:flex ds:items-center ds:gap-[var(--spacing-2xs)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n ].join(' '),\n {\n variants: {\n dragging: {\n true: 'ds:opacity-60',\n false: '',\n },\n dropTarget: {\n true: 'ds:outline-[length:var(--focus-ring-width)] ds:outline-dashed ds:outline-[var(--primary)] ds:outline-offset-[-2px]',\n false: '',\n },\n },\n defaultVariants: { dragging: false, dropTarget: false },\n },\n);\n\nconst dragHandleClasses = [\n 'ds:inline-flex ds:items-center ds:justify-center ds:shrink-0',\n 'ds:size-6 ds:rounded-[var(--radius-sm)]',\n 'ds:cursor-grab ds:active:cursor-grabbing',\n 'ds:text-[var(--muted-foreground)]',\n // Quiet chrome — only reveal the grip when the row is hovered or the\n // handle itself is focused (keyboard / AT). Matches the pin-star's\n // reveal-on-hover behaviour so the two siblings appear together.\n 'ds:opacity-0 ds:group-hover/item:opacity-100 ds:focus-visible:opacity-100',\n 'ds:hover:bg-[var(--muted)]/20 ds:hover:text-[var(--foreground)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n 'ds:transition-[color,opacity,background-color] ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n].join(' ');\n\nconst SidebarFavoriteItem = forwardRef<\n HTMLAnchorElement,\n SidebarFavoriteItemProps\n>(\n (\n {\n index,\n isActive = false,\n asChild = false,\n reorderLabel,\n isPinned = false,\n onPinChange,\n pinLabel,\n 'aria-label': ariaLabel,\n className,\n children,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation();\n const { mode } = useSidebar();\n const favorites = useFavoritesContext();\n const [isDropTarget, setIsDropTarget] = useState(false);\n const canReorder = Boolean(favorites?.onReorder) && mode !== 'icon';\n const label = reorderLabel ?? ariaLabel ?? '';\n const handleId = useId();\n\n const moveFromTo = (from: number, to: number) => {\n if (!favorites?.onReorder) return;\n const clamped = Math.max(0, Math.min(favorites.count - 1, to));\n if (clamped === from) return;\n favorites.onReorder(from, clamped);\n favorites.announce(\n t(\n 'navigation.sidebar.reorderAnnounce',\n '{{label}} moved to position {{to}} of {{total}}',\n { label, to: clamped + 1, total: favorites.count },\n ),\n );\n };\n\n const onHandleKeyDown = (event: ReactKeyboardEvent<HTMLButtonElement>) => {\n if (!canReorder) return;\n if (event.altKey && event.key === 'ArrowUp') {\n event.preventDefault();\n moveFromTo(index, index - 1);\n } else if (event.altKey && event.key === 'ArrowDown') {\n event.preventDefault();\n moveFromTo(index, index + 1);\n } else if (event.key === 'Home' && event.altKey) {\n event.preventDefault();\n moveFromTo(index, 0);\n } else if (event.key === 'End' && event.altKey) {\n event.preventDefault();\n moveFromTo(index, favorites!.count - 1);\n }\n };\n\n const onDragStart = (\n event: ReactMouseEvent & { dataTransfer?: DataTransfer },\n ) => {\n if (!canReorder) return;\n favorites?.setDragSource(index);\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = 'move';\n // Firefox requires data to initiate a drag.\n event.dataTransfer.setData('ds:text/plain', String(index));\n }\n };\n\n const onDragEnd = () => {\n favorites?.setDragSource(null);\n setIsDropTarget(false);\n };\n\n const onDragOver = (\n event: ReactMouseEvent & { dataTransfer?: DataTransfer },\n ) => {\n if (!canReorder || favorites?.dragSource === null) return;\n event.preventDefault();\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'move';\n setIsDropTarget(true);\n };\n\n const onDragLeave = () => setIsDropTarget(false);\n\n const onDrop = (event: ReactMouseEvent) => {\n if (!canReorder) return;\n event.preventDefault();\n const source = favorites?.dragSource;\n setIsDropTarget(false);\n if (source === null || source === undefined || source === index) return;\n moveFromTo(source, index);\n };\n\n const isDragging = favorites?.dragSource === index;\n\n return (\n <div\n className={favoriteRowClasses({\n dragging: isDragging,\n dropTarget: isDropTarget && !isDragging,\n })}\n // Drag the whole row — the grip is a visual + keyboard affordance,\n // not the sole drag target. Buttons don't start HTML5 drags reliably\n // in every browser, so we mount the drag events on the row wrapper.\n draggable={canReorder || undefined}\n onDragStart={\n canReorder\n ? (onDragStart as unknown as (\n e: ReactMouseEvent<HTMLDivElement>,\n ) => void)\n : undefined\n }\n onDragEnd={canReorder ? onDragEnd : undefined}\n onDragOver={\n onDragOver as unknown as (e: ReactMouseEvent<HTMLDivElement>) => void\n }\n onDragLeave={onDragLeave}\n onDrop={onDrop}\n >\n <SidebarItem\n ref={ref}\n isActive={isActive}\n asChild={asChild}\n aria-label={ariaLabel}\n aria-describedby={canReorder ? handleId : undefined}\n // Links and images are `draggable=auto` by default — without this\n // the browser would fire its native link-drag before our row-level\n // drag, and our reorder would never start.\n draggable={canReorder ? false : undefined}\n className={[canReorder ? 'ds:flex-1 ds:min-w-0' : '', className ?? '']\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n {children}\n </SidebarItem>\n {canReorder ? (\n <button\n type=\"button\"\n id={handleId}\n aria-label={t(\n 'navigation.sidebar.reorderHandle',\n 'Reorder {{label}}. Press Alt + Up or Alt + Down to move.',\n { label },\n )}\n className={dragHandleClasses}\n onKeyDown={onHandleKeyDown}\n >\n <GripVertical aria-hidden=\"true\" className=\"ds:size-4\" />\n </button>\n ) : null}\n {onPinChange && mode !== 'icon' ? (\n <SidebarPinButton\n isPinned={isPinned}\n label={pinLabel ?? ariaLabel ?? ''}\n onPinChange={onPinChange}\n />\n ) : null}\n </div>\n );\n },\n);\nSidebarFavoriteItem.displayName = 'SidebarFavoriteItem';\n\n/* -- Profile pill at the block-end --------------------------------- */\n\nconst profilePillClasses = cva(\n [\n 'ds:flex ds:items-center ds:gap-[var(--spacing-sm)]',\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n 'ds:rounded-[var(--radius-md)]',\n 'ds:text-[var(--foreground)] ds:text-[length:var(--font-size-sm)]',\n 'ds:hover:bg-[var(--muted)]/20',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n 'ds:no-underline',\n ].join(' '),\n);\n\nexport interface SidebarProfilePillProps extends ComponentPropsWithoutRef<'button'> {\n /** Avatar or other identifying glyph. Required. */\n avatar: ReactNode;\n /** User's display name — hidden in icon mode, always the accessible name. */\n name: string;\n /**\n * Secondary line (e.g. selected studio, \"Owner\", \"Admin\"). Accepts arbitrary\n * JSX so an icon can sit inline with the text. Hidden in icon mode.\n */\n subtitle?: ReactNode;\n /**\n * Plain-text form of the subtitle for the accessible name. Required when\n * `subtitle` is not a string; ignored otherwise.\n */\n subtitleLabel?: string;\n}\n\nconst SidebarProfilePill = forwardRef<\n HTMLButtonElement,\n SidebarProfilePillProps\n>(({ avatar, name, subtitle, subtitleLabel, className, ...rest }, ref) => {\n const { mode } = useSidebar();\n const showLabel = mode !== 'icon';\n const accessibleSubtitle =\n typeof subtitle === 'string' ? subtitle : subtitleLabel;\n return (\n <button\n ref={ref}\n type=\"button\"\n aria-label={accessibleSubtitle ? `${name}, ${accessibleSubtitle}` : name}\n // No `aria-haspopup` here until a DropdownMenu is wired — announcing\n // a menu that never opens is a screen-reader lie. Consumers wrap\n // this trigger in their own Radix DropdownMenu.\n className={[profilePillClasses(), className].filter(Boolean).join(' ')}\n {...rest}\n >\n <span\n aria-hidden=\"true\"\n className=\"ds:inline-flex ds:items-center ds:shrink-0\"\n >\n {avatar}\n </span>\n {showLabel ? (\n <span className=\"ds:flex-1 ds:min-w-0 ds:text-start\">\n <span className=\"ds:block ds:truncate type-label\">{name}</span>\n {subtitle ? (\n typeof subtitle === 'string' ? (\n <span className=\"ds:block ds:truncate type-meta ds:text-[color:var(--muted-foreground)]\">\n {subtitle}\n </span>\n ) : (\n <span className=\"ds:flex ds:items-center ds:gap-[length:var(--spacing-xs)] ds:min-w-0 type-meta ds:text-[color:var(--muted-foreground)]\">\n {subtitle}\n </span>\n )\n ) : null}\n </span>\n ) : null}\n </button>\n );\n});\nSidebarProfilePill.displayName = 'SidebarProfilePill';\n\n/* -------------------------------------------------------------------- */\n/* Collapse trigger */\n/* */\n/* Full-width nav-item-style toggle that swaps between `expanded` and */\n/* `icon` modes. A compact 44×44 icon-only button — drop it inline next */\n/* to the profile pill, Settings row, or anywhere else. Accessible name */\n/* comes from the i18n collapse / expand string; a tooltip shows the */\n/* same text on hover / focus so sighted users don't have to guess. */\n/* */\n/* Hidden in `overlay` mode (overlay has its own close button). */\n/* -------------------------------------------------------------------- */\n\nexport interface SidebarCollapseTriggerProps extends ComponentPropsWithoutRef<'button'> {\n /** Override the accessible label. Defaults to the i18n collapse/expand string. */\n 'aria-label'?: string;\n}\n\nconst collapseTriggerClasses = [\n 'ds:inline-flex ds:items-center ds:justify-center ds:shrink-0',\n 'ds:min-w-[var(--min-target-size)] ds:min-h-[var(--min-target-size)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:text-[var(--muted-foreground)]',\n 'ds:hover:bg-[var(--muted)]/20 ds:hover:text-[var(--foreground)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n].join(' ');\n\nconst SidebarCollapseTrigger = forwardRef<\n HTMLButtonElement,\n SidebarCollapseTriggerProps\n>(({ className, 'aria-label': ariaLabel, onClick, ...rest }, ref) => {\n const { t } = useTranslation();\n const { mode, transitionTo } = useSidebar();\n\n if (mode === 'overlay') return null;\n\n const isExpanded = mode === 'expanded';\n const accessibleLabel =\n ariaLabel ??\n (isExpanded\n ? t('navigation.sidebar.collapse', 'Collapse sidebar')\n : t('navigation.sidebar.expand', 'Expand sidebar'));\n\n const button = (\n <button\n ref={ref}\n type=\"button\"\n aria-label={accessibleLabel}\n aria-expanded={isExpanded}\n onClick={(event) => {\n transitionTo?.(isExpanded ? 'icon' : 'expanded');\n onClick?.(event);\n }}\n className={[collapseTriggerClasses, className].filter(Boolean).join(' ')}\n {...rest}\n >\n {isExpanded ? (\n <PanelLeftClose\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:rtl:-scale-x-100\"\n />\n ) : (\n <PanelLeftOpen\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:rtl:-scale-x-100\"\n />\n )}\n </button>\n );\n\n return (\n <RadixTooltip.Root>\n <RadixTooltip.Trigger asChild>{button}</RadixTooltip.Trigger>\n <RadixTooltip.Portal>\n <RadixTooltip.Content\n side={mode === 'icon' ? 'right' : 'top'}\n sideOffset={6}\n className={[\n 'ds:z-[var(--z-tooltip)] ds:max-w-[16rem]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:bg-[var(--foreground)] ds:text-[var(--background)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:py-[var(--spacing-xs)] ds:text-[length:var(--font-size-xs)]',\n 'ds:animate-in ds:fade-in ds:zoom-in-95 ds:motion-reduce:animate-none',\n ].join(' ')}\n >\n {accessibleLabel}\n <RadixTooltip.Arrow className=\"ds:fill-[var(--foreground)]\" />\n </RadixTooltip.Content>\n </RadixTooltip.Portal>\n </RadixTooltip.Root>\n );\n});\nSidebarCollapseTrigger.displayName = 'SidebarCollapseTrigger';\n\n/* -------------------------------------------------------------------- */\n/* Upgrade chip */\n/* */\n/* Persistent navigation affordance into the upgrade-packages area */\n/* (PAU) that sits between the body and the footer. Deliberately NOT */\n/* dismissible — it is chrome, not a banner. Consumers supply the copy */\n/* and destination; the chip owns layout, theming, and mode adaptation. */\n/* In icon mode it collapses to a 44×44 tile with a tooltip; the */\n/* accent-gradient surface flattens to the page background in the */\n/* accessible themes and follows Canvas in forced-colors. */\n/* -------------------------------------------------------------------- */\n\nconst upgradeChipClasses = cva(\n [\n 'ds:flex ds:items-center ds:gap-[var(--spacing-sm)]',\n 'ds:rounded-[var(--radius-md)]',\n 'ds:border ds:border-[var(--border)]',\n 'ds:bg-[image:var(--gradient-surface-subtle-accent)]',\n 'ds:no-underline ds:!text-[var(--foreground)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n ].join(' '),\n {\n variants: {\n mode: {\n expanded: [\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:py-[var(--spacing-sm)]',\n ].join(' '),\n icon: [\n 'ds:justify-center',\n 'ds:w-[var(--min-target-size)] ds:h-[var(--min-target-size)]',\n 'ds:ms-auto ds:me-auto ds:ps-0 ds:pe-0',\n ].join(' '),\n overlay: [\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:py-[var(--spacing-sm)]',\n ].join(' '),\n },\n },\n defaultVariants: { mode: 'expanded' },\n },\n);\n\nexport interface SidebarUpgradeChipProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n /**\n * Headline (clamped to two lines). In icon mode it becomes the tile's\n * accessible name and tooltip; in expanded mode the name comes from the\n * visible contents (title + description).\n */\n title: string;\n /** Supporting copy. Clamped to two lines; hidden in icon mode. */\n description?: string;\n /** Leading glyph. Defaults to an upgrade arrow. */\n icon?: ReactNode;\n}\n\nconst SidebarUpgradeChip = forwardRef<\n HTMLAnchorElement,\n SidebarUpgradeChipProps\n>(({ title, description, icon, className, ...rest }, ref) => {\n const { mode } = useSidebar();\n const isIconMode = mode === 'icon';\n\n const chip = (\n // aria-label only in icon mode (where the copy is hidden) — in\n // expanded mode the accessible name comes from the visible contents\n // so the description isn't excluded from it.\n <a\n ref={ref}\n aria-label={isIconMode ? title : undefined}\n className={upgradeChipClasses({ mode, className })}\n {...rest}\n >\n <span\n aria-hidden=\"true\"\n className={[\n 'ds:inline-flex ds:size-8 ds:shrink-0 ds:items-center ds:justify-center',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:bg-[var(--accent)] ds:text-[var(--accent-foreground)]',\n ].join(' ')}\n >\n {icon ?? <CircleArrowUp className=\"ds:size-4\" />}\n </span>\n {isIconMode ? null : (\n <>\n <span className=\"ds:flex-1 ds:min-w-0 ds:text-start\">\n {/* Wrap rather than truncate — an upsell headline cut to\n \"Unlock online pa…\" loses the pitch and there is no\n reveal affordance outside icon mode. */}\n <span className=\"ds:block ds:line-clamp-2 type-label\">{title}</span>\n {description ? (\n // Foreground (not muted) on the tinted surface — the gradient\n // stops leave muted text short of AA in both colour schemes.\n <span className=\"ds:block ds:line-clamp-2 type-meta\">\n {description}\n </span>\n ) : null}\n </span>\n {/* Trailing chevron marks the chip as navigation, not a banner. */}\n <ChevronRight\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:shrink-0 ds:rtl:-scale-x-100\"\n />\n </>\n )}\n </a>\n );\n\n if (!isIconMode) return chip;\n\n // Icon mode: tooltip on the chip itself (the focusable element), the\n // same recipe every other icon-mode affordance in this file uses.\n return (\n <RadixTooltip.Root>\n <RadixTooltip.Trigger asChild>{chip}</RadixTooltip.Trigger>\n <RadixTooltip.Portal>\n <RadixTooltip.Content\n side=\"right\"\n sideOffset={6}\n className={[\n 'ds:z-[var(--z-tooltip)] ds:max-w-[16rem]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:bg-[var(--foreground)] ds:text-[var(--background)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:py-[var(--spacing-xs)] ds:text-[length:var(--font-size-xs)]',\n 'ds:animate-in ds:fade-in ds:zoom-in-95 ds:motion-reduce:animate-none',\n ].join(' ')}\n >\n {title}\n <RadixTooltip.Arrow className=\"ds:fill-[var(--foreground)]\" />\n </RadixTooltip.Content>\n </RadixTooltip.Portal>\n </RadixTooltip.Root>\n );\n});\nSidebarUpgradeChip.displayName = 'SidebarUpgradeChip';\n\nexport {\n Sidebar,\n SidebarHeader,\n SidebarBody,\n SidebarFooter,\n SidebarSection,\n SidebarGroup,\n SidebarItem,\n SidebarItemIcon,\n SidebarItemLabel,\n SidebarItemBadge,\n SidebarWorkspaceSwitcher,\n SidebarPrimaryAction,\n SidebarFavorites,\n SidebarFavoriteItem,\n SidebarPinButton,\n SidebarProfilePill,\n SidebarCollapseTrigger,\n SidebarUpgradeChip,\n};\n"],"names":["__iconNode","PanelLeftClose","createLucideIcon","PanelLeftOpen","sidebarAgent","handle","SidebarContext","createContext","useSidebar","useContext","STORAGE_KEY","readStoredState","defaultMode","v","writeStoredState","value","railClasses","cva","Sidebar","forwardRef","state","defaultState","onStateChange","density","open","onOpenChange","ariaLabel","className","children","id","rest","ref","t","useTranslation","isControlled","internalState","setInternalState","useState","resolved","useEffect","transitionTo","useCallback","next","label","resolvedRef","useRef","agentHandle","useMemo","useAgentRegistration","jsx","RadixDialog","jsxs","X","RadixTooltip","SidebarHeader","mode","SidebarBody","SidebarFooter","sectionLabelClasses","sectionIconClasses","SidebarSection","icon","collapsible","defaultOpen","isIconMode","isAccordion","wrapperClasses","accordionValue","RadixAccordion","ChevronRight","AccordionContent","groupTriggerClasses","SidebarGroup","RadixCollapsible","itemClasses","SidebarItem","asChild","isActive","isPinned","onPinChange","pinLabel","Comp","Slot","showPin","anchor","body","SidebarPinButton","SidebarItemIcon","SidebarItemLabel","SidebarItemBadge","isIcon","workspaceSwitcherClasses","SidebarWorkspaceSwitcher","logo","name","showChevron","showLabel","Fragment","primaryActionClasses","SidebarPrimaryAction","shortcut","pinButtonClasses","onClick","accessibleLabel","event","Star","SidebarFavoritesContext","useFavoritesContext","SidebarFavorites","heading","emptyMessage","onReorder","resolvedHeading","childArray","count","hasChildren","dragSource","setDragSource","liveMessage","setLiveMessage","announceToggle","announce","message","favoriteRowClasses","dragHandleClasses","SidebarFavoriteItem","index","reorderLabel","favorites","isDropTarget","setIsDropTarget","canReorder","handleId","useId","moveFromTo","from","to","clamped","onHandleKeyDown","onDragStart","onDragEnd","onDragOver","onDragLeave","onDrop","source","isDragging","GripVertical","profilePillClasses","SidebarProfilePill","avatar","subtitle","subtitleLabel","accessibleSubtitle","collapseTriggerClasses","SidebarCollapseTrigger","isExpanded","button","upgradeChipClasses","SidebarUpgradeChip","title","description","chip","CircleArrowUp"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"task-card-CPyQ5AXC.js","sources":["../../src/components/task-card/task-card.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes, type ReactNode } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { CheckSquare, Square, AlertCircle, ChevronRight } from 'lucide-react';\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport type TaskStatus = 'open' | 'in-progress' | 'done';\nexport type TaskPriority = 'low' | 'normal' | 'high';\n\nexport interface TaskItem {\n /** Unique identifier for the task. */\n id: string;\n /** Title — single line, primary content. */\n title: string;\n /** Optional secondary line (e.g. \"Patient A · Due today\"). */\n description?: string;\n /**\n * Localised due-date hint (e.g. \"Due today\" / \"Tomorrow\"). Rendered as a\n * trailing eyebrow chip when set; consumers compute the bucket and pass\n * the localised string.\n */\n dueLabel?: string;\n /** Lifecycle state — drives the leading icon. */\n status?: TaskStatus;\n /** Priority — `high` colours the leading icon as `--destructive`. */\n priority?: TaskPriority;\n /** Optional deep link — when present the row is an anchor. */\n url?: string;\n}\n\nexport interface TaskCardProps\n extends\n Omit<HTMLAttributes<HTMLDivElement>, 'onClick' | 'role' | 'title'>,\n VariantProps<typeof taskCardVariants> {\n /** The task to render. */\n item: TaskItem;\n /** Visual density. */\n size?: 'sm' | 'md';\n /** Fires when the row is activated (click / Enter / Space). */\n onActivate?: (item: TaskItem) => void;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst taskCardVariants = cva(\n [\n 'ds:relative ds:flex ds:items-start ds:gap-[var(--spacing-sm)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:transition-colors',\n 'ds:motion-reduce:transition-none',\n 'ds:text-start ds:group',\n 'ds:border ds:border-[color:var(--card-border)] ds:[.theme-accessible_&]:border-2',\n 'ds:forced-colors:border ds:forced-colors:border-[CanvasText]',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:p-[var(--spacing-sm)]',\n md: 'ds:p-[var(--spacing-md)]',\n },\n interactive: {\n true: 'ds:hover:bg-[color:var(--muted)]/40 ds:cursor-pointer',\n false: '',\n },\n },\n defaultVariants: {\n size: 'sm',\n interactive: false,\n },\n },\n);\n\nconst stretchedLinkClass = [\n 'ds:focus-visible:outline-none',\n \"ds:after:content-[''] ds:after:absolute ds:after:inset-0 ds:after:rounded-[var(--radius-sm)]\",\n 'ds:after:pointer-events-auto',\n 'ds:focus-visible:after:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:after:outline-solid',\n 'ds:focus-visible:after:outline-[color:var(--ring)]',\n 'ds:focus-visible:after:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:after:outline-[CanvasText]',\n].join(' ');\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nexport function isSafeTaskUrl(url: string): boolean {\n return /^(https?:\\/\\/(?!\\/)|\\/(?!\\/)|#)/.test(url);\n}\n\nfunction StatusIcon({\n status,\n priority,\n}: {\n status?: TaskStatus;\n priority?: TaskPriority;\n}): ReactNode {\n const tone =\n priority === 'high'\n ? 'ds:text-[color:var(--destructive)]'\n : 'ds:text-[color:var(--muted-foreground)]';\n if (status === 'done') {\n return <CheckSquare aria-hidden=\"true\" className={`ds:size-4 ${tone}`} />;\n }\n if (priority === 'high') {\n return <AlertCircle aria-hidden=\"true\" className={`ds:size-4 ${tone}`} />;\n }\n return <Square aria-hidden=\"true\" className={`ds:size-4 ${tone}`} />;\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport const TaskCard = forwardRef<HTMLDivElement, TaskCardProps>(\n ({ item, size = 'sm', onActivate, className, ...rest }, ref) => {\n const { t } = useTranslation();\n const interactive = !!onActivate;\n const hasSafeUrl = !!item.url && isSafeTaskUrl(item.url);\n const ariaLabel = t('taskCard.itemLabel', {\n title: item.title,\n due: item.dueLabel ?? '',\n defaultValue: '{{title}}{{due, prepend, \" · \"}}',\n });\n\n const titleNode = (\n <span className=\"ds:flex-1 ds:min-w-0 ds:truncate type-body-sm ds:text-[color:var(--foreground)]\">\n {item.title}\n </span>\n );\n\n let activator: ReactNode;\n if (interactive && hasSafeUrl) {\n activator = (\n <a\n href={item.url}\n aria-label={ariaLabel}\n className={stretchedLinkClass + ' ds:contents'}\n onClick={(e) => {\n if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.shiftKey)\n return;\n onActivate?.(item);\n }}\n >\n {titleNode}\n </a>\n );\n } else if (interactive) {\n activator = (\n <button\n type=\"button\"\n aria-label={ariaLabel}\n className={\n stretchedLinkClass +\n ' ds:contents ds:bg-transparent ds:border-0 ds:p-0 ds:text-start'\n }\n onClick={() => onActivate?.(item)}\n >\n {titleNode}\n </button>\n );\n } else {\n activator = titleNode;\n }\n\n return (\n <div\n ref={ref}\n role=\"listitem\"\n data-component=\"task-card\"\n data-component-id={item.id}\n data-status={item.status ?? 'open'}\n data-priority={item.priority ?? 'normal'}\n className={taskCardVariants({ size, interactive, className })}\n {...rest}\n >\n <span className=\"ds:mt-[var(--spacing-2xs)] ds:shrink-0\">\n <StatusIcon status={item.status} priority={item.priority} />\n </span>\n\n <div className=\"ds:flex-1 ds:min-w-0 ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n {activator}\n {item.description ? (\n <span className=\"type-body-sm ds:text-[color:var(--muted-foreground)] ds:truncate\">\n {item.description}\n </span>\n ) : null}\n {item.dueLabel ? (\n <span className=\"type-eyebrow ds:text-[color:var(--muted-foreground)]\">\n {item.dueLabel}\n </span>\n ) : null}\n </div>\n\n {interactive ? (\n <ChevronRight\n aria-hidden=\"true\"\n className=\"ds:mt-[var(--spacing-2xs)] ds:size-4 ds:shrink-0 ds:text-[color:var(--muted-foreground)] ds:opacity-0 ds:transition-opacity ds:motion-reduce:transition-none ds:group-hover:opacity-100 ds:group-focus-within:opacity-100 ds:rtl:rotate-180\"\n />\n ) : null}\n </div>\n );\n },\n);\n\nTaskCard.displayName = 'TaskCard';\n"],"names":["taskCardVariants","cva","stretchedLinkClass","isSafeTaskUrl","url","StatusIcon","status","priority","tone","CheckSquare","AlertCircle","Square","TaskCard","forwardRef","item","size","onActivate","className","rest","ref","t","useTranslation","interactive","hasSafeUrl","ariaLabel","titleNode","jsx","activator","e","jsxs","ChevronRight"],"mappings":"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"}
|