@keyfunc/keybricks-ds 1.0.4 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (381) hide show
  1. package/DEPLOY.md +14 -5
  2. package/DESIGN.md +245 -59
  3. package/INTEGRATION.md +243 -49
  4. package/SKILL.md +13 -11
  5. package/_adherence.oxlintrc.json +183 -70
  6. package/_scripts/build-index.mjs +24 -4
  7. package/_scripts/build-tokens.mjs +5 -2
  8. package/assets/icons/icon-index.js +1 -1
  9. package/assets/icons/icon-index.json +1 -1
  10. package/components/_cards/accordion.card.html +2 -2
  11. package/components/_cards/action-chip.card.html +11 -9
  12. package/components/_cards/activity.card.html +3 -3
  13. package/components/_cards/alert.card.html +3 -3
  14. package/components/_cards/app-chrome.card.html +4 -4
  15. package/components/_cards/banner.card.html +1 -1
  16. package/components/_cards/breadcrumb.card.html +5 -5
  17. package/components/_cards/button-1-base.card.html +23 -26
  18. package/components/_cards/button-2-states.card.html +27 -25
  19. package/components/_cards/button-3-sizes-icons.card.html +20 -19
  20. package/components/_cards/button-4-group.card.html +14 -31
  21. package/components/_cards/canvas-zoom-controls.card.html +1 -1
  22. package/components/_cards/cards-indicators.card.html +2 -2
  23. package/components/_cards/charts-1-sparkline.card.html +5 -5
  24. package/components/_cards/charts-10-gauge.card.html +5 -5
  25. package/components/_cards/charts-11-funnel.card.html +3 -3
  26. package/components/_cards/charts-12-treemap.card.html +3 -3
  27. package/components/_cards/charts-14-radar.card.html +3 -3
  28. package/components/_cards/charts-15-distribution.card.html +2 -2
  29. package/components/_cards/charts-16-pareto.card.html +3 -3
  30. package/components/_cards/charts-17-candlestick.card.html +3 -3
  31. package/components/_cards/charts-18-sankey.card.html +3 -3
  32. package/components/_cards/charts-19-chord.card.html +3 -3
  33. package/components/_cards/charts-2-line.card.html +4 -4
  34. package/components/_cards/charts-20-sunburst.card.html +3 -3
  35. package/components/_cards/charts-21-worldmap.card.html +4 -4
  36. package/components/_cards/charts-22-gantt.card.html +3 -3
  37. package/components/_cards/charts-23-bar3d.card.html +3 -3
  38. package/components/_cards/charts-24-pie3d.card.html +3 -3
  39. package/components/_cards/charts-25-surface3d.card.html +3 -3
  40. package/components/_cards/charts-26-scatter3d.card.html +3 -3
  41. package/components/_cards/charts-27-ribbon3d.card.html +3 -3
  42. package/components/_cards/charts-3-bar.card.html +7 -7
  43. package/components/_cards/charts-4-barlist.card.html +3 -3
  44. package/components/_cards/charts-5-donut.card.html +4 -4
  45. package/components/_cards/charts-6-scatter.card.html +3 -3
  46. package/components/_cards/charts-7-heatmap.card.html +3 -3
  47. package/components/_cards/charts-8-waterfall.card.html +3 -3
  48. package/components/_cards/charts-9-bullet.card.html +3 -3
  49. package/components/_cards/charts-99-fullpage.card.html +5 -5
  50. package/components/_cards/checkbox.card.html +9 -6
  51. package/components/_cards/codeblock.card.html +2 -2
  52. package/components/_cards/combobox.card.html +6 -3
  53. package/components/_cards/context-menu.card.html +6 -3
  54. package/components/_cards/date-picker.card.html +10 -4
  55. package/components/_cards/diffvalue.card.html +3 -3
  56. package/components/_cards/divider.card.html +4 -4
  57. package/components/_cards/drawer.card.html +4 -4
  58. package/components/_cards/dropdown-menu.card.html +7 -7
  59. package/components/_cards/dropzone.card.html +5 -3
  60. package/components/_cards/empty-state.card.html +6 -6
  61. package/components/_cards/filter-bar.card.html +5 -5
  62. package/components/_cards/icon-button.card.html +14 -14
  63. package/components/_cards/icons-1-core.card.html +4 -4
  64. package/components/_cards/icons-2-feather.card.html +4 -4
  65. package/components/_cards/icons-3-unicons.card.html +4 -4
  66. package/components/_cards/input.card.html +5 -2
  67. package/components/_cards/kbd.card.html +2 -2
  68. package/components/_cards/keyvalue.card.html +2 -2
  69. package/components/_cards/listrow.card.html +2 -2
  70. package/components/_cards/loading.card.html +3 -3
  71. package/components/_cards/log-viewer.card.html +3 -3
  72. package/components/_cards/modal.card.html +9 -9
  73. package/components/_cards/multi-select.card.html +6 -3
  74. package/components/_cards/number-stepper.card.html +9 -5
  75. package/components/_cards/pagination.card.html +6 -3
  76. package/components/_cards/people.card.html +4 -4
  77. package/components/_cards/pipeline-node.card.html +8 -8
  78. package/components/_cards/pipeline-palette.card.html +5 -5
  79. package/components/_cards/radio.card.html +12 -7
  80. package/components/_cards/search.card.html +6 -3
  81. package/components/_cards/segmented-control.card.html +11 -10
  82. package/components/_cards/select.card.html +8 -4
  83. package/components/_cards/slider.card.html +2 -2
  84. package/components/_cards/smart-table.card.html +3 -3
  85. package/components/_cards/spreadsheet.card.html +3 -3
  86. package/components/_cards/stepper.card.html +3 -3
  87. package/components/_cards/table.card.html +165 -0
  88. package/components/_cards/tabs.card.html +6 -3
  89. package/components/_cards/tag.card.html +6 -3
  90. package/components/_cards/textarea.card.html +2 -2
  91. package/components/_cards/timeline.card.html +3 -3
  92. package/components/_cards/toast.card.html +10 -8
  93. package/components/_cards/toggles.card.html +15 -10
  94. package/components/_cards/tooltip.card.html +7 -7
  95. package/components/_cards/tree.card.html +3 -3
  96. package/components/_shared/card-kit.css +25 -0
  97. package/components/_shared/card-kit.js +50 -0
  98. package/components/_shared/src-buttons.js +1 -1
  99. package/components/_shared/src-charts.js +1 -1
  100. package/components/_shared/src-data.js +1 -1
  101. package/components/_shared/src-display.js +1 -1
  102. package/components/_shared/src-feedback.js +1 -1
  103. package/components/_shared/src-forms.js +1 -1
  104. package/components/_shared/src-icons.js +1 -1
  105. package/components/_shared/src-navigation.js +1 -1
  106. package/components/_shared/src-pipeline.js +1 -1
  107. package/components/_shared/src-tabs.js +1 -1
  108. package/components/_shared/view-source.js +3 -3
  109. package/components/_vue/index.mjs +16 -5
  110. package/components/buttons/ActionChip.d.ts +3 -1
  111. package/components/buttons/ActionChip.jsx +4 -4
  112. package/components/buttons/ActionChip.vue +4 -4
  113. package/components/buttons/Button.d.ts +5 -2
  114. package/components/buttons/Button.jsx +15 -18
  115. package/components/buttons/Button.vue +17 -18
  116. package/components/buttons/ButtonGroup.vue +1 -1
  117. package/components/buttons/IconButton.d.ts +2 -1
  118. package/components/buttons/IconButton.jsx +13 -9
  119. package/components/buttons/IconButton.vue +12 -9
  120. package/components/buttons/buttons.prompt.md +6 -5
  121. package/components/charts/Bar3D.jsx +2 -2
  122. package/components/charts/Bar3D.vue +3 -3
  123. package/components/charts/BarChart.jsx +4 -4
  124. package/components/charts/BarChart.vue +6 -6
  125. package/components/charts/BarList.jsx +4 -4
  126. package/components/charts/BarList.vue +4 -4
  127. package/components/charts/BoxPlot.jsx +1 -1
  128. package/components/charts/BoxPlot.vue +3 -3
  129. package/components/charts/BulletChart.jsx +6 -6
  130. package/components/charts/BulletChart.vue +6 -6
  131. package/components/charts/CandlestickChart.jsx +2 -2
  132. package/components/charts/CandlestickChart.vue +5 -5
  133. package/components/charts/ChartKit.jsx +8 -7
  134. package/components/charts/ChartLegend.vue +16 -0
  135. package/components/charts/ChartTooltip.vue +16 -0
  136. package/components/charts/ChordChart.jsx +2 -2
  137. package/components/charts/ChordChart.vue +3 -3
  138. package/components/charts/DonutChart.jsx +1 -1
  139. package/components/charts/DonutChart.vue +2 -2
  140. package/components/charts/FunnelChart.jsx +3 -3
  141. package/components/charts/FunnelChart.vue +4 -4
  142. package/components/charts/GanttChart.jsx +2 -2
  143. package/components/charts/GanttChart.vue +3 -3
  144. package/components/charts/GaugeChart.jsx +2 -2
  145. package/components/charts/GaugeChart.vue +2 -2
  146. package/components/charts/HeatmapChart.jsx +2 -2
  147. package/components/charts/HeatmapChart.vue +2 -2
  148. package/components/charts/Histogram.jsx +2 -2
  149. package/components/charts/Histogram.vue +4 -4
  150. package/components/charts/LineChart.jsx +1 -1
  151. package/components/charts/LineChart.vue +4 -4
  152. package/components/charts/ParetoChart.jsx +3 -3
  153. package/components/charts/ParetoChart.vue +5 -5
  154. package/components/charts/Pie3D.jsx +1 -1
  155. package/components/charts/Pie3D.vue +2 -2
  156. package/components/charts/PlotGrid.vue +18 -0
  157. package/components/charts/RadarChart.jsx +1 -1
  158. package/components/charts/RadarChart.vue +2 -2
  159. package/components/charts/Ribbon3D.jsx +2 -2
  160. package/components/charts/Ribbon3D.vue +3 -3
  161. package/components/charts/SankeyChart.jsx +2 -2
  162. package/components/charts/SankeyChart.vue +3 -3
  163. package/components/charts/Scatter3D.jsx +1 -1
  164. package/components/charts/Scatter3D.vue +2 -2
  165. package/components/charts/ScatterChart.jsx +3 -3
  166. package/components/charts/ScatterChart.vue +5 -5
  167. package/components/charts/Sparkline.jsx +1 -1
  168. package/components/charts/Sparkline.vue +1 -1
  169. package/components/charts/SunburstChart.jsx +1 -1
  170. package/components/charts/SunburstChart.vue +2 -2
  171. package/components/charts/Surface3D.jsx +2 -2
  172. package/components/charts/Surface3D.vue +3 -3
  173. package/components/charts/TreemapChart.jsx +2 -2
  174. package/components/charts/TreemapChart.vue +3 -3
  175. package/components/charts/WaterfallChart.jsx +2 -2
  176. package/components/charts/WaterfallChart.vue +6 -5
  177. package/components/charts/WorldMap.jsx +4 -4
  178. package/components/charts/WorldMap.vue +5 -5
  179. package/components/charts/XLabels.vue +11 -0
  180. package/components/data/CodeBlock.jsx +1 -1
  181. package/components/data/CodeBlock.vue +1 -1
  182. package/components/data/DiffValue.d.ts +1 -0
  183. package/components/data/DiffValue.jsx +1 -1
  184. package/components/data/DiffValue.vue +1 -1
  185. package/components/data/FilterBar.d.ts +2 -0
  186. package/components/data/FilterBar.jsx +10 -9
  187. package/components/data/FilterBar.vue +9 -8
  188. package/components/data/KeyValue.d.ts +1 -1
  189. package/components/data/KeyValue.jsx +4 -4
  190. package/components/data/KeyValue.vue +4 -4
  191. package/components/data/ListRow.jsx +2 -2
  192. package/components/data/ListRow.vue +2 -2
  193. package/components/data/Pagination.d.ts +5 -1
  194. package/components/data/Pagination.jsx +16 -12
  195. package/components/data/Pagination.vue +14 -9
  196. package/components/data/SmartTable.d.ts +4 -1
  197. package/components/data/SmartTable.jsx +16 -14
  198. package/components/data/SmartTable.vue +26 -23
  199. package/components/data/Spreadsheet.d.ts +2 -0
  200. package/components/data/Spreadsheet.jsx +16 -15
  201. package/components/data/Spreadsheet.vue +19 -18
  202. package/components/data/Table.d.ts +101 -0
  203. package/components/data/Table.jsx +223 -0
  204. package/components/data/Table.vue +153 -0
  205. package/components/data/data.prompt.md +3 -3
  206. package/components/display/Avatar.jsx +2 -2
  207. package/components/display/Avatar.vue +3 -2
  208. package/components/display/AvatarGroup.vue +3 -2
  209. package/components/display/Badge.d.ts +4 -1
  210. package/components/display/Badge.jsx +10 -5
  211. package/components/display/Badge.vue +1 -1
  212. package/components/display/Divider.vue +3 -3
  213. package/components/display/Donut.vue +3 -2
  214. package/components/display/IconTile.vue +10 -4
  215. package/components/display/Kbd.d.ts +1 -1
  216. package/components/display/Kbd.jsx +1 -1
  217. package/components/display/Kbd.vue +2 -2
  218. package/components/display/ProgressBar.jsx +1 -1
  219. package/components/display/ProgressBar.vue +1 -1
  220. package/components/display/StatCard.vue +1 -1
  221. package/components/display/Tag.d.ts +3 -1
  222. package/components/display/Tag.jsx +4 -4
  223. package/components/display/Tag.vue +4 -4
  224. package/components/feedback/Accordion.jsx +2 -2
  225. package/components/feedback/Accordion.vue +2 -2
  226. package/components/feedback/ActivityItem.d.ts +3 -1
  227. package/components/feedback/ActivityItem.jsx +6 -6
  228. package/components/feedback/ActivityItem.vue +5 -4
  229. package/components/feedback/Alert.jsx +4 -4
  230. package/components/feedback/Alert.vue +3 -3
  231. package/components/feedback/Banner.jsx +5 -5
  232. package/components/feedback/Banner.vue +5 -5
  233. package/components/feedback/ContextMenu.d.ts +3 -1
  234. package/components/feedback/ContextMenu.jsx +5 -5
  235. package/components/feedback/ContextMenu.vue +5 -5
  236. package/components/feedback/DotActivity.vue +3 -3
  237. package/components/feedback/Drawer.d.ts +2 -0
  238. package/components/feedback/Drawer.jsx +6 -6
  239. package/components/feedback/Drawer.vue +22 -15
  240. package/components/feedback/EmptyState.vue +2 -2
  241. package/components/feedback/LogViewer.vue +1 -1
  242. package/components/feedback/Modal.d.ts +2 -0
  243. package/components/feedback/Modal.jsx +12 -11
  244. package/components/feedback/Modal.vue +10 -8
  245. package/components/feedback/Skeleton.vue +2 -1
  246. package/components/feedback/Spinner.vue +2 -1
  247. package/components/feedback/Stepper.vue +1 -1
  248. package/components/feedback/Timeline.jsx +1 -1
  249. package/components/feedback/Timeline.vue +3 -3
  250. package/components/feedback/Toast.vue +4 -4
  251. package/components/feedback/ToastStack.vue +11 -0
  252. package/components/feedback/Tooltip.vue +19 -0
  253. package/components/feedback/feedback.prompt.md +4 -4
  254. package/components/forms/Checkbox.d.ts +3 -2
  255. package/components/forms/Checkbox.jsx +7 -7
  256. package/components/forms/Checkbox.vue +8 -8
  257. package/components/forms/Combobox.d.ts +2 -0
  258. package/components/forms/Combobox.jsx +12 -10
  259. package/components/forms/Combobox.vue +11 -10
  260. package/components/forms/DatePicker.d.ts +4 -0
  261. package/components/forms/DatePicker.jsx +16 -12
  262. package/components/forms/DatePicker.vue +15 -11
  263. package/components/forms/Dropzone.jsx +2 -2
  264. package/components/forms/Dropzone.vue +5 -5
  265. package/components/forms/Field.d.ts +5 -1
  266. package/components/forms/Field.jsx +4 -4
  267. package/components/forms/Field.vue +4 -4
  268. package/components/forms/Input.d.ts +5 -1
  269. package/components/forms/Input.jsx +8 -8
  270. package/components/forms/Input.vue +3 -3
  271. package/components/forms/MultiSelect.d.ts +2 -0
  272. package/components/forms/MultiSelect.jsx +13 -11
  273. package/components/forms/MultiSelect.vue +12 -11
  274. package/components/forms/NumberStepper.d.ts +3 -1
  275. package/components/forms/NumberStepper.jsx +7 -7
  276. package/components/forms/NumberStepper.vue +8 -7
  277. package/components/forms/Radio.d.ts +5 -3
  278. package/components/forms/Radio.jsx +13 -15
  279. package/components/forms/Radio.vue +9 -10
  280. package/components/forms/RadioGroup.vue +5 -5
  281. package/components/forms/SearchInput.d.ts +3 -1
  282. package/components/forms/SearchInput.jsx +6 -6
  283. package/components/forms/SearchInput.vue +7 -6
  284. package/components/forms/Select.d.ts +3 -2
  285. package/components/forms/Select.jsx +6 -7
  286. package/components/forms/Select.vue +6 -6
  287. package/components/forms/Slider.jsx +3 -3
  288. package/components/forms/Slider.vue +3 -3
  289. package/components/forms/Switch.d.ts +2 -2
  290. package/components/forms/Switch.jsx +20 -22
  291. package/components/forms/Switch.vue +22 -18
  292. package/components/forms/Textarea.vue +5 -5
  293. package/components/forms/forms.prompt.md +1 -1
  294. package/components/forms/input-base.js +2 -1
  295. package/components/icons/Icon.jsx +17 -1
  296. package/components/icons/Icon.prompt.md +2 -0
  297. package/components/icons/Icon.vue +1 -1
  298. package/components/icons/icon-paths.js +15 -0
  299. package/components/index.d.ts +1 -2
  300. package/components/index.js +4 -5
  301. package/components/navigation/Breadcrumb.jsx +6 -10
  302. package/components/navigation/Breadcrumb.vue +6 -12
  303. package/components/navigation/DocTree.jsx +3 -3
  304. package/components/navigation/DocTree.vue +3 -3
  305. package/components/navigation/PageHeading.vue +1 -1
  306. package/components/navigation/PageToolbar.vue +7 -6
  307. package/components/navigation/Sidebar.jsx +4 -23
  308. package/components/navigation/Sidebar.vue +5 -10
  309. package/components/navigation/ThemeToggle.vue +2 -1
  310. package/components/navigation/TopBar.d.ts +3 -1
  311. package/components/navigation/TopBar.jsx +6 -6
  312. package/components/navigation/Tree.jsx +5 -5
  313. package/components/navigation/Tree.vue +13 -8
  314. package/components/navigation/nav-model.js +23 -0
  315. package/components/navigation/theme-store.js +9 -0
  316. package/components/pipeline/ConfigPanel.d.ts +2 -0
  317. package/components/pipeline/ConfigPanel.jsx +9 -9
  318. package/components/pipeline/ConfigPanel.vue +9 -9
  319. package/components/pipeline/DataPreview.d.ts +3 -1
  320. package/components/pipeline/DataPreview.jsx +7 -7
  321. package/components/pipeline/DataPreview.vue +7 -7
  322. package/components/pipeline/NodeCard.jsx +3 -3
  323. package/components/pipeline/NodeCard.vue +3 -3
  324. package/components/pipeline/PaletteItem.vue +2 -2
  325. package/components/pipeline/PaletteListItem.vue +1 -1
  326. package/components/pipeline/PalettePanel.jsx +2 -2
  327. package/components/pipeline/PalettePanel.vue +1 -1
  328. package/components/pipeline/Port.vue +15 -0
  329. package/components/pipeline/PortLabel.vue +15 -0
  330. package/components/pipeline/ZoomControls.vue +1 -1
  331. package/components/pipeline/port-skin.js +13 -0
  332. package/components/px.js +4 -0
  333. package/components/tabs/PanelTabs.vue +5 -4
  334. package/components/tabs/PillTabs.vue +5 -4
  335. package/components/tabs/SegmentedControl.d.ts +2 -2
  336. package/components/tabs/SegmentedControl.jsx +7 -7
  337. package/components/tabs/SegmentedControl.vue +7 -7
  338. package/components/tabs/Tabs.d.ts +5 -3
  339. package/components/tabs/Tabs.jsx +15 -15
  340. package/components/tabs/Tabs.vue +5 -5
  341. package/components/tabs/ViewToggle.d.ts +3 -1
  342. package/components/tabs/ViewToggle.jsx +5 -5
  343. package/components/tabs/ViewToggle.vue +5 -5
  344. package/components/tabs/tabs.prompt.md +1 -1
  345. package/keybricks.css +4 -0
  346. package/package.json +6 -3
  347. package/readme.md +91 -122
  348. package/readme.zh-CN.md +121 -0
  349. package/tokens/alpha.css +3 -1
  350. package/tokens/charts.css +20 -17
  351. package/tokens/colors.css +3 -3
  352. package/tokens/dark.css +3 -3
  353. package/tokens/hover.css +32 -0
  354. package/tokens/interaction.css +3 -1
  355. package/tokens/layout.css +31 -7
  356. package/tokens/tokens.d.ts +58 -0
  357. package/tokens/tokens.js +179 -92
  358. package/tokens/tokens.json +327 -114
  359. package/tokens/typography.css +45 -15
  360. package/components/_cards/brand-visual.card.html +0 -43
  361. package/components/_cards/datatable.card.html +0 -48
  362. package/components/_shared/src-brand.js +0 -1
  363. package/components/brand/BrandVisual.d.ts +0 -17
  364. package/components/brand/BrandVisual.jsx +0 -29
  365. package/components/brand/BrandVisual.vue +0 -34
  366. package/components/brand/_dir.card.html +0 -13
  367. package/components/brand/brandMotifs.js +0 -210
  368. package/components/buttons/_dir.card.html +0 -13
  369. package/components/charts/ChartKit.vue +0 -47
  370. package/components/charts/_dir.card.html +0 -7
  371. package/components/data/DataTable.d.ts +0 -28
  372. package/components/data/DataTable.jsx +0 -32
  373. package/components/data/DataTable.vue +0 -25
  374. package/components/data/_dir.card.html +0 -13
  375. package/components/display/_dir.card.html +0 -13
  376. package/components/feedback/_dir.card.html +0 -13
  377. package/components/forms/_dir.card.html +0 -13
  378. package/components/icons/_dir.card.html +0 -13
  379. package/components/navigation/_dir.card.html +0 -13
  380. package/components/pipeline/_dir.card.html +0 -13
  381. package/components/tabs/_dir.card.html +0 -13
@@ -47,7 +47,7 @@ function toggle(name){
47
47
  <path v-for="(d,i) in g.rings" :key="'r'+i" :d="d" fill="none" stroke="var(--chart-grid)" stroke-width="1"/>
48
48
  <g v-for="(sp,i) in g.spokes" :key="sp.label">
49
49
  <line :x1="g.cx" :y1="g.cy" :x2="sp.x" :y2="sp.y" :stroke="hover===i?'var(--chart-guide)':'var(--chart-axis)'" stroke-width="1"/>
50
- <text :x="sp.lx" :y="sp.ly+3" :text-anchor="sp.anchor" :style="{fontFamily:'var(--font-sans)',fontSize:'10px',fill:hover===i?'var(--text-heading)':'var(--chart-label)'}">{{ sp.label }}</text>
50
+ <text :x="sp.lx" :y="sp.ly+3" :text-anchor="sp.anchor" :style="{fontFamily:'var(--font-sans)',fontSize:'var(--text-2xs)',fill:hover===i?'var(--text-heading)':'var(--chart-label)'}">{{ sp.label }}</text>
51
51
  </g>
52
52
  <g v-for="sh in g.shapes" :key="sh.s.name">
53
53
  <path :d="sh.d" :fill="sh.color" fill-opacity="0.14" :stroke="sh.color" stroke-width="1.5" stroke-linejoin="round"/>
@@ -59,7 +59,7 @@ function toggle(name){
59
59
  <div v-for="sh in g.shapes" :key="sh.s.name" style="display:flex;align-items:center;gap:6px">
60
60
  <span :style="{width:'7px',height:'7px',borderRadius:'2px',background:sh.color}"/>
61
61
  <span style="font-family:var(--font-sans);font-size:var(--text-xs);color:var(--text-secondary)">{{ sh.s.name }}</span>
62
- <span style="font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-heading);margin-left:auto;padding-left:10px">{{ valueFormat(sh.s.values[hover]) }}</span>
62
+ <span style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-xs);color:var(--text-heading);margin-left:auto;padding-left:10px">{{ valueFormat(sh.s.values[hover]) }}</span>
63
63
  </div>
64
64
  </div>
65
65
  <div v-if="legend && series.length>1" style="display:flex;flex-wrap:wrap;gap:4px 14px;padding-top:6px;line-height:normal">
@@ -47,7 +47,7 @@ export function Ribbon3D({ series = [], xLabels = [], width = 460, height = 300,
47
47
  {vTicks.map((t, i) => (
48
48
  <g key={"vt" + i}>
49
49
  <line x1={t.p.x - 4} y1={t.p.y} x2={t.p.x} y2={t.p.y} stroke="var(--chart-guide)" strokeWidth="1" />
50
- <text x={t.p.x - 7} y={t.p.y + 3} textAnchor="end" style={{ fontFamily: "var(--font-mono)", fontSize: 9, fill: "var(--chart-label)" }}>{t.v}</text>
50
+ <text x={t.p.x - 7} y={t.p.y + 3} textAnchor="end" style={{ fontFamily: "var(--font-sans)", fontVariantNumeric: "tabular-nums", fontSize: "var(--text-2xs-mono)", fill: "var(--chart-label)" }}>{t.v}</text>
51
51
  </g>
52
52
  ))}
53
53
  {xLabels.map((lb, i) => {
@@ -57,7 +57,7 @@ export function Ribbon3D({ series = [], xLabels = [], width = 460, height = 300,
57
57
  const p0 = P(i / (n - 1) - 0.5, -0.45, zE);
58
58
  const ctr = P(0, -0.45, 0);
59
59
  const dx = p0.x - ctr.x, dy = p0.y - ctr.y, len = Math.hypot(dx, dy) || 1;
60
- return <text key={"x" + i} x={p0.x + (dx / len) * 14} y={p0.y + (dy / len) * 14 + 3} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontSize: 10, fill: "var(--chart-label)" }}>{lb}</text>;
60
+ return <text key={"x" + i} x={p0.x + (dx / len) * 14} y={p0.y + (dy / len) * 14 + 3} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{lb}</text>;
61
61
  })}
62
62
  {rows.map((r) => (
63
63
  <g key={r.s.name} opacity={hover == null || hover === r.si ? 1 : 0.4}
@@ -55,9 +55,9 @@ const g = computed(() => {
55
55
  <line :x1="g.vAxis[0].x" :y1="g.vAxis[0].y" :x2="g.vAxis[1].x" :y2="g.vAxis[1].y" stroke="var(--chart-guide)" stroke-width="1"/>
56
56
  <g v-for="(t,i) in g.vTicks" :key="'vt'+i">
57
57
  <line :x1="t.p.x-4" :y1="t.p.y" :x2="t.p.x" :y2="t.p.y" stroke="var(--chart-guide)" stroke-width="1"/>
58
- <text :x="t.p.x-7" :y="t.p.y+3" text-anchor="end" style="font-family:var(--font-mono);font-size:9px;fill:var(--chart-label)">{{ t.v }}</text>
58
+ <text :x="t.p.x-7" :y="t.p.y+3" text-anchor="end" style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-2xs-mono);fill:var(--chart-label)">{{ t.v }}</text>
59
59
  </g>
60
- <text v-for="(l,i) in g.labels" :key="'x'+i" :x="l.x" :y="l.y" text-anchor="middle" style="font-family:var(--font-sans);font-size:10px;fill:var(--chart-label)">{{ l.lb }}</text>
60
+ <text v-for="(l,i) in g.labels" :key="'x'+i" :x="l.x" :y="l.y" text-anchor="middle" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">{{ l.lb }}</text>
61
61
  <g v-for="r in g.rows" :key="r.s.name" :opacity="hover==null||hover===r.si?1:0.4"
62
62
  @mouseenter="interactive && (hover=r.si)" @mouseleave="interactive && (hover=null)"
63
63
  style="transition:opacity var(--dur-fast) var(--ease-out)">
@@ -66,7 +66,7 @@ const g = computed(() => {
66
66
  </svg>
67
67
  <div v-if="hover!=null && interactive" :style="{position:'absolute',left:(width/2)+'px',top:(height*0.28)+'px',transform:'translate(10px,-50%)',pointerEvents:'none',zIndex:5,background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-menu)',padding:'7px 10px',lineHeight:'normal',whiteSpace:'nowrap'}">
68
68
  <div style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--text-muted);padding-bottom:3px">{{ series[hover].name }}</div>
69
- <div style="font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-heading)">peak {{ valueFormat(Math.max(...series[hover].values)) }} · latest {{ valueFormat(series[hover].values[series[hover].values.length-1]) }}</div>
69
+ <div style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-xs);color:var(--text-heading)">peak {{ valueFormat(Math.max(...series[hover].values)) }} · latest {{ valueFormat(series[hover].values[series[hover].values.length-1]) }}</div>
70
70
  </div>
71
71
  <div style="display:flex;gap:14px;padding-top:6px;line-height:normal">
72
72
  <span v-for="(s,i) in series" :key="s.name" @mouseenter="interactive && (hover=i)" @mouseleave="interactive && (hover=null)"
@@ -45,9 +45,9 @@ export function SankeyChart({ nodes = [], links = [], width = 620, height = 320,
45
45
  style={{ cursor: interactive ? "default" : undefined }}>
46
46
  <rect x={n.x} y={n.y} width={n.w} height={n.h} rx="2" fill={c} opacity={hover == null || (hover.kind === "node" && hover.id === n.id) ? 1 : 0.55} />
47
47
  <text x={rightSide ? n.x + n.w + 6 : n.x + n.w + 6} y={n.y + n.h / 2 + 3.5}
48
- style={{ fontFamily: "var(--font-sans)", fontSize: 11, fill: "var(--text-heading)" }}>{n.label}</text>
48
+ style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", fill: "var(--text-heading)" }}>{n.label}</text>
49
49
  <text x={n.x + n.w + 6} y={n.y + n.h / 2 + 15}
50
- style={{ fontFamily: "var(--font-mono)", fontSize: 9.5, fill: "var(--chart-label)" }}>{valueFormat(n.value)}</text>
50
+ style={{ fontFamily: "var(--font-sans)", fontVariantNumeric: "tabular-nums", fontSize: "var(--text-2xs-mono)", fill: "var(--chart-label)" }}>{valueFormat(n.value)}</text>
51
51
  </g>
52
52
  );
53
53
  })}
@@ -40,14 +40,14 @@ const tip = computed(()=>{
40
40
  style="transition:opacity var(--dur-fast) var(--ease-out)"/>
41
41
  <g v-for="n in g.laid.nodes" :key="n.id" @mouseenter="interactive && (hover={kind:'node',id:n.id})" @mouseleave="interactive && (hover=null)">
42
42
  <rect :x="n.x" :y="n.y" :width="n.w" :height="n.h" rx="2" :fill="g.color(n)" :opacity="hover==null||(hover.kind==='node'&&hover.id===n.id)?1:0.55"/>
43
- <text :x="n.x+n.w+6" :y="n.y+n.h/2+3.5" style="font-family:var(--font-sans);font-size:11px;fill:var(--text-heading)">{{ n.label }}</text>
44
- <text :x="n.x+n.w+6" :y="n.y+n.h/2+15" style="font-family:var(--font-mono);font-size:9.5px;fill:var(--chart-label)">{{ valueFormat(n.value) }}</text>
43
+ <text :x="n.x+n.w+6" :y="n.y+n.h/2+3.5" style="font-family:var(--font-sans);font-size:var(--text-xs);fill:var(--text-heading)">{{ n.label }}</text>
44
+ <text :x="n.x+n.w+6" :y="n.y+n.h/2+15" style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-2xs-mono);fill:var(--chart-label)">{{ valueFormat(n.value) }}</text>
45
45
  </g>
46
46
  </g>
47
47
  </svg>
48
48
  <div v-if="tip && interactive" :style="{position:'absolute',left:tip.x+'px',top:tip.y+'px',transform:tip.x>width*0.6?'translate(calc(-100% - 10px),-50%)':'translate(10px,-50%)',pointerEvents:'none',zIndex:5,background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-menu)',padding:'7px 10px',lineHeight:'normal',whiteSpace:'nowrap'}">
49
49
  <div style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--text-muted);padding-bottom:3px">{{ tip.title }}</div>
50
- <div style="font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-heading)">{{ tip.value }}</div>
50
+ <div style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-xs);color:var(--text-heading)">{{ tip.value }}</div>
51
51
  </div>
52
52
  </div>
53
53
  </template>
@@ -40,7 +40,7 @@ export function Scatter3D({ points = [], width = 420, height = 300, yaw: yaw0 =
40
40
  {edges.map(([a, b], i) => <line key={i} x1={a.x} y1={a.y} x2={b.x} y2={b.y} stroke="var(--chart-axis)" strokeWidth="1" />)}
41
41
  {axes3.map((ax, i) => <line key={"ae" + i} x1={ax.a.x} y1={ax.a.y} x2={ax.b.x} y2={ax.b.y} stroke="var(--chart-guide)" strokeWidth="1" />)}
42
42
  {axes3.map((ax, i) => (
43
- <text key={"at" + i} x={ax.nx} y={ax.ny + 3} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontSize: 10, fill: "var(--text-secondary)" }}>{ax.name}</text>
43
+ <text key={"at" + i} x={ax.nx} y={ax.ny + 3} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--text-secondary)" }}>{ax.name}</text>
44
44
  ))}
45
45
  {dots.map((d) => (
46
46
  <circle key={d.i} cx={d.x} cy={d.y} r={r * (1.18 - (d.depth + 0.75) * 0.35) * (hover === d.i ? 1.5 : 1)}
@@ -38,7 +38,7 @@ const g = computed(() => {
38
38
  role="img" :style="{cursor:interactive?'grab':'default',touchAction:'none'}">
39
39
  <line v-for="(e,i) in g.edges" :key="'e'+i" :x1="e[0].x" :y1="e[0].y" :x2="e[1].x" :y2="e[1].y" stroke="var(--chart-axis)" stroke-width="1"/>
40
40
  <line v-for="(ax,i) in g.axes3" :key="'ae'+i" :x1="ax.a.x" :y1="ax.a.y" :x2="ax.b.x" :y2="ax.b.y" stroke="var(--chart-guide)" stroke-width="1"/>
41
- <text v-for="(ax,i) in g.axes3" :key="'at'+i" :x="ax.nx" :y="ax.ny+3" text-anchor="middle" style="font-family:var(--font-sans);font-size:10px;fill:var(--text-secondary)">{{ ax.name }}</text>
41
+ <text v-for="(ax,i) in g.axes3" :key="'at'+i" :x="ax.nx" :y="ax.ny+3" text-anchor="middle" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--text-secondary)">{{ ax.name }}</text>
42
42
  <circle v-for="d in g.dots" :key="d.i" :cx="d.x" :cy="d.y"
43
43
  :r="r*(1.18-(d.depth+0.75)*0.35)*(hover===d.i?1.5:1)" :fill="d.color"
44
44
  :opacity="hover===d.i ? 1 : (0.85-(d.depth+0.75)*0.28)*(hover==null?1:0.45)"
@@ -47,7 +47,7 @@ const g = computed(() => {
47
47
  </svg>
48
48
  <div v-if="hover!=null && interactive" :style="{position:'absolute',left:g.dots.find(d=>d.i===hover).x+'px',top:g.dots.find(d=>d.i===hover).y+'px',transform:g.dots.find(d=>d.i===hover).x>width*0.6?'translate(calc(-100% - 10px),-50%)':'translate(10px,-50%)',pointerEvents:'none',zIndex:5,background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-menu)',padding:'7px 10px',lineHeight:'normal',whiteSpace:'nowrap'}">
49
49
  <div style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--text-muted);padding-bottom:3px">{{ points[hover].label || points[hover].series }}</div>
50
- <div style="font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-heading)">{{ xLabel }} {{ valueFormat(points[hover].x) }} · {{ yLabel }} {{ valueFormat(points[hover].y) }} · {{ zLabel }} {{ valueFormat(points[hover].z) }}</div>
50
+ <div style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-xs);color:var(--text-heading)">{{ xLabel }} {{ valueFormat(points[hover].x) }} · {{ yLabel }} {{ valueFormat(points[hover].y) }} · {{ zLabel }} {{ valueFormat(points[hover].z) }}</div>
51
51
  </div>
52
52
  <div v-if="legend && g.names.length>1" style="display:flex;gap:14px;padding-top:6px;line-height:normal">
53
53
  <span v-for="(nm,i) in g.names" :key="nm" style="display:inline-flex;align-items:center;gap:6px">
@@ -33,9 +33,9 @@ export function ScatterChart({ points = [], width = 560, height = 260, xFormat =
33
33
  <svg width={width} height={height} onMouseMove={move} onMouseLeave={() => setHover(null)} role="img">
34
34
  {axes ? <g>
35
35
  <PlotGrid w={width} h={height} pad={pad} ticks={ty.ticks} sy={sy} xLabels={[]} sxLabel={() => 0} yFormat={yFormat} />
36
- {tx.ticks.map((t) => <text key={t} x={sx(t)} y={height - pad.b + 16} textAnchor="middle" style={{ fontFamily: "var(--font-mono)", fontSize: 10, fill: "var(--chart-label)" }}>{xFormat(t)}</text>)}
37
- {xLabel ? <text x={width - pad.r} y={height - 2} textAnchor="end" style={{ fontFamily: "var(--font-sans)", fontSize: 10, fill: "var(--chart-label)" }}>{xLabel}</text> : null}
38
- {yLabel ? <text x={pad.l} y={pad.t - 1} style={{ fontFamily: "var(--font-sans)", fontSize: 10, fill: "var(--chart-label)" }}>{yLabel}</text> : null}
36
+ {tx.ticks.map((t) => <text key={t} x={sx(t)} y={height - pad.b + 16} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontVariantNumeric: "tabular-nums", fontSize: "var(--text-2xs-mono)", fill: "var(--chart-label)" }}>{xFormat(t)}</text>)}
37
+ {xLabel ? <text x={width - pad.r} y={height - 2} textAnchor="end" style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{xLabel}</text> : null}
38
+ {yLabel ? <text x={pad.l} y={pad.t - 1} style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{yLabel}</text> : null}
39
39
  </g> : null}
40
40
  {points.map((p, i) => (
41
41
  <circle key={i} cx={sx(p.x)} cy={sy(p.y)} r={sr(p.r != null ? p.r : 1)} fill={colorOf(p)}
@@ -33,11 +33,11 @@ function move(e){
33
33
  <template v-if="axes">
34
34
  <g v-for="t in g.ty.ticks" :key="t">
35
35
  <line :x1="g.pad.l" :x2="width-g.pad.r" :y1="g.sy(t)" :y2="g.sy(t)" :stroke="t===0?'var(--chart-axis)':'var(--chart-grid)'" stroke-width="1"/>
36
- <text :x="g.pad.l-8" :y="g.sy(t)+3" text-anchor="end" style="font-family:var(--font-mono);font-size:10px;fill:var(--chart-label)">{{ yFormat(t) }}</text>
36
+ <text :x="g.pad.l-8" :y="g.sy(t)+3" text-anchor="end" style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-2xs-mono);fill:var(--chart-label)">{{ yFormat(t) }}</text>
37
37
  </g>
38
- <text v-for="t in g.tx.ticks" :key="'x'+t" :x="g.sx(t)" :y="height-g.pad.b+16" text-anchor="middle" style="font-family:var(--font-mono);font-size:10px;fill:var(--chart-label)">{{ xFormat(t) }}</text>
39
- <text v-if="xLabel" :x="width-g.pad.r" :y="height-2" text-anchor="end" style="font-family:var(--font-sans);font-size:10px;fill:var(--chart-label)">{{ xLabel }}</text>
40
- <text v-if="yLabel" :x="g.pad.l" :y="g.pad.t-1" style="font-family:var(--font-sans);font-size:10px;fill:var(--chart-label)">{{ yLabel }}</text>
38
+ <text v-for="t in g.tx.ticks" :key="'x'+t" :x="g.sx(t)" :y="height-g.pad.b+16" text-anchor="middle" style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-2xs-mono);fill:var(--chart-label)">{{ xFormat(t) }}</text>
39
+ <text v-if="xLabel" :x="width-g.pad.r" :y="height-2" text-anchor="end" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">{{ xLabel }}</text>
40
+ <text v-if="yLabel" :x="g.pad.l" :y="g.pad.t-1" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">{{ yLabel }}</text>
41
41
  </template>
42
42
  <circle v-for="d in g.dots" :key="d.i" :cx="d.cx" :cy="d.cy" :r="d.r" :fill="d.color"
43
43
  :opacity="hover==null?.55:hover===d.i?.9:.2" :stroke="hover===d.i?'var(--bg-surface)':'none'" stroke-width="1.5"
@@ -45,7 +45,7 @@ function move(e){
45
45
  </svg>
46
46
  <div v-if="hover!=null && interactive" :style="{position:'absolute',left:g.dots[hover].cx+'px',top:g.dots[hover].cy+'px',transform:g.dots[hover].cx>width*0.62?'translate(calc(-100% - 10px),-50%)':'translate(10px,-50%)',pointerEvents:'none',zIndex:5,background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-menu)',padding:'7px 10px',lineHeight:'normal'}">
47
47
  <div style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--text-muted);padding-bottom:4px;white-space:nowrap">{{ points[hover].label || points[hover].series }}</div>
48
- <div style="font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-heading);white-space:nowrap">{{ (xLabel||'x')+' '+xFormat(points[hover].x) }} · {{ (yLabel||'y')+' '+yFormat(points[hover].y) }}</div>
48
+ <div style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-xs);color:var(--text-heading);white-space:nowrap">{{ (xLabel||'x')+' '+xFormat(points[hover].x) }} · {{ (yLabel||'y')+' '+yFormat(points[hover].y) }}</div>
49
49
  </div>
50
50
  <div v-if="legend && g.names.length>1" style="display:flex;gap:14px;padding-top:8px;line-height:normal">
51
51
  <span v-for="(nm,i) in g.names" :key="nm" style="display:inline-flex;align-items:center;gap:6px">
@@ -28,7 +28,7 @@ export function Sparkline({ values = [], mode = "line", curve = "linear", tone =
28
28
  setHover(Math.max(0, Math.min(values.length - 1, i)));
29
29
  };
30
30
  const chip = hover != null && interactive ? (
31
- <span style={{ position: "absolute", left: Math.min(Math.max(sx(hover), 18), width - 18), top: -4, transform: "translate(-50%,-100%)", pointerEvents: "none", whiteSpace: "nowrap", background: "var(--bg-surface)", border: "1px solid var(--border-card)", borderRadius: "var(--radius-sm)", boxShadow: "var(--shadow-menu)", padding: "2px 6px", fontFamily: "var(--font-mono)", fontSize: 10, lineHeight: "14px", color: "var(--text-heading)", zIndex: 5 }}>
31
+ <span style={{ position: "absolute", left: Math.min(Math.max(sx(hover), 18), width - 18), top: -4, transform: "translate(-50%,-100%)", pointerEvents: "none", whiteSpace: "nowrap", background: "var(--bg-surface)", border: "1px solid var(--border-card)", borderRadius: "var(--radius-sm)", boxShadow: "var(--shadow-menu)", padding: "2px 6px", fontFamily: "var(--font-sans)", fontVariantNumeric: "tabular-nums", fontSize: "var(--text-2xs-mono)", lineHeight: "14px", color: "var(--text-heading)", zIndex: 5 }}>
32
32
  {labels && labels[hover] ? <span style={{ color: "var(--text-muted)", paddingRight: 5 }}>{labels[hover]}</span> : null}
33
33
  {valueFormat(values[hover])}
34
34
  </span>
@@ -47,7 +47,7 @@ const g = computed(() => {
47
47
  <circle v-if="hover!=null && interactive" :cx="g.sx(hover)" :cy="g.sy(values[hover])" :r="strokeWidth+1.4" :fill="g.color" stroke="var(--bg-surface)" stroke-width="1.5"/>
48
48
  </template>
49
49
  </svg>
50
- <span v-if="hover!=null && interactive" :style="{position:'absolute',left:Math.min(Math.max(g.sx(hover),18),width-18)+'px',top:'-4px',transform:'translate(-50%,-100%)',pointerEvents:'none',whiteSpace:'nowrap',background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-sm)',boxShadow:'var(--shadow-menu)',padding:'2px 6px',fontFamily:'var(--font-mono)',fontSize:'10px',lineHeight:'14px',color:'var(--text-heading)',zIndex:5}">
50
+ <span v-if="hover!=null && interactive" :style="{position:'absolute',left:Math.min(Math.max(g.sx(hover),18),width-18)+'px',top:'-4px',transform:'translate(-50%,-100%)',pointerEvents:'none',whiteSpace:'nowrap',background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-sm)',boxShadow:'var(--shadow-menu)',padding:'2px 6px',fontFamily: 'var(--font-sans)', fontVariantNumeric: 'tabular-nums',fontSize:'var(--text-2xs-mono)',lineHeight:'14px',color:'var(--text-heading)',zIndex:5}">
51
51
  <span v-if="labels && labels[hover]" style="color:var(--text-muted);padding-right:5px">{{ labels[hover] }}</span>{{ valueFormat(values[hover]) }}
52
52
  </span>
53
53
  </span>
@@ -49,7 +49,7 @@ export function SunburstChart({ data, size = 320, ringWidth, valueFormat = fmtNu
49
49
  <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", color: "var(--text-muted)", maxWidth: rInner * 1.7, textAlign: "center", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
50
50
  {zoom.length ? focus.label : focus.label || "Total"}
51
51
  </span>
52
- {zoom.length ? <span style={{ fontFamily: "var(--font-sans)", fontSize: 9, color: "var(--action-primary)" }}>↑ back</span> : null}
52
+ {zoom.length ? <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", color: "var(--action-primary)" }}>↑ back</span> : null}
53
53
  </div>
54
54
  {h && interactive ? (
55
55
  <ChartTooltip x={tipAt[0]} y={tipAt[1]} flip={tipAt[0] > size * 0.55} title={h.node.label}
@@ -49,11 +49,11 @@ const tip = computed(()=>{
49
49
  <div style="position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;pointer-events:none;line-height:normal;gap:2px">
50
50
  <span :style="{fontFamily:'var(--font-sans)',fontWeight:'var(--weight-light)',fontSize:Math.round(size/13)+'px',color:'var(--text-heading)'}">{{ valueFormat(g.focus.value) }}</span>
51
51
  <span :style="{fontFamily:'var(--font-sans)',fontSize:'var(--text-2xs)',color:'var(--text-muted)',maxWidth:g.rInner*1.7+'px',textAlign:'center',whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}">{{ g.focus.label || 'Total' }}</span>
52
- <span v-if="zoom.length" style="font-family:var(--font-sans);font-size:9px;color:var(--action-primary)">↑ back</span>
52
+ <span v-if="zoom.length" style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--action-primary)">↑ back</span>
53
53
  </div>
54
54
  <div v-if="tip && interactive" :style="{position:'absolute',left:tip.x+'px',top:tip.y+'px',transform:tip.x>size*0.55?'translate(calc(-100% - 10px),-50%)':'translate(10px,-50%)',pointerEvents:'none',zIndex:5,background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-menu)',padding:'7px 10px',lineHeight:'normal',whiteSpace:'nowrap'}">
55
55
  <div style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--text-muted);padding-bottom:3px">{{ tip.title }}</div>
56
- <div style="font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-heading)">{{ tip.value }}</div>
56
+ <div style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-xs);color:var(--text-heading)">{{ tip.value }}</div>
57
57
  </div>
58
58
  </div>
59
59
  </div>
@@ -47,11 +47,11 @@ export function Surface3D({ values = [], width = 420, height = 300, yaw: yaw0 =
47
47
  <svg width={width} height={height} {...handlers} role="img" style={{ cursor: interactive ? "grab" : "default", touchAction: "none" }}>
48
48
  <path d={basePath} fill="var(--bg-inset)" stroke="var(--chart-axis)" strokeWidth="1" />
49
49
  {axes3.map((ax, i) => <line key={"ae" + i} x1={ax.a.x} y1={ax.a.y} x2={ax.b.x} y2={ax.b.y} stroke="var(--chart-guide)" strokeWidth="1" />)}
50
- {axes3.map((ax, i) => ax.label ? <text key={"al" + i} x={ax.lp.x} y={ax.lp.y + 3} textAnchor={ax.anchor} style={{ fontFamily: "var(--font-sans)", fontSize: 10, fill: "var(--text-secondary)" }}>{ax.label}</text> : null)}
50
+ {axes3.map((ax, i) => ax.label ? <text key={"al" + i} x={ax.lp.x} y={ax.lp.y + 3} textAnchor={ax.anchor} style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--text-secondary)" }}>{ax.label}</text> : null)}
51
51
  {zTicks.map((t, i) => (
52
52
  <g key={"zt" + i}>
53
53
  <line x1={t.p.x - 4} y1={t.p.y} x2={t.p.x} y2={t.p.y} stroke="var(--chart-guide)" strokeWidth="1" />
54
- <text x={t.p.x - 7} y={t.p.y + 3} textAnchor="end" style={{ fontFamily: "var(--font-mono)", fontSize: 9, fill: "var(--chart-label)" }}>{t.v}</text>
54
+ <text x={t.p.x - 7} y={t.p.y + 3} textAnchor="end" style={{ fontFamily: "var(--font-sans)", fontVariantNumeric: "tabular-nums", fontSize: "var(--text-2xs-mono)", fill: "var(--chart-label)" }}>{t.v}</text>
55
55
  </g>
56
56
  ))}
57
57
  {quads.map((q, i) => (
@@ -47,17 +47,17 @@ function fill(q){ return shade(heatColor(q.t), Math.max(-0.35, Math.min(0.3, q.l
47
47
  <path :d="g.basePath" fill="var(--bg-inset)" stroke="var(--chart-axis)" stroke-width="1"/>
48
48
  <line v-for="(ax,i) in g.axes3" :key="'ae'+i" :x1="ax.a.x" :y1="ax.a.y" :x2="ax.b.x" :y2="ax.b.y" stroke="var(--chart-guide)" stroke-width="1"/>
49
49
  <text v-for="(ax,i) in g.axes3.filter(a=>a.label)" :key="'al'+i" :x="ax.lp.x" :y="ax.lp.y+3" :text-anchor="ax.anchor"
50
- style="font-family:var(--font-sans);font-size:10px;fill:var(--text-secondary)">{{ ax.label }}</text>
50
+ style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--text-secondary)">{{ ax.label }}</text>
51
51
  <g v-for="(t,i) in g.zTicks" :key="'zt'+i">
52
52
  <line :x1="t.p.x-4" :y1="t.p.y" :x2="t.p.x" :y2="t.p.y" stroke="var(--chart-guide)" stroke-width="1"/>
53
- <text :x="t.p.x-7" :y="t.p.y+3" text-anchor="end" style="font-family:var(--font-mono);font-size:9px;fill:var(--chart-label)">{{ t.v }}</text>
53
+ <text :x="t.p.x-7" :y="t.p.y+3" text-anchor="end" style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-2xs-mono);fill:var(--chart-label)">{{ t.v }}</text>
54
54
  </g>
55
55
  <path v-for="(q,i) in g.quads" :key="i" :d="q.d" :fill="fill(q)" :stroke="wire?'var(--bg-surface)':'none'" stroke-width="0.5"
56
56
  @mouseenter="interactive && (hover=q)" @mouseleave="interactive && (hover=null)"/>
57
57
  </svg>
58
58
  <div v-if="hover && interactive" :style="{position:'absolute',left:hover.cx+'px',top:hover.cy+'px',transform:hover.cx>width*0.6?'translate(calc(-100% - 10px),-50%)':'translate(10px,-50%)',pointerEvents:'none',zIndex:5,background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-menu)',padding:'7px 10px',lineHeight:'normal',whiteSpace:'nowrap'}">
59
59
  <div style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--text-muted);padding-bottom:3px">row {{ hover.r+1 }} · col {{ hover.c+1 }}</div>
60
- <div style="font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-heading)">{{ valueFormat(hover.avg) }}</div>
60
+ <div style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-xs);color:var(--text-heading)">{{ valueFormat(hover.avg) }}</div>
61
61
  </div>
62
62
  </div>
63
63
  </template>
@@ -20,8 +20,8 @@ export function TreemapChart({ items = [], width = 560, height = 260, valueForma
20
20
  <rect x={c.x + 1} y={c.y + 1} width={Math.max(1, c.w - 2)} height={Math.max(1, c.h - 2)} rx="3" fill={colorOf(c.item)}
21
21
  opacity={hover == null ? 0.85 : hover === i ? 1 : 0.35} style={{ transition: "opacity var(--dur-fast) var(--ease-out)" }} />
22
22
  {c.w > 74 && c.h > 34 ? <>
23
- <text x={c.x + 9} y={c.y + 18} style={{ fontFamily: "var(--font-sans)", fontSize: 11, fill: "var(--on-accent)" }}>{c.item.label}</text>
24
- <text x={c.x + 9} y={c.y + 32} style={{ fontFamily: "var(--font-mono)", fontSize: 10, fill: "var(--on-accent)", opacity: 0.85 }}>{valueFormat(c.item.value)}</text>
23
+ <text x={c.x + 9} y={c.y + 18} style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", fill: "var(--on-accent)" }}>{c.item.label}</text>
24
+ <text x={c.x + 9} y={c.y + 32} style={{ fontFamily: "var(--font-sans)", fontVariantNumeric: "tabular-nums", fontSize: "var(--text-2xs-mono)", fill: "var(--on-accent)", opacity: 0.85 }}>{valueFormat(c.item.value)}</text>
25
25
  </> : null}
26
26
  </g>
27
27
  ))}
@@ -14,14 +14,14 @@ const total = computed(() => props.items.reduce((s,i)=>s+i.value,0)||1)
14
14
  <rect :x="c.x+1" :y="c.y+1" :width="Math.max(1,c.w-2)" :height="Math.max(1,c.h-2)" rx="3" :fill="c.color"
15
15
  :opacity="hover==null?.85:hover===i?1:.35" style="transition:opacity var(--dur-fast) var(--ease-out)"/>
16
16
  <template v-if="c.w>74 && c.h>34">
17
- <text :x="c.x+9" :y="c.y+18" style="font-family:var(--font-sans);font-size:11px;fill:var(--on-accent)">{{ c.item.label }}</text>
18
- <text :x="c.x+9" :y="c.y+32" style="font-family:var(--font-mono);font-size:10px;fill:var(--on-accent);opacity:.85">{{ valueFormat(c.item.value) }}</text>
17
+ <text :x="c.x+9" :y="c.y+18" style="font-family:var(--font-sans);font-size:var(--text-xs);fill:var(--on-accent)">{{ c.item.label }}</text>
18
+ <text :x="c.x+9" :y="c.y+32" style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-2xs-mono);fill:var(--on-accent);opacity:.85">{{ valueFormat(c.item.value) }}</text>
19
19
  </template>
20
20
  </g>
21
21
  </svg>
22
22
  <div v-if="hover!=null && interactive" :style="{position:'absolute',left:(cells[hover].x+cells[hover].w/2)+'px',top:(cells[hover].y+cells[hover].h/2)+'px',transform:(cells[hover].x+cells[hover].w/2)>width*0.62?'translate(calc(-100% - 10px),-50%)':'translate(10px,-50%)',pointerEvents:'none',zIndex:5,background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-menu)',padding:'7px 10px',lineHeight:'normal'}">
23
23
  <div style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--text-muted);white-space:nowrap;padding-bottom:2px">{{ cells[hover].item.label }}</div>
24
- <div style="font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-heading);white-space:nowrap">{{ valueFormat(cells[hover].item.value) }} · {{ ((cells[hover].item.value/total)*100).toFixed(1) }}%</div>
24
+ <div style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-xs);color:var(--text-heading);white-space:nowrap">{{ valueFormat(cells[hover].item.value) }} · {{ ((cells[hover].item.value/total)*100).toFixed(1) }}%</div>
25
25
  </div>
26
26
  </div>
27
27
  </template>
@@ -38,8 +38,8 @@ export function WaterfallChart({ steps = [], width = 560, height = 260, axes = t
38
38
  <g key={i} opacity={hover == null || hover === i ? 1 : 0.45} style={{ transition: "opacity var(--dur-fast) var(--ease-out)" }}>
39
39
  <rect x={x - bw / 2} y={y} width={bw} height={hgt} rx="2" fill={fill[b.kind]} />
40
40
  {i < bars.length - 1 ? <line x1={x + bw / 2} x2={pad.l + slot * (i + 1) + slot / 2 - bw / 2} y1={sy(runEnd)} y2={sy(runEnd)} stroke="var(--chart-guide)" strokeWidth="1" strokeDasharray="2 3" /> : null}
41
- {showValues ? <text x={x} y={y - 5} textAnchor="middle" style={{ fontFamily: "var(--font-mono)", fontSize: 10, fill: b.kind === "neg" ? "var(--chart-neg)" : "var(--text-heading)" }}>{(b.kind === "pos" ? "+" : "") + valueFormat(b.value)}</text> : null}
42
- <text x={x} y={height - pad.b + 15} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontSize: 10, fill: "var(--chart-label)" }}>
41
+ {showValues ? <text x={x} y={y - 5} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontVariantNumeric: "tabular-nums", fontSize: "var(--text-2xs-mono)", fill: b.kind === "neg" ? "var(--chart-neg)" : "var(--text-heading)" }}>{(b.kind === "pos" ? "+" : "") + valueFormat(b.value)}</text> : null}
42
+ <text x={x} y={height - pad.b + 15} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>
43
43
  {String(b.label).split("\n").map((ln, li) => <tspan key={li} x={x} dy={li ? 11 : 0}>{ln}</tspan>)}
44
44
  </text>
45
45
  </g>
@@ -13,7 +13,7 @@ const g = computed(() => {
13
13
  const sy = scaleLin(lo, hi, props.height-pad.b, pad.t)
14
14
  const slot = (props.width-pad.l-pad.r)/bars.length
15
15
  const bw = Math.min(slot*0.58, 40)
16
- return { pad, ticks, sy, out: bars.map((b,i)=>{
16
+ return { pad, ticks, sy, slot, out: bars.map((b,i)=>{
17
17
  const x = pad.l + slot*i + slot/2
18
18
  return { ...b, x, bw, y: sy(b.y1), h: Math.max(1.5, sy(b.y0)-sy(b.y1)), fill: FILL[b.kind],
19
19
  run: sy(b.kind==='total'?b.y1:b.to), nextX: pad.l + slot*(i+1) + slot/2 - bw/2, last: i===bars.length-1,
@@ -26,21 +26,22 @@ const g = computed(() => {
26
26
  <template v-if="axes">
27
27
  <g v-for="t in g.ticks" :key="t">
28
28
  <line :x1="g.pad.l" :x2="width-g.pad.r" :y1="g.sy(t)" :y2="g.sy(t)" :stroke="t===0?'var(--chart-axis)':'var(--chart-grid)'" stroke-width="1"/>
29
- <text :x="g.pad.l-8" :y="g.sy(t)+3" text-anchor="end" style="font-family:var(--font-mono);font-size:10px;fill:var(--chart-label)">{{ valueFormat(t) }}</text>
29
+ <text :x="g.pad.l-8" :y="g.sy(t)+3" text-anchor="end" style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-2xs-mono);fill:var(--chart-label)">{{ valueFormat(t) }}</text>
30
30
  </g>
31
31
  </template>
32
+ <rect v-if="hover!=null" :x="g.pad.l+g.slot*hover" :y="g.pad.t" :width="g.slot" :height="height-g.pad.t-g.pad.b" fill="var(--bg-hover)"/>
32
33
  <g v-for="(b,i) in g.out" :key="i" :opacity="hover==null||hover===i?1:0.45" style="transition:opacity var(--dur-fast) var(--ease-out)">
33
34
  <rect :x="b.x-b.bw/2" :y="b.y" :width="b.bw" :height="b.h" rx="2" :fill="b.fill"/>
34
35
  <line v-if="!b.last" :x1="b.x+b.bw/2" :x2="b.nextX" :y1="b.run" :y2="b.run" stroke="var(--chart-guide)" stroke-width="1" stroke-dasharray="2 3"/>
35
- <text v-if="showValues" :x="b.x" :y="b.y-5" text-anchor="middle" :style="{fontFamily:'var(--font-mono)',fontSize:'10px',fill:b.kind==='neg'?'var(--chart-neg)':'var(--text-heading)'}">{{ (b.kind==='pos'?'+':'')+valueFormat(b.value) }}</text>
36
- <text :x="b.x" :y="height-g.pad.b+15" text-anchor="middle" style="font-family:var(--font-sans);font-size:10px;fill:var(--chart-label)">
36
+ <text v-if="showValues" :x="b.x" :y="b.y-5" text-anchor="middle" :style="{fontFamily: 'var(--font-sans)', fontVariantNumeric: 'tabular-nums',fontSize:'var(--text-2xs-mono)',fill:b.kind==='neg'?'var(--chart-neg)':'var(--text-heading)'}">{{ (b.kind==='pos'?'+':'')+valueFormat(b.value) }}</text>
37
+ <text :x="b.x" :y="height-g.pad.b+15" text-anchor="middle" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">
37
38
  <tspan v-for="(ln,li) in b.lines" :key="li" :x="b.x" :dy="li?11:0">{{ ln }}</tspan>
38
39
  </text>
39
40
  </g>
40
41
  </svg>
41
42
  <div v-if="hover!=null && interactive" :style="{position:'absolute',left:g.out[hover].x+'px',top:(height/2-10)+'px',transform:g.out[hover].x>width*0.62?'translate(calc(-100% - 10px),-50%)':'translate(10px,-50%)',pointerEvents:'none',zIndex:5,background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-menu)',padding:'7px 10px',lineHeight:'normal',whiteSpace:'nowrap'}">
42
43
  <div style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--text-muted);padding-bottom:3px">{{ String(g.out[hover].label).replace('\n',' ') }}</div>
43
- <div style="font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-heading)">{{ g.out[hover].kind==='total' ? valueFormat(g.out[hover].value) : ((g.out[hover].kind==='pos'?'+':'')+valueFormat(g.out[hover].value)+' → '+valueFormat(g.out[hover].to)) }}</div>
44
+ <div style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-xs);color:var(--text-heading)">{{ g.out[hover].kind==='total' ? valueFormat(g.out[hover].value) : ((g.out[hover].kind==='pos'?'+':'')+valueFormat(g.out[hover].value)+' → '+valueFormat(g.out[hover].to)) }}</div>
44
45
  </div>
45
46
  </div>
46
47
  </template>
@@ -74,8 +74,8 @@ export function WorldMap({ values = {}, width = 660, height = 340, projection =
74
74
  return HEAT[Math.max(0, bucket(v))];
75
75
  };
76
76
 
77
- if (err) return <div style={{ width, height, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-mono)", fontSize: "var(--text-xs)", color: "var(--text-muted)", background: "var(--bg-inset)", borderRadius: "var(--radius-lg)", ...style }}>{err}</div>;
78
- if (!paths) return <div style={{ width, height, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-mono)", fontSize: "var(--text-xs)", color: "var(--text-muted)", ...style }}>loading map…</div>;
77
+ if (err) return <div style={{ width, height, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-sans)", fontVariantNumeric: "tabular-nums", fontSize: "var(--text-xs)", color: "var(--text-muted)", background: "var(--bg-inset)", borderRadius: "var(--radius-lg)", ...style }}>{err}</div>;
78
+ if (!paths) return <div style={{ width, height, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-sans)", fontVariantNumeric: "tabular-nums", fontSize: "var(--text-xs)", color: "var(--text-muted)", ...style }}>loading map…</div>;
79
79
 
80
80
  const h = hover != null ? paths[hover] : null;
81
81
  return (
@@ -91,11 +91,11 @@ export function WorldMap({ values = {}, width = 660, height = 340, projection =
91
91
  </svg>
92
92
  {legend ? (
93
93
  <div style={{ display: "flex", alignItems: "center", gap: 6, paddingTop: 6, lineHeight: "normal" }}>
94
- <span style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--chart-label)" }}>{valueFormat(lo)}</span>
94
+ <span style={{ fontFamily: "var(--font-sans)", fontVariantNumeric: "tabular-nums", fontSize: "var(--text-2xs-mono)", color: "var(--chart-label)" }}>{valueFormat(lo)}</span>
95
95
  {(scale === "diverging" ? ["var(--chart-neg)", "color-mix(in srgb, var(--chart-neg) 40%, var(--bg-surface))", "var(--chart-track)", "color-mix(in srgb, var(--chart-pos) 40%, var(--bg-surface))", "var(--chart-pos)"] : HEAT).map((c, i) => (
96
96
  <span key={i} style={{ width: 22, height: 8, borderRadius: 2, background: c }} />
97
97
  ))}
98
- <span style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--chart-label)" }}>{valueFormat(hi)}{unit ? " " + unit : ""}</span>
98
+ <span style={{ fontFamily: "var(--font-sans)", fontVariantNumeric: "tabular-nums", fontSize: "var(--text-2xs-mono)", color: "var(--chart-label)" }}>{valueFormat(hi)}{unit ? " " + unit : ""}</span>
99
99
  </div>
100
100
  ) : null}
101
101
  {h && interactive ? (
@@ -51,8 +51,8 @@ const swatches = computed(() => props.scale==='diverging'
51
51
  : HEAT)
52
52
  </script>
53
53
  <template>
54
- <div v-if="err" :style="{width:width+'px',height:height+'px',display:'flex',alignItems:'center',justifyContent:'center',fontFamily:'var(--font-mono)',fontSize:'var(--text-xs)',color:'var(--text-muted)',background:'var(--bg-inset)',borderRadius:'var(--radius-lg)',...style}">{{ err }}</div>
55
- <div v-else-if="!paths" :style="{width:width+'px',height:height+'px',display:'flex',alignItems:'center',justifyContent:'center',fontFamily:'var(--font-mono)',fontSize:'var(--text-xs)',color:'var(--text-muted)',...style}">loading map…</div>
54
+ <div v-if="err" :style="{width:width+'px',height:height+'px',display:'flex',alignItems:'center',justifyContent:'center',fontFamily: 'var(--font-sans)', fontVariantNumeric: 'tabular-nums',fontSize:'var(--text-xs)',color:'var(--text-muted)',background:'var(--bg-inset)',borderRadius:'var(--radius-lg)',...style}">{{ err }}</div>
55
+ <div v-else-if="!paths" :style="{width:width+'px',height:height+'px',display:'flex',alignItems:'center',justifyContent:'center',fontFamily: 'var(--font-sans)', fontVariantNumeric: 'tabular-nums',fontSize:'var(--text-xs)',color:'var(--text-muted)',...style}">loading map…</div>
56
56
  <div v-else :style="{position:'relative',display:'inline-block',lineHeight:0,...style}">
57
57
  <svg :width="width" :height="plotH" role="img">
58
58
  <path v-for="(p,i) in paths" :key="p.name+i" :d="p.d" :fill="fill(p.name)" stroke="var(--bg-surface)" stroke-width="0.5"
@@ -61,13 +61,13 @@ const swatches = computed(() => props.scale==='diverging'
61
61
  <path v-if="hover!=null" :d="paths[hover].d" fill="none" stroke="var(--action-primary)" stroke-width="1.4" pointer-events="none"/>
62
62
  </svg>
63
63
  <div v-if="legend" style="display:flex;align-items:center;gap:6px;padding-top:6px;line-height:normal">
64
- <span style="font-family:var(--font-mono);font-size:10px;color:var(--chart-label)">{{ valueFormat(lo) }}</span>
64
+ <span style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-2xs-mono);color:var(--chart-label)">{{ valueFormat(lo) }}</span>
65
65
  <span v-for="(c,i) in swatches" :key="i" :style="{width:'22px',height:'8px',borderRadius:'2px',background:c}"/>
66
- <span style="font-family:var(--font-mono);font-size:10px;color:var(--chart-label)">{{ valueFormat(hi) }}{{ unit ? ' '+unit : '' }}</span>
66
+ <span style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-2xs-mono);color:var(--chart-label)">{{ valueFormat(hi) }}{{ unit ? ' '+unit : '' }}</span>
67
67
  </div>
68
68
  <div v-if="hover!=null && interactive" :style="{position:'absolute',left:paths[hover].c[0]+'px',top:paths[hover].c[1]+'px',transform:paths[hover].c[0]>width*0.62?'translate(calc(-100% - 10px),-50%)':'translate(10px,-50%)',pointerEvents:'none',zIndex:5,background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-menu)',padding:'7px 10px',lineHeight:'normal',whiteSpace:'nowrap'}">
69
69
  <div style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--text-muted);padding-bottom:3px">{{ paths[hover].name }}</div>
70
- <div style="font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-heading)">{{ resolved[paths[hover].name]==null ? 'no data' : valueFormat(resolved[paths[hover].name]) }}</div>
70
+ <div style="font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-xs);color:var(--text-heading)">{{ resolved[paths[hover].name]==null ? 'no data' : valueFormat(resolved[paths[hover].name]) }}</div>
71
71
  </div>
72
72
  </div>
73
73
  </template>
@@ -0,0 +1,11 @@
1
+ <script setup>
2
+ // Thin x-axis category labels only (small charts with no y axis). Render inside an <svg>.
3
+ defineProps({ h: Number, pad: Object, xLabels: { type: Array, default: () => [] }, sxLabel: Function })
4
+ </script>
5
+ <template>
6
+ <g>
7
+ <template v-for="(lb, i) in xLabels" :key="i">
8
+ <text v-if="lb != null" :x="sxLabel(i)" :y="h - pad.b + 16" text-anchor="middle" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">{{ lb }}</text>
9
+ </template>
10
+ </g>
11
+ </template>
@@ -9,7 +9,7 @@ export function CodeBlock({ code = "", language, height, style }) {
9
9
  <div style={{ background: "var(--bg-inset)", border: "1px solid var(--border-subtle)", borderRadius: "var(--radius-md)", ...style }}>
10
10
  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "7px 10px", borderBottom: "1px solid var(--border-subtle)" }}>
11
11
  <span style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-xs)", color: "var(--text-muted)" }}>{language || "code"}</span>
12
- <button type="button" onClick={copy} style={{ display: "flex", alignItems: "center", gap: 4, border: "none", background: "transparent", cursor: "pointer", color: copied ? "var(--success-strong)" : "var(--text-secondary)", fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", padding: 0 }}>
12
+ <button type="button" onClick={copy} data-ink="" style={{ display: "flex", alignItems: "center", gap: 4, border: "none", background: "transparent", cursor: "pointer", color: copied ? "var(--success-strong)" : "var(--ink, var(--text-secondary))", fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", padding: 0 }}>
13
13
  <Icon name={copied ? "check" : "copy"} size={12} />{copied ? "Copied" : "Copy"}
14
14
  </button>
15
15
  </div>
@@ -13,7 +13,7 @@ function copy() {
13
13
  <div :style="{ background: 'var(--bg-inset)', border: '1px solid var(--border-subtle)', borderRadius: 'var(--radius-md)', ...style }">
14
14
  <div style="display:flex;justify-content:space-between;align-items:center;padding:7px 10px;border-bottom:1px solid var(--border-subtle)">
15
15
  <span style="font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-muted)">{{ language || 'code' }}</span>
16
- <button type="button" @click="copy" :style="{ display: 'flex', alignItems: 'center', gap: 4, border: 'none', background: 'transparent', cursor: 'pointer', color: copied ? 'var(--success-strong)' : 'var(--text-secondary)', fontFamily: 'var(--font-sans)', fontSize: 'var(--text-xs)', padding: 0 }">
16
+ <button type="button" @click="copy" data-ink="" :style="{ display: 'flex', alignItems: 'center', gap: '4px', border: 'none', background: 'transparent', cursor: 'pointer', color: copied ? 'var(--success-strong)' : 'var(--ink, var(--text-secondary))', fontFamily: 'var(--font-sans)', fontSize: 'var(--text-xs)', padding: 0 }">
17
17
  <Icon :name="copied ? 'check' : 'copy'" :size="12" />{{ copied ? 'Copied' : 'Copy' }}
18
18
  </button>
19
19
  </div>
@@ -5,6 +5,7 @@ export interface DiffValueProps {
5
5
  from?: React.ReactNode;
6
6
  to: React.ReactNode;
7
7
  tone?: "neutral" | "warning" | "success" | "danger";
8
+ /** Tabular figures (UI font — the monospace font is reserved for code). */
8
9
  mono?: boolean;
9
10
  style?: React.CSSProperties;
10
11
  }
@@ -6,7 +6,7 @@ const toneColor = { neutral: "var(--text-heading)", warning: "var(--warning-text
6
6
  /** Before → after value change ("USD → EUR"). tone colors the new value; from renders muted + struck through when both sides are given. */
7
7
  export function DiffValue({ from, to, tone = "warning", mono = true, style }) {
8
8
  return (
9
- <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontFamily: mono ? "var(--font-mono)" : "var(--font-sans)", fontSize: "var(--text-sm)", ...style }}>
9
+ <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontFamily: "var(--font-sans)", fontSize: "var(--control-text)", ...style }}>
10
10
  {from != null ? <span style={{ color: "var(--text-muted)", textDecoration: "line-through" }}>{from}</span> : null}
11
11
  <Icon name="arrow-right" size={12} style={{ color: "var(--text-muted)" }} />
12
12
  <span style={{ color: toneColor[tone], fontWeight: "var(--weight-medium)" }}>{to}</span>
@@ -5,7 +5,7 @@ const toneColor = { neutral: 'var(--text-heading)', warning: 'var(--warning-text
5
5
  defineProps({ from: [String, Number], to: [String, Number], tone: { type: String, default: 'warning' }, mono: { type: Boolean, default: true }, style: Object })
6
6
  </script>
7
7
  <template>
8
- <span :style="{ display: 'inline-flex', alignItems: 'center', gap: 6, fontFamily: mono ? 'var(--font-mono)' : 'var(--font-sans)', fontSize: 'var(--text-sm)', ...style }">
8
+ <span :style="{ display: 'inline-flex', alignItems: 'center', gap: '6px', fontFamily: 'var(--font-sans)', fontSize: 'var(--control-text)', ...style }">
9
9
  <span v-if="from != null" style="color:var(--text-muted);text-decoration:line-through">{{ from }}</span>
10
10
  <Icon name="arrow-right" :size="12" style="color:var(--text-muted)" />
11
11
  <span :style="{ color: toneColor[tone], fontWeight: 'var(--weight-medium)' }">{{ to }}</span>
@@ -9,6 +9,8 @@ export interface FilterBarProps {
9
9
  /** Count shown in "Adapt Filters (n)" */
10
10
  adaptCount?: number;
11
11
  defaultExpanded?: boolean;
12
+ /** Size tier for the whole bar and every field in it. Omit to inherit the enclosing region's tier (the default). */
13
+ size?: "sm" | "md" | "lg";
12
14
  onGo?: () => void;
13
15
  onAdapt?: () => void;
14
16
  children?: React.ReactNode;
@@ -2,21 +2,22 @@ import React from "react";
2
2
  import { Icon } from "../icons/Icon.jsx";
3
3
  import { Button } from "../buttons/Button.jsx";
4
4
 
5
- /** SAP Fiori-style list-report filter bar: variant title row with expand/collapse, a wrapping row of labeled filter fields (pass Field-wrapped controls as children), and Adapt Filters (n) + Go actions. */
6
- export function FilterBar({ variant = "Standard", modified, adaptCount, defaultExpanded = true, onGo, onAdapt, children, style }) {
5
+ /** SAP Fiori-style list-report filter bar: variant title row with expand/collapse, a wrapping row of labeled filter fields (pass Field-wrapped controls as children), and Adapt Filters (n) + Go actions.
6
+ * A size region: `size` (default inherit → md) sets the title bar height, the fields' tier and the gap between fields (--group-gap) so every control in it matches. */
7
+ export function FilterBar({ variant = "Standard", modified, adaptCount, defaultExpanded = true, size, onGo, onAdapt, children, style }) {
7
8
  const [open, setOpen] = React.useState(defaultExpanded);
8
9
  return (
9
- <div style={{ background: "var(--bg-surface)", border: "1px solid var(--border-card)", borderRadius: "var(--radius-lg)", padding: "10px 16px 0", boxSizing: "border-box", ...style }}>
10
- <div style={{ display: "flex", alignItems: "center", gap: 6, paddingBottom: 10 }}>
11
- <button type="button" onClick={() => setOpen(!open)} style={{ display: "flex", alignItems: "center", gap: 6, border: "none", background: "transparent", cursor: "pointer", padding: 0, color: "var(--text-heading)", fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-base)", letterSpacing: "var(--tracking-base)" }}>
10
+ <div data-size={size} style={{ background: "var(--bg-surface)", border: "1px solid var(--border-card)", borderRadius: "var(--radius-lg)", boxSizing: "border-box", ...style }}>
11
+ <div style={{ display: "flex", alignItems: "center", gap: "var(--control-gap)", minHeight: "var(--bar-card-h)", padding: "0 var(--edge-pad)", boxSizing: "border-box" }}>
12
+ <button type="button" aria-expanded={open} onClick={() => setOpen(!open)} style={{ display: "flex", alignItems: "center", gap: 6, border: "none", background: "transparent", cursor: "pointer", padding: 0, color: "var(--text-heading)", fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--control-text)", lineHeight: "var(--control-leading)", letterSpacing: "var(--control-tracking)" }}>
12
13
  {variant}{modified && <span style={{ color: "var(--text-muted)", fontWeight: "var(--weight-regular)" }}>*</span>}
13
- <span style={{ color: "var(--text-muted)", display: "inline-flex", transform: open ? "rotate(180deg)" : "none", transition: "transform var(--dur-fast) var(--ease-out)" }}><Icon name="chevron-down" size={14} /></span>
14
+ <span style={{ color: "var(--text-muted)", display: "inline-flex", transform: open ? "rotate(180deg)" : "none", transition: "transform var(--dur-fast) var(--ease-out)" }}><Icon name="chevron-down" size={16} style={{ width: "var(--control-icon)", height: "var(--control-icon)" }} /></span>
14
15
  </button>
15
16
  <span style={{ flex: 1 }}></span>
16
- <Button variant="text" size="sm" onClick={onAdapt}>Adapt Filters{adaptCount ? ` (${adaptCount})` : ""}</Button>
17
- <Button size="sm" onClick={onGo}>Go</Button>
17
+ <Button variant="text" onClick={onAdapt}>Adapt Filters{adaptCount ? ` (${adaptCount})` : ""}</Button>
18
+ <Button onClick={onGo}>Go</Button>
18
19
  </div>
19
- {open && <div style={{ display: "flex", flexWrap: "wrap", gap: "12px 16px", paddingBottom: 14, borderTop: "1px solid var(--border-subtle)", paddingTop: 12 }}>{children}</div>}
20
+ {open && <div style={{ display: "flex", flexWrap: "wrap", alignItems: "flex-end", gap: "var(--control-gap) var(--group-gap)", padding: "12px var(--edge-pad) var(--edge-pad)", borderTop: "1px solid var(--border-subtle)" }}>{children}</div>}
20
21
  </div>
21
22
  );
22
23
  }