@cueplusplus/ui 0.15.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (508) hide show
  1. package/CHANGELOG.md +1083 -0
  2. package/README.md +26 -0
  3. package/dist/agent-runtime/tool-call-card.js +7 -3
  4. package/dist/brand/_chassis.d.ts +1 -1
  5. package/dist/brand/cue-mark.d.ts +1 -1
  6. package/dist/brand/cue-mark.js +1 -1
  7. package/dist/charts/ramps.js +1 -1
  8. package/dist/chat/agent-pile.js +2 -1
  9. package/dist/chat/ask-box.js +4 -3
  10. package/dist/chat/delegation-card.js +3 -2
  11. package/dist/chat/message-list.js +4 -2
  12. package/dist/chat/message.js +17 -7
  13. package/dist/chrome/_edge-scroller.js +2 -1
  14. package/dist/chrome/_status-bar.js +9 -3
  15. package/dist/chrome/_tabs-scroll.d.ts +17 -1
  16. package/dist/chrome/_tabs-scroll.js +20 -3
  17. package/dist/chrome/app-bar.js +10 -3
  18. package/dist/chrome/app-shell.js +2 -1
  19. package/dist/chrome/band.d.ts +18 -12
  20. package/dist/chrome/band.js +19 -31
  21. package/dist/chrome/eyebrow.d.ts +13 -5
  22. package/dist/chrome/eyebrow.js +18 -7
  23. package/dist/chrome/footer.d.ts +5 -0
  24. package/dist/chrome/footer.js +14 -3
  25. package/dist/chrome/navigation-menu.js +4 -2
  26. package/dist/chrome/page-shell.js +8 -5
  27. package/dist/chrome/panel.d.ts +5 -2
  28. package/dist/chrome/panel.js +9 -4
  29. package/dist/chrome/row.js +6 -3
  30. package/dist/chrome/scroll-area.js +2 -1
  31. package/dist/chrome/section-header.js +13 -4
  32. package/dist/chrome/segmented-control.js +12 -3
  33. package/dist/chrome/status-bar.js +2 -1
  34. package/dist/chrome/tabs.js +11 -3
  35. package/dist/chrome/toolbar.js +2 -1
  36. package/dist/chrome/tree.js +3 -2
  37. package/dist/color/_thumb.js +9 -3
  38. package/dist/color/color-area.js +1 -1
  39. package/dist/color/color-field.d.ts +2 -1
  40. package/dist/color/color-picker.d.ts +2 -1
  41. package/dist/color/color-swatch.js +1 -1
  42. package/dist/configurator/_overrides.js +13 -4
  43. package/dist/configurator/configurator.js +4 -1
  44. package/dist/configurator/export-dialog.js +5 -2
  45. package/dist/configurator/panel-sections.js +6 -2
  46. package/dist/configurator/token-editor.js +4 -1
  47. package/dist/date/calendar.js +12 -8
  48. package/dist/date/date-field.d.ts +2 -1
  49. package/dist/date/date-picker.d.ts +2 -1
  50. package/dist/date/date-range-picker.d.ts +2 -1
  51. package/dist/date/time-field.d.ts +2 -1
  52. package/dist/dmx/channel-matrix.js +3 -2
  53. package/dist/dmx/dmx-bar.js +1 -1
  54. package/dist/dmx/dmx-strip.js +1 -1
  55. package/dist/dmx/universe-grid.js +3 -2
  56. package/dist/elements/activity-graph.js +3 -3
  57. package/dist/elements/agent-card.js +3 -3
  58. package/dist/elements/approval-card.js +3 -3
  59. package/dist/elements/artifact-card.js +2 -2
  60. package/dist/elements/background-inbox.js +2 -2
  61. package/dist/elements/canvas-split.js +2 -2
  62. package/dist/elements/chart.js +1 -1
  63. package/dist/elements/chat-panel.js +2 -2
  64. package/dist/elements/checkpoint-history.js +2 -2
  65. package/dist/elements/clamp.js +2 -1
  66. package/dist/elements/code-diff.js +1 -1
  67. package/dist/elements/code-runner.js +1 -1
  68. package/dist/elements/command-palette.js +6 -5
  69. package/dist/elements/comparison-card.js +2 -2
  70. package/dist/elements/composer.js +9 -8
  71. package/dist/elements/computer-use.js +1 -1
  72. package/dist/elements/confidence-marker.js +2 -1
  73. package/dist/elements/connection-state.js +1 -1
  74. package/dist/elements/context-breakdown.js +1 -1
  75. package/dist/elements/context-usage.js +1 -1
  76. package/dist/elements/conversation-search.js +4 -3
  77. package/dist/elements/cost-meter.js +1 -1
  78. package/dist/elements/data-table.js +2 -2
  79. package/dist/elements/day-separator.js +1 -1
  80. package/dist/elements/diagram.js +1 -1
  81. package/dist/elements/document-reference.js +3 -3
  82. package/dist/elements/draft-restore.js +1 -1
  83. package/dist/elements/edit-message.js +4 -3
  84. package/dist/elements/elements.css +26 -5
  85. package/dist/elements/elicitation-form.js +3 -3
  86. package/dist/elements/empty-state.js +2 -1
  87. package/dist/elements/error-state.js +1 -1
  88. package/dist/elements/feedback-dialog.js +4 -3
  89. package/dist/elements/file-tree.js +2 -2
  90. package/dist/elements/flow-graph.js +2 -2
  91. package/dist/elements/guardrail-notice.js +3 -3
  92. package/dist/elements/image-generation.js +1 -1
  93. package/dist/elements/inline-citation.js +3 -3
  94. package/dist/elements/job-progress.js +3 -3
  95. package/dist/elements/launcher-bubble.js +2 -2
  96. package/dist/elements/loading-state.js +1 -1
  97. package/dist/elements/map-answer.js +3 -2
  98. package/dist/elements/markdown.js +5 -4
  99. package/dist/elements/math-block.js +1 -1
  100. package/dist/elements/mcp-server-panel.js +3 -3
  101. package/dist/elements/message-attachment.js +4 -4
  102. package/dist/elements/message-pair.js +1 -1
  103. package/dist/elements/message-queue.js +2 -2
  104. package/dist/elements/mobile-composer.js +4 -3
  105. package/dist/elements/model-picker.js +3 -3
  106. package/dist/elements/onboarding.js +2 -2
  107. package/dist/elements/permission-grant.js +2 -2
  108. package/dist/elements/permission-scopes.js +5 -4
  109. package/dist/elements/prompt-library.js +7 -6
  110. package/dist/elements/queue-dock.js +4 -3
  111. package/dist/elements/quota-banner.js +1 -1
  112. package/dist/elements/quote-reply.js +1 -1
  113. package/dist/elements/read-aloud.js +2 -2
  114. package/dist/elements/reasoning-panel.js +2 -1
  115. package/dist/elements/recommendation-card.d.ts +1 -1
  116. package/dist/elements/recommendation-card.js +2 -2
  117. package/dist/elements/regenerate-menu.js +2 -2
  118. package/dist/elements/research-report.js +1 -1
  119. package/dist/elements/retrieval-chunks.js +1 -1
  120. package/dist/elements/revert-dock.js +5 -4
  121. package/dist/elements/reviewable-diff.js +1 -1
  122. package/dist/elements/schedule-card.js +3 -3
  123. package/dist/elements/score-breakdown.js +1 -1
  124. package/dist/elements/scroll-anchor.js +2 -2
  125. package/dist/elements/settings-panel.js +3 -2
  126. package/dist/elements/shared-conversation.js +2 -2
  127. package/dist/elements/sources.js +4 -3
  128. package/dist/elements/speaker-identity.js +1 -1
  129. package/dist/elements/spec-sheet.js +1 -1
  130. package/dist/elements/streaming-text.js +1 -1
  131. package/dist/elements/subagent-list.js +2 -2
  132. package/dist/elements/suggestions.js +1 -1
  133. package/dist/elements/surfaces.d.ts +1 -1
  134. package/dist/elements/surfaces.js +2 -1
  135. package/dist/elements/tail-status.js +1 -1
  136. package/dist/elements/terminal-block.js +1 -1
  137. package/dist/elements/thread-list.js +1 -1
  138. package/dist/elements/thread-search.js +5 -4
  139. package/dist/elements/timeline.js +1 -1
  140. package/dist/elements/todo-list.js +2 -2
  141. package/dist/elements/tool-call.js +4 -3
  142. package/dist/elements/tool-error.js +2 -2
  143. package/dist/elements/tool-group.js +1 -1
  144. package/dist/elements/tool-timeline.js +4 -3
  145. package/dist/elements/trace-waterfall.js +1 -1
  146. package/dist/elements/verdict-row.js +2 -2
  147. package/dist/elements/voice-conversation.js +3 -2
  148. package/dist/elements/web-preview.js +1 -1
  149. package/dist/elements/web-search.js +2 -2
  150. package/dist/elements/work-collapse.js +2 -1
  151. package/dist/flow/node-card.js +3 -2
  152. package/dist/flow/use-flow-theme.js +2 -1
  153. package/dist/forms/_chassis-size.d.ts +22 -0
  154. package/dist/forms/_chassis.d.ts +28 -15
  155. package/dist/forms/_chassis.js +34 -8
  156. package/dist/forms/_listbox.js +8 -5
  157. package/dist/forms/autocomplete.d.ts +2 -1
  158. package/dist/forms/checkbox.js +8 -2
  159. package/dist/forms/combobox.d.ts +2 -1
  160. package/dist/forms/env-var-input.d.ts +2 -1
  161. package/dist/forms/env-var-input.js +3 -2
  162. package/dist/forms/field.d.ts +2 -1
  163. package/dist/forms/field.js +15 -4
  164. package/dist/forms/file-upload.js +3 -2
  165. package/dist/forms/index.d.ts +2 -1
  166. package/dist/forms/input-group.d.ts +2 -1
  167. package/dist/forms/input.d.ts +2 -1
  168. package/dist/forms/multi-select.d.ts +2 -1
  169. package/dist/forms/number-field.js +2 -1
  170. package/dist/forms/otp-field.d.ts +2 -1
  171. package/dist/forms/password-input.d.ts +2 -1
  172. package/dist/forms/password-input.js +4 -2
  173. package/dist/forms/radio-group.js +6 -2
  174. package/dist/forms/rating.js +2 -1
  175. package/dist/forms/scrub-input.d.ts +2 -1
  176. package/dist/forms/scrub-input.js +2 -1
  177. package/dist/forms/search-input.d.ts +2 -1
  178. package/dist/forms/search-input.js +2 -1
  179. package/dist/forms/select.d.ts +2 -1
  180. package/dist/forms/select.js +6 -2
  181. package/dist/forms/slider.js +6 -2
  182. package/dist/forms/switch.js +6 -2
  183. package/dist/forms/tags-input.d.ts +2 -1
  184. package/dist/forms/textarea.js +2 -1
  185. package/dist/forms/toggle-group.d.ts +1 -1
  186. package/dist/forms/toggle.d.ts +1 -1
  187. package/dist/forms/toggle.js +3 -1
  188. package/dist/index.d.ts +4 -3
  189. package/dist/index.js +2 -2
  190. package/dist/instruments/_data-row.js +2 -1
  191. package/dist/instruments/app-window-frame.js +1 -1
  192. package/dist/instruments/code-block.js +8 -2
  193. package/dist/instruments/group-bar.js +1 -1
  194. package/dist/instruments/ledger.js +6 -2
  195. package/dist/instruments/log-viewer.js +5 -3
  196. package/dist/instruments/progress.js +5 -2
  197. package/dist/instruments/seam-grid.js +5 -3
  198. package/dist/instruments/stat.js +10 -3
  199. package/dist/instruments/table.js +28 -10
  200. package/dist/instruments/terminal-frame.js +4 -2
  201. package/dist/instruments/usage-chart.js +1 -1
  202. package/dist/layout/_collapse.js +6 -1
  203. package/dist/layout/bento.js +7 -4
  204. package/dist/layout/breadcrumb.js +7 -3
  205. package/dist/layout/card.js +14 -6
  206. package/dist/layout/carousel.js +3 -2
  207. package/dist/layout/collapsible.js +5 -1
  208. package/dist/layout/container.js +2 -1
  209. package/dist/layout/description-list.js +4 -1
  210. package/dist/layout/frames.js +11 -5
  211. package/dist/layout/item.js +3 -2
  212. package/dist/layout/link.d.ts +16 -0
  213. package/dist/layout/link.js +22 -3
  214. package/dist/layout/pagination.js +2 -1
  215. package/dist/layout/preview.d.ts +32 -12
  216. package/dist/layout/preview.js +149 -40
  217. package/dist/layout/resizable.js +2 -1
  218. package/dist/layout/sidebar.js +11 -3
  219. package/dist/layout/stepper.js +6 -2
  220. package/dist/lib/cn.js +29 -2
  221. package/dist/midi/musical-time-input.d.ts +2 -1
  222. package/dist/midi/piano-keyboard.js +3 -2
  223. package/dist/midi/spectrum-visualizer.js +1 -1
  224. package/dist/midi/threshold-rail.js +2 -1
  225. package/dist/midi/timeline-ruler.js +1 -1
  226. package/dist/overlays/_surface.d.ts +72 -12
  227. package/dist/overlays/_surface.js +86 -12
  228. package/dist/overlays/command-palette.js +9 -5
  229. package/dist/overlays/dialog.d.ts +5 -0
  230. package/dist/overlays/dialog.js +6 -1
  231. package/dist/overlays/info-tip.js +2 -1
  232. package/dist/overlays/menubar.js +3 -1
  233. package/dist/overlays/popover.js +2 -1
  234. package/dist/overlays/toast.js +6 -2
  235. package/dist/overlays/tooltip.js +4 -1
  236. package/dist/primitives/button.d.ts +15 -0
  237. package/dist/primitives/button.js +40 -10
  238. package/dist/primitives/chip.d.ts +20 -2
  239. package/dist/primitives/chip.js +39 -17
  240. package/dist/primitives/kbd.d.ts +6 -0
  241. package/dist/primitives/kbd.js +10 -1
  242. package/dist/primitives/skeleton.js +1 -1
  243. package/dist/system/_focus-ring-field.js +29 -0
  244. package/dist/system/_focus-ring.js +125 -0
  245. package/dist/system/_paint-elevation.js +9 -0
  246. package/dist/system/_paint-glass.js +46 -0
  247. package/dist/system/_paint-glow.js +51 -0
  248. package/dist/system/_paint-ground-pattern.js +30 -0
  249. package/dist/system/_paint-rest-shade.js +32 -0
  250. package/dist/system/_paint-rim.js +59 -0
  251. package/dist/system/_paint-stroke-sunken.js +19 -0
  252. package/dist/system/_paint-stroke-surface-1.js +19 -0
  253. package/dist/system/_paint-stroke-surface-2.js +40 -0
  254. package/dist/system/_paint-texture.js +56 -0
  255. package/dist/system/_style-app-bar.js +65 -0
  256. package/dist/system/_style-band.js +57 -0
  257. package/dist/system/_style-body-leading.js +21 -0
  258. package/dist/system/_style-body-size.js +30 -0
  259. package/dist/system/_style-body-weight.js +24 -0
  260. package/dist/system/_style-body.js +27 -0
  261. package/dist/system/_style-caption.js +19 -0
  262. package/dist/system/_style-card-pad.js +43 -0
  263. package/dist/system/_style-check.js +33 -0
  264. package/dist/system/_style-chip.js +103 -0
  265. package/dist/system/_style-code.js +13 -0
  266. package/dist/system/_style-collapse.js +14 -0
  267. package/dist/system/_style-control-face.js +29 -0
  268. package/dist/system/_style-control-label.js +22 -0
  269. package/dist/system/_style-control-step.js +22 -0
  270. package/dist/system/_style-control.js +76 -0
  271. package/dist/system/_style-data-face.js +28 -0
  272. package/dist/system/_style-description.js +23 -0
  273. package/dist/system/_style-eyebrow.js +43 -0
  274. package/dist/system/_style-footer-rule.js +47 -0
  275. package/dist/system/_style-gutter.js +17 -0
  276. package/dist/system/_style-help-ink.js +14 -0
  277. package/dist/system/_style-help.js +29 -0
  278. package/dist/system/_style-input-face.js +34 -0
  279. package/dist/system/_style-kbd.js +46 -0
  280. package/dist/system/_style-label-case.js +36 -0
  281. package/dist/system/_style-label-face.js +32 -0
  282. package/dist/system/_style-label-ink.js +29 -0
  283. package/dist/system/_style-label-leading.js +14 -0
  284. package/dist/system/_style-label-size.js +36 -0
  285. package/dist/system/_style-label-tracking.js +45 -0
  286. package/dist/system/_style-label-weight.js +40 -0
  287. package/dist/system/_style-lede.js +49 -0
  288. package/dist/system/_style-link.js +46 -0
  289. package/dist/system/_style-menu.js +30 -0
  290. package/dist/system/_style-nav-item.js +41 -0
  291. package/dist/system/_style-nav-voice.js +43 -0
  292. package/dist/system/_style-option.js +42 -0
  293. package/dist/system/_style-overlay-title.js +35 -0
  294. package/dist/system/_style-page-title.js +48 -0
  295. package/dist/system/_style-popover-pad.js +13 -0
  296. package/dist/system/_style-quiet-ink.js +13 -0
  297. package/dist/system/_style-row-pad.js +13 -0
  298. package/dist/system/_style-seam.js +43 -0
  299. package/dist/system/_style-section-rule.js +26 -0
  300. package/dist/system/_style-segment.js +30 -0
  301. package/dist/system/_style-segmented-control.js +86 -0
  302. package/dist/system/_style-selected.js +36 -0
  303. package/dist/system/_style-stage-marks.js +26 -0
  304. package/dist/system/_style-tab.js +71 -0
  305. package/dist/system/_style-textarea.js +21 -0
  306. package/dist/system/_style-title.js +37 -0
  307. package/dist/system/_style-tooltip.js +17 -0
  308. package/dist/system/density.d.ts +15 -5
  309. package/dist/system/density.js +188 -25
  310. package/dist/system/index.d.ts +2 -2
  311. package/dist/system/index.js +2 -2
  312. package/dist/system/overrides.d.ts +1 -0
  313. package/dist/system/overrides.js +151 -3
  314. package/dist/system/portal.d.ts +3 -2
  315. package/dist/system/portal.js +22 -10
  316. package/dist/system/prepaint.d.ts +21 -5
  317. package/dist/system/prepaint.js +3 -1
  318. package/dist/system/published.d.ts +1 -0
  319. package/dist/system/published.js +131 -0
  320. package/dist/system/theme-provider.d.ts +168 -60
  321. package/dist/system/theme-provider.js +375 -79
  322. package/dist/system/theme-registry.d.ts +2 -1
  323. package/dist/system/theme-registry.js +27 -10
  324. package/dist/system/use-density.js +4 -3
  325. package/dist/system/use-theme.d.ts +5 -2
  326. package/dist/system/use-theme.js +7 -4
  327. package/dist/system/vocabulary.js +2 -2
  328. package/dist/theming/create-theme.js +12 -6
  329. package/dist/theming/serialize.d.ts +34 -2
  330. package/dist/theming/serialize.js +86 -4
  331. package/manifest/components/accordion.json +7 -1
  332. package/manifest/components/agent-pile.json +3 -0
  333. package/manifest/components/alert-dialog.json +38 -1
  334. package/manifest/components/app-bar.json +23 -2
  335. package/manifest/components/app-shell.json +5 -0
  336. package/manifest/components/ask-box.json +3 -1
  337. package/manifest/components/autocomplete.json +49 -1
  338. package/manifest/components/band.json +14 -3
  339. package/manifest/components/bento.json +12 -1
  340. package/manifest/components/breadcrumb.json +8 -1
  341. package/manifest/components/button.json +31 -3
  342. package/manifest/components/calendar.json +7 -0
  343. package/manifest/components/card.json +28 -1
  344. package/manifest/components/carousel.json +4 -1
  345. package/manifest/components/channel-matrix.json +40 -1
  346. package/manifest/components/chart-tooltip-content.json +38 -1
  347. package/manifest/components/chat-empty-state.json +3 -1
  348. package/manifest/components/checkbox-group.json +14 -0
  349. package/manifest/components/checkbox.json +14 -0
  350. package/manifest/components/chip.json +16 -1
  351. package/manifest/components/clamp.json +3 -1
  352. package/manifest/components/code-block.json +10 -1
  353. package/manifest/components/collapsible.json +13 -2
  354. package/manifest/components/color-area.json +4 -2
  355. package/manifest/components/color-field.json +14 -0
  356. package/manifest/components/color-picker.json +14 -0
  357. package/manifest/components/color-slider.json +3 -1
  358. package/manifest/components/colors-section.json +9 -1
  359. package/manifest/components/combobox.json +49 -1
  360. package/manifest/components/command-palette.json +37 -1
  361. package/manifest/components/composer-actions.json +3 -0
  362. package/manifest/components/composer-attach-button.json +3 -0
  363. package/manifest/components/composer-attachment-chip.json +3 -0
  364. package/manifest/components/composer-attachments.json +3 -0
  365. package/manifest/components/composer-bar.json +3 -0
  366. package/manifest/components/composer-command-item.json +3 -0
  367. package/manifest/components/composer-context.json +3 -0
  368. package/manifest/components/composer-input.json +3 -0
  369. package/manifest/components/composer-menu-item.json +3 -0
  370. package/manifest/components/composer-menu.json +3 -0
  371. package/manifest/components/composer-model-item.json +3 -0
  372. package/manifest/components/composer-model-trigger.json +3 -0
  373. package/manifest/components/composer-person-item.json +3 -0
  374. package/manifest/components/composer-send.json +3 -0
  375. package/manifest/components/composer-toolbar.json +3 -0
  376. package/manifest/components/composer-voice-button.json +3 -0
  377. package/manifest/components/composer-voice.json +3 -0
  378. package/manifest/components/composer.json +14 -0
  379. package/manifest/components/confidence-marker.json +3 -1
  380. package/manifest/components/container.json +2 -1
  381. package/manifest/components/context-menu.json +38 -1
  382. package/manifest/components/conversation-search.json +3 -1
  383. package/manifest/components/cue-mark.json +2 -2
  384. package/manifest/components/cue-portal-frame.json +1 -1
  385. package/manifest/components/data-row.json +3 -1
  386. package/manifest/components/data-tree.json +3 -1
  387. package/manifest/components/date-field.json +14 -0
  388. package/manifest/components/date-picker.json +14 -0
  389. package/manifest/components/date-range-picker.json +14 -0
  390. package/manifest/components/delegation-card.json +3 -1
  391. package/manifest/components/density.json +21 -7
  392. package/manifest/components/description-list.json +6 -1
  393. package/manifest/components/dialog.json +39 -1
  394. package/manifest/components/disclosure.json +13 -2
  395. package/manifest/components/dmx-bar.json +37 -1
  396. package/manifest/components/dmx-strip.json +37 -1
  397. package/manifest/components/drawer.json +38 -1
  398. package/manifest/components/dropdown-menu.json +38 -1
  399. package/manifest/components/edit-message.json +3 -1
  400. package/manifest/components/elements-command-palette.json +3 -1
  401. package/manifest/components/elements-composer.json +3 -0
  402. package/manifest/components/empty-state-composer.json +3 -1
  403. package/manifest/components/empty-state-greeting.json +3 -1
  404. package/manifest/components/empty-state-suggestion.json +3 -1
  405. package/manifest/components/empty-state-suggestions.json +3 -1
  406. package/manifest/components/env-var-input.json +14 -1
  407. package/manifest/components/export-dialog.json +6 -1
  408. package/manifest/components/eyebrow.json +13 -2
  409. package/manifest/components/feedback-dialog.json +3 -0
  410. package/manifest/components/field-description.json +14 -0
  411. package/manifest/components/field-error.json +14 -0
  412. package/manifest/components/field-label.json +15 -1
  413. package/manifest/components/field.json +14 -0
  414. package/manifest/components/file-upload.json +3 -0
  415. package/manifest/components/footer.json +14 -1
  416. package/manifest/components/frames.json +14 -1
  417. package/manifest/components/hover-card.json +38 -1
  418. package/manifest/components/info-tip.json +3 -0
  419. package/manifest/components/input-group.json +14 -0
  420. package/manifest/components/input.json +14 -0
  421. package/manifest/components/item.json +3 -1
  422. package/manifest/components/kbd.json +10 -1
  423. package/manifest/components/ledger.json +9 -2
  424. package/manifest/components/link.json +10 -0
  425. package/manifest/components/log-viewer.json +10 -0
  426. package/manifest/components/map-answer.json +3 -1
  427. package/manifest/components/markdown-text.json +3 -0
  428. package/manifest/components/menubar.json +41 -2
  429. package/manifest/components/message-list.json +10 -0
  430. package/manifest/components/message.json +6 -1
  431. package/manifest/components/mobile-composer.json +3 -1
  432. package/manifest/components/multi-select.json +49 -1
  433. package/manifest/components/musical-time-input.json +14 -0
  434. package/manifest/components/navigation-menu.json +41 -1
  435. package/manifest/components/node-card.json +3 -0
  436. package/manifest/components/number-field.json +14 -1
  437. package/manifest/components/otp-field.json +13 -0
  438. package/manifest/components/page-shell.json +14 -0
  439. package/manifest/components/pagination.json +3 -0
  440. package/manifest/components/panel-header.json +12 -0
  441. package/manifest/components/panel.json +13 -1
  442. package/manifest/components/password-input.json +14 -1
  443. package/manifest/components/permission-scopes.json +3 -1
  444. package/manifest/components/piano-keyboard.json +3 -0
  445. package/manifest/components/popover.json +39 -1
  446. package/manifest/components/preset-section.json +9 -1
  447. package/manifest/components/preview.json +30 -10
  448. package/manifest/components/progress.json +6 -1
  449. package/manifest/components/prompt-library.json +3 -1
  450. package/manifest/components/queue-dock.json +3 -1
  451. package/manifest/components/radio-group.json +8 -0
  452. package/manifest/components/radio.json +8 -0
  453. package/manifest/components/rating.json +4 -1
  454. package/manifest/components/reasoning-panel.json +3 -1
  455. package/manifest/components/recommendation-card.json +1 -1
  456. package/manifest/components/resizable.json +4 -1
  457. package/manifest/components/revert-dock.json +3 -1
  458. package/manifest/components/row.json +5 -1
  459. package/manifest/components/scroll-area.json +4 -2
  460. package/manifest/components/scrollable-tabs-list.json +19 -0
  461. package/manifest/components/scrub-input.json +14 -1
  462. package/manifest/components/seam-cell.json +1 -0
  463. package/manifest/components/seam-grid.json +1 -0
  464. package/manifest/components/seam-list.json +5 -1
  465. package/manifest/components/search-input.json +14 -1
  466. package/manifest/components/section-header.json +15 -2
  467. package/manifest/components/segmented-control.json +17 -0
  468. package/manifest/components/select.json +28 -0
  469. package/manifest/components/settings-panel.json +3 -0
  470. package/manifest/components/shape-section.json +9 -1
  471. package/manifest/components/sheet.json +38 -1
  472. package/manifest/components/shimmer-label.json +3 -0
  473. package/manifest/components/sidebar.json +19 -2
  474. package/manifest/components/slider.json +8 -0
  475. package/manifest/components/sources.json +3 -1
  476. package/manifest/components/stat.json +9 -0
  477. package/manifest/components/status-bar.json +4 -0
  478. package/manifest/components/stepper.json +8 -0
  479. package/manifest/components/swap-label.json +3 -0
  480. package/manifest/components/switch.json +8 -0
  481. package/manifest/components/table-scroll-region.json +20 -2
  482. package/manifest/components/table.json +20 -2
  483. package/manifest/components/tabs.json +20 -1
  484. package/manifest/components/tags-input.json +49 -1
  485. package/manifest/components/terminal-frame.json +3 -0
  486. package/manifest/components/textarea.json +16 -0
  487. package/manifest/components/theme-configurator.json +38 -1
  488. package/manifest/components/theme-provider.json +37 -19
  489. package/manifest/components/thread-search.json +3 -1
  490. package/manifest/components/threshold-rail.json +3 -0
  491. package/manifest/components/time-field.json +14 -0
  492. package/manifest/components/toast.json +39 -0
  493. package/manifest/components/toggle-group.json +1 -19
  494. package/manifest/components/toggle.json +3 -5
  495. package/manifest/components/token-editor.json +6 -1
  496. package/manifest/components/tool-call-card.json +9 -2
  497. package/manifest/components/tool-call.json +3 -1
  498. package/manifest/components/tool-timeline.json +3 -1
  499. package/manifest/components/toolbar.json +4 -1
  500. package/manifest/components/tooltip.json +40 -1
  501. package/manifest/components/tree-visibility-toggle.json +3 -0
  502. package/manifest/components/tree.json +3 -0
  503. package/manifest/components/universe-grid.json +3 -0
  504. package/manifest/components/voice-conversation.json +3 -0
  505. package/manifest/components/work-collapse.json +3 -1
  506. package/manifest/manifest.json +205 -185
  507. package/manifest/tokens.json +260 -4
  508. package/package.json +6 -6
package/CHANGELOG.md CHANGED
@@ -1,5 +1,1088 @@
1
1
  # @cueplusplus/ui
2
2
 
3
+ ## 0.17.0
4
+
5
+ ### Minor Changes
6
+
7
+ - a6afdd2: Graphite's round of the looks-fidelity work (spec §10.4, lane L5): ten more optional style names, and `band-y`'s rule admits a rem-plus-vw ramp.
8
+
9
+ **Ten optional names** join the style contract — `style-control-case` (a control's text-transform: `uppercase`, `none` or `capitalize`), `style-lede-ink` (a lede's ink apart from the prose ink), `style-band-title-size`, `-weight` and `-leading` (a band heading's own voice apart from the docs heading rung; the size scales with `--cue-font-scale` like every reading size), `style-subheading-leading`, `style-appbar-inset` (a proportion of `space-7`), `style-nav-active-ground` (the sidebar's active item, apart from a table's selected row), and `band-y-top` / `band-y-bottom` (the band rhythm's two halves, each falling back to `band-y` at its reader). Each is `initial` on the shared `[data-style]` reset, which grows from 99 lines to 109, and every set block is byte-identical apart from those ten lines. `console` declines all ten.
10
+
11
+ **`band-y`'s rule, widened once for it and both halves:** a `clamp()`'s middle term may now be a rem plus a vw expression (`3.8286rem + 6.8571vw`), the form a rung proportion already admits, as well as a bare vw term. The bounds are still `space-7` or a multiple of it, never `--cue-density`.
12
+
13
+ **The `graphite` style set, re-measured against agent-native.com** (spec §10.3–§10.4). Its reading measure is 53ch (the source's 633px lede column), its seam a 54% share of `--cue-border` in `srgb`, the share whose painted pixel lands inside ΔE00 3 of the source's subtle line in Chromium and WebKit (60% in `oklch` painted the light seam pink, and 55% painted #e0dedc in Chromium, 3.86), and its input face sans (the one field a visitor types into is sans). It now declares the round's type and control voice at the source's own pixels: a 46px/500/1.05 band title and display weight, a 32px/600 page title and 24px/600 heading at −0.02em, 18px (16px on a phone) card titles at 1.15, ledes at 16–18px in `fg-muted` with body prose in `fg`, 12px mono captions at 600 and 0.02em, 12px help, uppercase 600-weight buttons at 0.02em, a 2px focus offset, a `fg-subtle` outline edge, sans 15px/500 nav links that hover to `fg`, a transparent sidebar active ground at weight 500, dialogs on the page ground at a 12px corner, a 64px header with 40px (24px on a phone) of inline padding, and bands 160px above and 80px below (88/32 on a phone) through `band-y-top`/`band-y-bottom`. `band-y` itself is unchanged, so a `Footer` stays symmetric.
14
+
15
+ **The `bevel` paint pack draws one flat ink per surface kind** (F-19): recessed controls and cards are edged in `border-overlay` at both ends of the stroke, overlays in `border`, where it used to spend a 140° gradient on every surface. Its glass is `bg` at 90% in `srgb` (exactly the page colour), and its overlay shadow is the chassis stop at twice its geometry with a −12px spread, cast in 25% of the theme's `shade` role (F-24) — black under `theme-graphite`, which authors `shade: #000000`; under a theme that authors no `shade`, 25% of `fg`, where it used to be black at 40%. A consumer choosing `bevel` for its gradient now gets a flat edge.
16
+
17
+ These names are read by the `@cueplusplus/ui` components of the same release: `Button` takes its case from `style-control-case`, `PageShell`'s subtitle its ink from `style-lede-ink`, `AppBar` its inline padding from `style-appbar-inset` (40px, 24px on a phone, under `graphite`; `space-5` under every other set), the `Sidebar`'s active item its ground from `style-nav-active-ground` (transparent under `graphite`, so the item shows by its ink and weight alone; the selected ground under every other set), and `Band` its top and bottom padding from `band-y-top` and `band-y-bottom` (`Footer` keeps `band-y`); the band title and subheading leading are read by the docs site's own headings. Paired with an older `@cueplusplus/ui`, the graphite set's values for them are declared and inert. `@cueplusplus/ui`'s component manifest (`manifest/tokens.json`) lists the ten names beside the rest of the style vocabulary.
18
+
19
+ - d205951: The looks-fidelity round's four contract PRs (P0.4–P0.7): a theme may now author four derived colour roles, the style axis gains 95 optional names, the paint axis gains a scrim filter and three more inks, and a theme's density override is gated for monotonicity.
20
+
21
+ **Four derived colour roles a theme may author per mode (spec §3.9).** `accent-fill`, `accent-fill-fg` and `accent-fill-hover` let a theme give its primary button a fill distinct from `accent` itself (unauthored, each still resolves to its `accent`/`accent-fg`/`accent-hover` anchor); `shade` gives a theme a shadow ink independent of `fg`. `Button`'s primary tone now reads `bg-accent-fill text-accent-fill-fg hover:bg-accent-fill-hover` — a no-op everywhere, since none of the fifteen shipped presets authors the trio. `accent-fill-fg/accent-fill` is a new required contrast pair (4.5:1); `accent-fill/bg` is advisory (3:1). Four presets — `theme-hivehub`, `theme-luma`, `theme-signal`, `theme-venu` — already waive `accent-fg/accent` and now waive the identical, unauthored `accent-fill-fg/accent-fill` failure beside it, at the same ratio.
22
+
23
+ **The style axis's contract, round 2 (spec §3.0–§3.11): 95 more optional names**, covering display/title/heading voice, body/prose/label/eyebrow/chip/kbd voice, control/focus/link voice, navigation/selection/tab/menu voice, and surface proportions. Every one is optional and every one is declined by all eight shipped style sets today — no rendered change. The shared `[data-style]` reset now emits `initial` for all 99 optional names once, ahead of every specific `[data-style="x"]` block, replacing the per-block restatement each set used to carry; a set's own block now declares only what it authors.
24
+
25
+ **The paint axis, round 2 (spec §3.10): five more names on every pack.** `paint-scrim-filter` (a modal scrim's own backdrop-filter, distinct from `paint-glass-filter`), `paint-rest-shade` (a resting-surface shadow fragment, `system/_paint-rest-shade.ts`), `paint-stroke-overlay-from`/`-to` (an overlay's own stroke ink, read by `_paint-stroke-surface-2.ts` in place of the shared `paint-stroke-from`/`-to`), and `paint-danger-glow-ink` (the danger button's own glow, `GLOW_DANGER_CLASSES`). All ten packs declare all five; nine of them restate their own existing stroke pair for the new overlay ink (no rendered change). **`none` is the one deliberate change (F-10):** its overlay stroke pair is now `var(--cue-border-overlay)`, closing a gap where an overlay's edge under `none` differed from what a page with no pack at all draws — on the docs site, a Classic overlay's edge now reads `border-overlay` instead of `border`. The overlay's fill layer also gains `style-overlay-ground` as a reader (spec §3.11), falling back to the existing `--cue-surface-2`. **`paint-scrim-filter` lives on a `::before` pseudo-element of the scrim, never on the scrim's own `backdrop-filter`:** every overlay's `backdropClassName` prop feeds a consumer's own backdrop utility onto that same element, and a raw `backdrop-filter` declaration there made a consumer's `backdropClassName="backdrop-blur-sm"` compute `none` instead of a blur — a regression this release did not ship with, caught before publish.
26
+
27
+ **Density override gates (spec §4.2, F-7, F-8).** A theme's `densities.overrides` may now retune only `control-sm`/`-md`/`-lg`, `text-ui`, `text-body` and `radius-control`/`-surface`/`-overlay` — never `chrome-toolbar`, `text-label` or `space-*` — and must cover all five rungs, monotonically (strictly increasing, a constant `0` radius excepted) at both 390px and 1440px, with `control-sm <= control-md <= control-lg` holding within each rung. This is stricter than before: a single-rung override, or one of a token outside that list, built without complaint and now refuses at `buildTheme`. `@cueplusplus/theme-tools` exports `deriveRungs(normal, token)`, which derives the other four rungs' values from a theme's own `normal` value and the base ladder's own ratios, and a theme that overrides `control-sm`/`-md`/`-lg` at `ultra-compact` now gets its own coarse-pointer re-raise (`max(<the base compact floor>, <the theme's own value>)`) instead of falling back to the base ladder's. The re-raise is written under the same selectors as the theme's own `ultra-compact` rule, including the ones that reach an island still carrying `data-cue-follows` before it mounts, so under a coarse pointer such an island is held to the same floor as the settled one.
28
+
29
+ **`@cueplusplus/theme-base`'s `validateManifest` gained a real shape check on every geometry value (spec §4.2, F-8), where it previously accepted any non-empty string.** A value now has to be a unitless number, a `rem`/`px` length, the font-scale `calc()` a text rung carries, or a `clamp()`/`min()`/`max()` of `rem`/`px`/`vw` terms (plain, or wrapped in that same `calc()` for a `text-ui`/`text-body` override, per spec §4.3) — this is what makes the Zine and Porcelain Looks' clamp-shaped text rungs admissible at all. It also means a hand-written or foreign manifest (one built by something other than `@cueplusplus/theme-tools`) carrying a geometry value outside this shape — `0.625em`, `calc(1rem + 2px)` — now fails `validateManifest`, and `ThemeProvider` throws on it in development where it previously did not. No first- or third-party manifest this repository builds authors such a value.
30
+
31
+ None of the fifteen shipped theme packages (`cue`, `dusk`, `graphite`, `hivehub`, `kiln`, `luma`, `porcelain`, `quotamate`, `requestport`, `signal`, `snuffle`, `tender`, `terminal`, `venu`, `zine`) authors any of the new derived roles, style names or paint names, or overrides a density, so every one is unchanged but for the four derived-colour lines every `theme.css` block now carries.
32
+
33
+ **`@cueplusplus/studio-mcp`: a studio document may set the four derived colour roles.** The catalogue a document is validated against is the published `/r/tokens.json`, whose colour list is 48 names now (44 before `accent-fill`, `accent-fill-fg`, `accent-fill-hover` and `shade`).
34
+
35
+ - 7884cb4: The type voice reads the style set: a page title, a card, panel, bento or overlay title, body
36
+ copy, figures and field help text can each be restyled by a Look without a class at the call
37
+ site.
38
+
39
+ Every one of these sites now reads an optional `--cue-style-*` name through a `var()` whose
40
+ fallback is exactly what it rendered before. No shipped set (`console`, `editorial`,
41
+ `marketing`, `graphite`, `tender`, `zine`, `kiln`, `porcelain`) declares any of these 21 names
42
+ yet, and a set that does not declare one leaves its readers on their fallbacks, so the new names
43
+ change nothing under no style set or under any shipped set.
44
+
45
+ One change is visible under three shipped sets, and it is intended: **`FieldDescription` and
46
+ `FieldError` now take their label's face.** They read `--cue-style-label-face` like
47
+ `FieldLabel` above them, and that is a name every set declares. Under `tender`, `kiln` and
48
+ `porcelain` it is `var(--cue-font-sans)`, so a field's help text and its error move from mono to
49
+ the Look's sans, matching the label. Under no set and under `console`, `editorial`, `marketing`,
50
+ `graphite` and `zine` they stay mono.
51
+
52
+ - **`PageShell`'s title** reads `--cue-style-page-title-face`, `-size`, `-weight`, `-tracking`
53
+ and `-leading` (mono, `--cue-text-title`, 500, `normal`, inherited), plus
54
+ `--cue-style-display-variation` (`normal`) and `--cue-style-heading-ink` (`fg`).
55
+ - **`CardTitle`, `PanelHeader`'s title and `Bento.Tile`'s title** read the title voice:
56
+ `--cue-style-title-face`, `-size`, `-weight`, `-tracking` and `-leading` (mono,
57
+ `--cue-text-emphasis`, 500, `normal`, inherited), the variation and the heading ink.
58
+ - **`overlayTitleClasses`** (Dialog, AlertDialog, Drawer, Sheet and Popover titles) reads the
59
+ title face, weight, variation and heading ink at its own `--cue-style-overlay-title-size`
60
+ (`--cue-text-emphasis`).
61
+ - **`CardDescription`, `overlayTextClasses`, `overlayDescriptionClasses` and `PageShell`'s
62
+ subtitle** read `--cue-style-body-face` (mono) and `--cue-style-body-weight` (inherited). The
63
+ subtitle is a lede: it also reads `--cue-style-lede-size` (`--cue-text-ui`) and its ink as
64
+ `var(--cue-style-lede-ink, var(--cue-style-prose-ink, var(--cue-fg-muted)))`.
65
+ - **`Stat`'s value and detail, `Table`, `Row` (`rowVariants`), `Bento.Tile`'s eyebrow and
66
+ `SectionHeader`'s count** read `--cue-style-data-face` (mono). `tabular-nums` stays.
67
+ - **`FieldDescription` and `FieldError`** wear the label face (`--cue-style-label-face`: mono by
68
+ default, the sans under `tender`, `kiln` and `porcelain`, as above) and read
69
+ `--cue-style-help-size` (`--cue-text-micro`); the description's ink reads
70
+ `--cue-style-help-ink` (`fg-subtle`), and the error keeps `danger`.
71
+ - **The recessed control chassis** (`controlSurface`, `bareControlClasses`) reads
72
+ `--cue-style-body-weight` (inherited).
73
+
74
+ The public class constants `overlayTitleClasses`, `overlayTextClasses`,
75
+ `overlayDescriptionClasses`, `controlSurface`, `bareControlClasses` and `rowVariants` change
76
+ their strings accordingly. `className` still overrides as before: the weight readers are written
77
+ `font-[number:…]`, so a caller's `font-bold` or `font-semibold` replaces them through `cn()` as it
78
+ replaced `font-medium`.
79
+
80
+ - 5d75ae7: Captions, the eyebrow, chips and key caps read the style set's round-2 names (spec
81
+ 2026-09-26-looks-fidelity §3.6, lane R2) — fifteen optional names, each falling back to exactly
82
+ what its reader rendered before. No shipped set declares any of the fifteen, so they move nothing
83
+ yet. What does move under shipped sets is a handful of readers that now read a face, case or
84
+ tracking name those sets already declare:
85
+
86
+ - **Under `tender`, `kiln` and `porcelain`** (a sans label face, no label case, `normal` label
87
+ tracking): a chip's face and case (sans, sentence case — F-15 below); the face of `StatusBar`,
88
+ its interactive items included, of `Table.Caption` and of the `Progress` header (sans); and the
89
+ `Progress` label's case (sentence case) and, under `tender` and `kiln`, its tracking (`normal`
90
+ in place of their caps rung; `porcelain`'s caps rung is already `normal`).
91
+ - **Under `tender`, `kiln`, `porcelain` and `zine`** (a sans control face): `Kbd`'s face (F-16
92
+ below).
93
+
94
+ Under no set, `console`, `graphite`, `editorial` and `marketing`, nothing renders differently —
95
+ except a `Table.GroupRow` given a weight in its `className`, whose name now takes it (below).
96
+
97
+ - **Label size, ink and weight.** `FieldLabel`, a `SectionHeader` label, a table head and group
98
+ row, a `Sidebar.Section` label, a `Stat` label and a menu group label read
99
+ `--cue-style-label-size`, `-ink` and `-weight`; the `Checkbox` and `Switch` labels read the ink
100
+ and the weight. Each keeps its own fallback: the label rung (the micro rung for `Stat`),
101
+ `fg-muted` or `fg-subtle`, and the inherited weight (`400` on a table head, whose `<th>` is bold
102
+ in the user-agent sheet). A caller's `className="font-medium"` still wins, as it did over
103
+ `font-normal`. A `Table.GroupRow`'s name now inherits its cell's weight instead of pinning
104
+ `font-normal`, so a set's label weight moves the whole row, and a weight in the row's
105
+ `className` (which lands on the cell) now reaches the name as well as the count.
106
+ - **The eyebrow** reads `--cue-style-eyebrow-face`, `-size`, `-ink` and `-weight`, falling back
107
+ through the label names to mono, the label rung, the accent and the inherited weight; and
108
+ `--cue-style-eyebrow-glyph: none` drops the `//` slashes (`inline` by default).
109
+ `slashes={false}` still removes them from the markup under any set.
110
+ - **Chips read the label face** (`--cue-style-label-face`) and **their case through
111
+ `--cue-style-chip-case`**, which falls back to the label case. This reverses the earlier "a
112
+ tag's text is the value being shown" ruling (F-15): under a sans, sentence-case Look a chip is
113
+ now sans and sentence case like the captions around it. Under no set and under `console`,
114
+ `editorial`, `marketing`, `graphite` and `zine` it is still mono and uppercase; pass
115
+ `className="font-mono uppercase"` to keep a chip mono under every set. Its tracking, size and
116
+ radius read `--cue-style-chip-tracking`, `-size` and `-radius`, and each tone's fill and rim are
117
+ a share a set can move: `color-mix(in oklab, var(--cue-<tone>) var(--cue-style-chip-fill, 10%),
118
+ transparent)` and the same at `--cue-style-chip-edge, 35%` — exactly `bg-<tone>/10` and
119
+ `border-<tone>/35` by default. `neutral` keeps its own inks.
120
+ - **`Kbd` wears the control face** (`--cue-style-control-face`, mono by default) rather than a
121
+ fixed mono (F-16) — so it is sans wherever controls are: under `tender`, `kiln`, `porcelain` and
122
+ `zine` — and reads `--cue-style-kbd-edge` for its rim, the chip's
123
+ `--cue-style-chip-size` and `--cue-style-label-weight`.
124
+ - **`StatusBar`, `Table.Caption` and the `Progress` header** read the label face, and the
125
+ `Progress` label the label case and tracking, instead of a fixed `font-mono`, `uppercase` and
126
+ caps tracking. An interactive `StatusBar.Item`, a `<button>` that restates the bar's face
127
+ because form controls inherit no type, restates the label face too, so one bar never mixes two
128
+ faces.
129
+
130
+ The shadcn registry's `@cue/eyebrow` ships the new label and eyebrow modules and `@cue/chip`
131
+ ships `_style-chip.ts`; `@cue/chip` now depends on `@cue/eyebrow`, which owns the label modules
132
+ it imports.
133
+
134
+ - 5d75ae7: Navigation, selection, segments, tabs, menus and section rules take their voice from the style
135
+ set, so a Look can restyle a header, a sidebar, a tab strip or a menu without a class at every
136
+ call site. Every reader falls back to exactly the class it replaced, and no shipped style set
137
+ declares any of the new names yet, so nothing renders differently under no style set, and under
138
+ the shipped sets one thing does: **`Footer`'s fine print** (`meta`) is now set in the label face
139
+ rather than always in mono, so under `tender`, `kiln` and `porcelain`, whose label face is sans,
140
+ it is sans; under every other set it is mono as before.
141
+
142
+ - **`AppBar`.** The bar reads `--cue-style-appbar-height`, `--cue-style-chrome-rule` (its bottom
143
+ rule's ink) and `--cue-style-appbar-inset` (its inline padding). `AppBar.Link` reads the
144
+ navigation voice — `--cue-style-nav-face`, `-case`, `-tracking`, `-size` and `-weight`, falling
145
+ back to mono at the UI size — plus `--cue-style-nav-pad`, `--cue-style-nav-hover-ground`,
146
+ `--cue-style-hover-ink`, and `--cue-style-quiet-ink` for the `muted` register.
147
+ - **`Footer`** sets its column in the same navigation voice, reads `--cue-style-footer-rule` for
148
+ its top rule's width and `--cue-style-section-rule` for the rule over its fine print, which is
149
+ set in the label face. **`SectionHeader`**'s hairline reads `--cue-style-section-rule`.
150
+ - **`Sidebar.Item`** reads `--cue-style-nav-ink` at rest; the current page reads
151
+ `--cue-style-nav-active-ground`, then `--cue-style-selected-ground`, for its ground, and
152
+ `--cue-style-selected-ink` and `--cue-style-selected-weight`. A selected **`Table.Row`** reads
153
+ `--cue-style-selected-ground` and `--cue-style-selected-ink`, so a Look that inverts a
154
+ selection inverts its ink with it.
155
+ - **`SegmentedControl`** and **`Tabs`** share the segment names: `--cue-style-segment-track` and
156
+ `--cue-style-segment-inset` on the track — `SegmentedControl`'s rounded frame, whose own
157
+ `surface-1` ground and `space-1` padding are the fallbacks, and the `Tabs` list, which has
158
+ neither — `--cue-style-segment-idle-ink` on an unpicked choice,
159
+ and `--cue-style-segment-ground`, `-ink`, `-edge` and `-weight` on the pressed segment and the
160
+ active tab, which also carry the paint axis's resting shade (`--cue-paint-rest-shade`). A
161
+ segment's corners nest inside the track's inset. `Tabs` reads `--cue-style-tab-rule` and
162
+ `--cue-style-tab-underline` for its rule and the active underline.
163
+ - **Menu rows** (`DropdownMenu`'s items, and anything built on the exported `menuItemClasses`)
164
+ read `--cue-style-quiet-ink` at rest and `--cue-style-menu-highlight` when highlighted. The
165
+ exported `menuItemClasses` string no longer contains `text-fg-muted` or
166
+ `data-[highlighted]:bg-accent-soft`: code that edits it with `.replace()` on either finds
167
+ nothing to replace. Override those through `className` (or append a class) instead.
168
+ - **A `className` still wins over each of them**, as it won over the class each replaced: a
169
+ caller's `font-medium` on an `AppBar.Link` or `Footer`'s `columnClassName`, and a caller's
170
+ weight, ground, shadow or ink on a `Sidebar.Item`, a `SegmentedControl` item, a `Tabs.Tab` or
171
+ a `Table.Row`, applies to the current, pressed, active or selected one too. The readers of
172
+ what those states never set before — their weight, the active tab's ground, the pressed
173
+ segment's and active tab's shadow, the selected row's ink and a link's hover ground — sit at
174
+ zero specificity (`:where()`), so any class beats them.
175
+
176
+ `--cue-style-appbar-inset` and `--cue-style-nav-active-ground` are read now and join the style
177
+ contract in a later release; until then no set declares them.
178
+
179
+ - 7884cb4: Surfaces and proportions read the style set (looks-fidelity round, lane R5). Every reader falls back to what the site drew before, so nothing changes under no style set or any shipped set until a Look declares a value.
180
+
181
+ - **`Card`**: every side of `Card.Header`, `Card.Content` and `Card.Footer` pads `--cue-space-5` times `--cue-style-card-pad` (1 by default), seamed or not.
182
+ - **`Dialog`**: the popup's corner reads `--cue-style-dialog-radius` over the overlay rung, times `--cue-radius-scale`. Every other overlay keeps `rounded-overlay`.
183
+ - **`Band`**: a `width="broad"` column reads `--cue-style-band-width` over `--cue-measure-broad`, and `Band` spends the rhythm's two halves, `--cue-band-y-top` and `--cue-band-y-bottom`, each falling back to `--cue-band-y`. `Footer` is unchanged and stays symmetric, `Container` keeps its broad rung, and a `className="py-0"` still zeroes a band.
184
+ - **`Preview`**: a frame's four registration marks read `--cue-style-stage-marks`, so a set that says `none` takes them away.
185
+ - **`Card` and `Panel`**: the paint axis's resting shade, `--cue-paint-rest-shade`, is now the second layer of their shadow, transparent under every shipped pack.
186
+
187
+ Rendered no-ops, measured: computed styles match the pre-change snapshot in both engines, and Card and Panel are pixel-identical under all ten paint packs. The one visible difference is in the markup. The longer class strings add about 2% to the HTML of pages that render many of these components.
188
+
189
+ - e56ebf3: Round 2 of the Looks fidelity work added the readers its five Looks' fix lanes asked for. Every new reader falls back to the class it replaced. No shipped style set declares any of the new names yet, so no set renders differently through a new name. A shipped set does render differently at the sites below, where an existing name is now read. Each change follows the set's own voice.
190
+
191
+ - **Label voice at four more captions.** These are `CodeBlock`'s label, `TerminalFrame`'s title, `Footer`'s meta row and a `Frames.Item` caption. They read `--cue-style-label-size` and `--cue-style-label-ink`. A frame's caption also reads the label face and tracking, and a new optional `--cue-style-caption-case`. Under `tender`, `zine`, `kiln`, `porcelain` and `graphite` they take each set's label size, and each set's label ink where it has one.
192
+ - **Body weight.** `--cue-style-body-weight` now also reaches `FieldDescription`, `FieldError`, an unselected `Select` or combobox row, and the label beside a `Switch`, a `Checkbox` or a `Radio`. The control label falls back to `--cue-style-label-weight`. Under `tender` these are 300.
193
+ - **`Radio`'s label** reads the label ink and weight as `Checkbox`'s does.
194
+ - **The disclosure trigger.** `Accordion`, `Collapsible` and `Disclosure` read the control face, the quiet ink and the label weight.
195
+ - **`Select` and the filterable lists.** Their rows read `--cue-style-menu-highlight` (kiln's is `transparent`). The select's popup now uses the overlay recipe that every other popup uses, `STROKE_SURFACE_2`, so it reads `--cue-style-overlay-ground` and the pack's overlay stroke. Under no pack this draws the same pixels as before.
196
+ - **Help ink and size.** `Table.Caption` and the breadcrumb separator read `--cue-style-help-ink`. `Tooltip` reads `--cue-style-help-size`.
197
+ - **Other existing names at new sites.**
198
+ - The `PageShell` subtitle reads `--cue-style-prose-tracking`, which `kiln` and `zine` declare.
199
+ - The underline's hover colour reads `--cue-style-hover-ink`.
200
+ - Idle tabs read `--cue-style-segment-weight`, which `porcelain` sets to 500.
201
+
202
+ New optional names, each read at the sites named and falling back to what the site drew:
203
+
204
+ - **Type**
205
+ - `--cue-style-body-size` and `--cue-style-body-leading`: descriptions, tables, the breadcrumb, field help and the tooltip.
206
+ - `--cue-style-description-leading` and `-tracking`: `Card.Description`.
207
+ - `--cue-style-lede-leading`: the `PageShell` subtitle.
208
+ - `--cue-style-overlay-title-leading`, `--cue-style-label-leading` and `--cue-style-input-leading`.
209
+ - `--cue-style-code-weight`: `CodeBlock`.
210
+ - `--cue-style-title-variation`: the card, panel and bento titles, ahead of the display variation.
211
+ - `--cue-style-control-step-size`: the `sm` and `lg` fields and the `lg` button.
212
+ - **Inks**
213
+ - `--cue-style-option-ink` and `-option-selected-ink`: select and list rows.
214
+ - `--cue-style-secondary-hover-ink` and `-hover-edge`: the secondary tone under the pointer.
215
+ - `--cue-style-segment-rim`: `SegmentedControl`'s frame.
216
+ - **Geometry**
217
+ - `--cue-style-field-focus-offset`: the field ring.
218
+ - `--cue-style-gutter`: a padded `Container`.
219
+ - `--cue-style-chip-height` and `-chip-pad`.
220
+ - `--cue-style-kbd-size`, `-kbd-height`, `-kbd-pad` and `-kbd-radius`.
221
+ - `--cue-style-check-radius` and `-check-size`.
222
+ - `--cue-style-menu-item-radius`: menu, select and list rows.
223
+ - `--cue-style-tab-radius`: pill tabs on a rounded track.
224
+ - `--cue-style-tooltip-pad`, `--cue-style-row-pad`, `--cue-style-collapse-height`, `--cue-style-popover-pad` and `--cue-style-textarea-pad`.
225
+ - **`Card`'s stroke** reads the new `--cue-paint-stroke-raised-from` and `-to` ahead of the shared pair.
226
+
227
+ Three changes have no new name:
228
+
229
+ - `PageShell`'s title wraps a word too long for its column (`overflow-wrap: anywhere`).
230
+ - A `Panel` header's title clips only on the inline axis, so a tight title leading no longer cuts its descenders.
231
+ - A ground `Band` masks its grain with its own ground, so a transparent ground no longer lays a second grain over the page's.
232
+
233
+ - f2c514d: The first frame of a page is the visitor's theme, mode, density and type size everywhere on it —
234
+ nested theme islands, `Preview` stages and density islands included — not the app's defaults.
235
+
236
+ Under a root `ThemeProvider` that persists (the default), `prepaintScript()` puts the visitor's
237
+ stored preferences on `<html>` before the page paints, and the root restates nothing of its own
238
+ until it has restored them. Three things still painted the app's defaults until they hydrated —
239
+ on a streamed page, for as long as their part of the page took to arrive:
240
+
241
+ - **A nested provider or stage that names one of theme and mode and not the other.** A theme's
242
+ light palette is keyed on `data-theme` and `data-mode` together, so such an island stamps the
243
+ other beside it, and in the server's HTML the only value it had was the root's prop. A visitor
244
+ who chose dark in an app whose default is light saw every `<ThemeProvider theme="…">` island and
245
+ every `<Preview theme="…">` stage light, at the default density; one whose stored theme was not
246
+ the default saw every `<ThemeProvider mode="…">` island in the default theme.
247
+ - **A density island's theme stamp.** A nested provider that names only a density, a `<Density>`
248
+ island and a `<Preview density="…">` stage stamp the theme around them as `data-cue-theme`, which
249
+ a theme's own density retunes are addressed through; the stamp was the root's default theme.
250
+ - **The type scale.** `fontScale` is published on the root's own element, but until the root has
251
+ restored, the text-size tokens the page reads are declared on `<html>`, which carried no scale:
252
+ every word set by a text token was drawn at 1× on the first frame and at the root's scale after.
253
+
254
+ What changes:
255
+
256
+ - **`@cueplusplus/ui`:** until it has mounted, an island leaves out any theme, mode or density it
257
+ would have copied from a persisting root (and the inline `color-scheme` that goes with them), and
258
+ carries `data-cue-follows` naming what it left out (`"mode density"`, `"theme"`, …). Its own
259
+ layout effect then stamps exactly the attributes it stamped before, ahead of the first paint once
260
+ it runs, and the marker goes. Anything the server does know is stamped from the first render as
261
+ before: an axis the island names itself, one named by a provider, `<Density>` island or stage
262
+ between it and the root, and everything under a root with `persistPreferences={false}`. If you
263
+ read these attributes off a nested provider's element before it hydrates, read `<html>`'s instead;
264
+ if you have written CSS of your own keyed on them, it will not reach such an island until it has
265
+ mounted (see **Migrating**). `overrides.colors` follows too: while the mode is `<html>`'s — a
266
+ persisting root before its restore, an island before its mount — the colour edit is a `<style>`
267
+ beside the element keyed on `<html>`'s mode (carrying `nonce`), not the inline block for the
268
+ root's default mode, so the first frame never pairs one mode's palette with the other mode's edit;
269
+ after the restore or the mount it is inline, as before. A nested provider with `asChild` over a
270
+ component, rather than a host element, follows nothing and stamps the root's values as before: the
271
+ re-render at its mount would render the component again, and a `<Suspense>` boundary it creates
272
+ would lose its streamed HTML.
273
+ - **`prepaintScript({ fontScale })`, new:** pass the same number as `<ThemeProvider fontScale>`, and
274
+ the script writes it on `<html>` as `--cue-font-scale`, where the first frame's text tokens are
275
+ declared; the root keeps it there after hydration, and takes it off when it unmounts. Omitted or
276
+ `1`, the script is exactly what it was. An app with a root `fontScale` other than `1` has to pass
277
+ it to get a first frame at that scale.
278
+ - **`createTheme()`, the `ThemeConfigurator`'s override stylesheet and `overrides.densities`** gain
279
+ the same selectors as a packaged theme (below), so a generated theme, a configured one and a
280
+ density override reach such an island too.
281
+ - **`themeSelector(name, { follows: true })`, new:** the same selectors for a theme assembled by
282
+ hand with `serializeThemeCss()`/`serializeThemeBlock()` — pass it for every block, or such an
283
+ island paints that theme's dark block for a light visitor until it mounts. `createTheme()` writes
284
+ exactly this. `mode` now also takes `"system"`, for the block inside each
285
+ `prefers-color-scheme` query; `follows` with both a light or system `mode` and a `density` throws.
286
+ - **`@cueplusplus/theme-tools`, and every theme package regenerated with it:** each `theme.css`
287
+ gains one selector line in front of each colour block — two in front of its light and system
288
+ blocks — and, for a theme that retunes or adds a density, in front of each density rule, that
289
+ matches such an island by `<html>`'s theme, mode or density and the island's marker, e.g.
290
+ `:where(:root[data-mode="light"]) [data-theme="x"][data-cue-follows~="mode"]`. No colour or
291
+ value moves, and each block keeps its specificity. A `data-theme` you stamp by hand, with no
292
+ mode beside it, is untouched: only the library's islands carry the marker. A theme with no light
293
+ palette (`supportsLight: false`, from theme-tools or `createTheme()`) now declares
294
+ `color-scheme: dark` in its two system blocks rather than `light dark`, as the pre-paint script
295
+ and the provider already said for it.
296
+ - **`@cueplusplus/tokens`:** each density rule in `axes.css`, and the coarse-pointer floor, gains the
297
+ same kind of line, so an island that is following the root's density declares that density
298
+ itself — its text tokens at its own `fontScale`, not the page's. The shadcn registry's
299
+ `registry/token-layer.json` keys its density rules the same way (the selector list `axes.css`
300
+ writes, `", "`-joined), so a registry install reaches such an island too.
301
+ - **`@cueplusplus/theme-base`:** `base.css`'s light and system blocks gain the line too, for the
302
+ tokens a `delta` theme's light palette leaves to the base.
303
+
304
+ ## Migrating
305
+
306
+ The new runtime and the new stylesheets ship as one change, and nothing but you ties their versions
307
+ together: the theme packages version on their own and peer only on `@cueplusplus/theme-base`, so
308
+ `pnpm up @cueplusplus/ui` alone leaves every `theme.css` you have where it was. With an older
309
+ stylesheet, an island that follows `<html>`'s mode matches no light block until it mounts, and
310
+ paints its theme's dark block for every visitor whose mode is light — on a streamed page, for as
311
+ long as its part of the page takes to arrive. Before, it painted the app's default mode, which was
312
+ right for exactly those visitors. So, in the same change as this upgrade:
313
+
314
+ - **Upgrade every `@cueplusplus/theme-*` package you register, and `@cueplusplus/theme-base`,** to
315
+ the releases that ship with this one: `pnpm up "@cueplusplus/theme-*"`.
316
+ - **A theme package you built with `@cueplusplus/theme-tools`:** upgrade `theme-tools`, run the
317
+ package's `generate` again, and ship the `theme.css` it writes.
318
+ - **CSS you emitted from `createTheme()`, `serializeThemeCss()`/`serializeThemeBlock()` or the
319
+ `ThemeConfigurator`'s CSS export and committed:** emit it again with this release.
320
+ `createTheme()` and the configurator write the new selectors themselves; a block you assemble
321
+ with `themeSelector()` gets them from `follows: true`.
322
+ - **Overrides of your own keyed on `[data-theme]`, `[data-mode]` or `[data-density]`:** put the twin
323
+ line in front of each compound (`docs/CONSUMING.md` §4 has the three forms), or they reach such an
324
+ island only once it has mounted.
325
+ - **Snapshots of server-rendered markup:** a nested provider, a stage or a `<Density>` island under
326
+ a persisting root no longer carries the `data-mode`, `data-theme`, `data-density` or
327
+ `data-cue-theme` it follows until it mounts, and carries `data-cue-follows` instead; a provider
328
+ with `overrides.colors` there carries `data-cue-colors`, with a `<style data-cue-colors-for>`
329
+ beside it. The DOM after hydration is what it was. Re-record them, and read the document's axes
330
+ off `<html>` before hydration.
331
+ - **A root `fontScale` other than `1`:** pass the same number to `prepaintScript({ fontScale })`.
332
+
333
+ - 0d26a0c: Radii resolve at the element that draws them, a `Preview` stage that names a theme restates the
334
+ rung in force around it, and every focus ring library-wide reads the theme's contrast-gated
335
+ `focus` role instead of `accent`.
336
+
337
+ - **`rounded-(--radius-control|surface|overlay)` is gone; the library reads the compiled
338
+ `rounded-control` / `rounded-surface` / `rounded-overlay` utilities instead** (spec
339
+ 2026-09-26-looks-fidelity §4.1.1, F-11). The old form named a Tailwind theme variable that
340
+ resolves once, at `:root`/`:host` — so a theme override or a `<Density>` island never reached a
341
+ radius, however deep inside it a card or a dialog sat. Measured: a `large` island computed
342
+ `--cue-radius-control: 5px` and still rendered a 4px radius. The new utilities inline the same
343
+ `calc(var(--cue-radius-*) * var(--cue-radius-scale))` at the element that draws it, so an
344
+ override or an island now reaches every radius in its subtree. No visual change under any
345
+ shipped preset today; this is what makes a theme's own radius override (a later release) work at
346
+ all. `cn()` is taught the three rungs (`extendTailwindMerge`), so a caller's own `rounded-*`
347
+ still overrides a component's default the way `className` always has — unextended,
348
+ `tailwind-merge` cannot see that `rounded-surface` and `rounded-full` are the same property, and
349
+ keeps both instead of the caller's winning. `Message`'s user and agent bubbles were the one
350
+ remaining `var(--radius-*)` reader (a four-value shorthand no plain utility could express, or so
351
+ it seemed); they now compose two ordinary bridge utilities instead — an all-corner rung and one
352
+ corner overridden — so no reader of the old, unreachable form is left in this package.
353
+ - **A `Preview` stage that names a theme (or a mode) now also carries `data-density` and
354
+ `data-cue-theme`, even when it names no density of its own.** A theme's rung retunes key on the
355
+ theme and the rung on one element, and `/looks` opens a stage with a theme and nothing else — so
356
+ before this, such a stage inherited the rung already resolved against the page's theme, and its
357
+ own theme's retune of that rung never applied. The stage now restates the rung in force around it
358
+ beside the theme it is naming, exactly as a nested `ThemeProvider` that names a theme already
359
+ does; outside every provider there is no rung in force, and nothing is restated. A stage that
360
+ names its own `density` is unaffected; a stage that names neither a theme nor a mode still stamps
361
+ nothing. Under a root that persists preferences, where that rung is the root's, the stage holds it
362
+ back until it mounts and names `density` in `data-cue-follows` instead — the same follower the
363
+ island first-frame fix introduced — so its first frame is the visitor's stored rung, and its own
364
+ theme's retune of it, rather than the app's default corrected a frame later.
365
+ - **Every `focus-visible` (and, for the one attribute-driven exception, `data-[focus-visible]`)
366
+ ring in this library now draws in the theme's `focus` role, never `accent`.** `forms/_chassis.ts`
367
+ was the only site that already made this distinction (its own comment has the long argument:
368
+ `focus` is contrast-gated at 3:1 against five grounds and `accent` is not); the other 81 sites —
369
+ every button, chip, tab, link, row, control and the colour picker's own draggable thumb — pointed
370
+ at the un-gated brand colour instead. A new shared module, `system/_focus-ring.ts`, draws the ring
371
+ everywhere now, and its width is a style-set knob (`--cue-style-focus-width`, falling back to the
372
+ existing 2px) that a Look may widen without a second module.
373
+
374
+ **This is a deliberate colour change, not a no-op.** The ring's colour moves wherever a theme's
375
+ `focus` differs from its `accent` — ten of the thirty shipped theme blocks:
376
+
377
+ - `graphite` light and dark
378
+ - `kiln` light and dark
379
+ - `porcelain` light and dark
380
+ - `tender` dark
381
+ - `hivehub` light
382
+ - `luma` light
383
+ - `venu` light
384
+
385
+ The other twenty blocks ship `focus` and `accent` at the same value, so nothing moves on screen
386
+ there. No component's public API changed.
387
+
388
+ `system/_focus-ring.ts`'s seven exports are each a complete literal string, not built from a
389
+ shared modifier-and-offset helper: Tailwind's compiler discovers a utility by scanning source
390
+ text for a whole candidate, never by evaluating the template literal that would assemble one
391
+ from parts, so a helper-built class rendered correctly everywhere and painted an `outline-offset`
392
+ of `0px` on every site in a real browser. `pnpm test:browser` (260/260) is green with the literal
393
+ form; nothing outside this one module needed a change.
394
+
395
+ `<AgentSurface skin="aui">`'s island re-points `--cue-focus` to its own ink alongside `--cue-accent`,
396
+ so an element inside it keeps drawing its ring in the island's palette rather than the outer
397
+ console theme's — the same ink it always drew, before this shared module gave the property a
398
+ name to read.
399
+
400
+ - 5d75ae7: `Button`, `IconButton`, the checkbox and `Link` take their voice, tones and ink from the style
401
+ set, and the outline button, every recessed input and the checkbox take the paint axis's resting
402
+ shade (spec 2026-09-26-looks-fidelity §3.7, §3.10 and §10.4, plan R3).
403
+
404
+ - **`Button` and `IconButton`.** The chassis reads `--cue-style-control-weight` (falling back to
405
+ 500, `font-medium`'s weight), `--cue-style-control-tracking` (`normal`),
406
+ `--cue-style-control-trim` (a `text-box` of `normal`) and `--cue-style-control-case` (`none`).
407
+ Each size's inline padding is its old rung times `--cue-style-control-pad` (1). The secondary
408
+ tone reads `--cue-style-secondary-ink`, `-ground` and `-edge`; the ghost and outline tones read
409
+ `--cue-style-quiet-ink` over their own inks (`fg-muted` and `fg`), and the outline reads
410
+ `--cue-style-outline-edge`. Hover states keep their classes.
411
+ - **The checkbox's** resting edge reads `--cue-style-check-edge` (`border`).
412
+ - **`Link`** reads `--cue-style-link-ink` (`fg`), and its `underline` variant
413
+ `--cue-style-inline-link-ink`, which falls back through the link ink; the underline's colour and
414
+ offset read `--cue-style-link-rule` (`border`) and `--cue-style-link-offset` (4px), its weight
415
+ `--cue-style-link-weight` (its parent's), and its hover ink `--cue-style-hover-ink` (`accent`).
416
+ Each variant now carries its own ink and the base none, so `linkVariants()` spread without
417
+ `cn()` never carries two.
418
+ - **The resting shade.** The outline tone, the recessed control chassis (`Input`, `Textarea`,
419
+ `Select`'s trigger, `NumberField` and every other control on it) and the checkbox add
420
+ `REST_SHADE`, a one-stop shadow whose ink is `--cue-paint-rest-shade`.
421
+ - **A `className` still overrides each of them** the way it overrode the class it replaced: a
422
+ caller's `font-*` weight, `tracking-*`, `px-*`, text, background and border colour, or
423
+ `shadow-*` passed to `Button`, `IconButton`, `Checkbox`, `Link` or an input replaces the reader
424
+ through the component's own `tailwind-merge`, and a `shadow-<colour>` tints the resting shade.
425
+ A caller's `uppercase`, `normal-case` and the rest still win over the case reader, which
426
+ Tailwind emits before them.
427
+ - **Concatenated onto `buttonVariants()` or `linkVariants()` without a merge, a class no longer
428
+ always wins.** Both return their recipe unmerged, so a class appended by a template string, `clsx`
429
+ or their own `className` option competes with the recipe's by Tailwind's emission order. The
430
+ button's padding readers (`px-[calc(…)]`) are emitted after every numeric `px-*`, where the
431
+ `px-(--cue-space-*)` rungs they replace were emitted before them, so `` `${buttonVariants()} px-2` ``
432
+ now keeps the recipe's padding; the link's offset reader is likewise emitted after every numeric
433
+ `underline-offset-*`. Pass `className` to the component, or merge with `tailwind-merge`.
434
+
435
+ Every fallback is what the site drew before, and no shipped style set or paint pack declares any
436
+ of these names with another value yet, so nothing renders differently under any shipped Look: the
437
+ style names are declared only as the shared `[data-style]` reset's `initial`, and every pack's
438
+ rest shade is `transparent`. One inheritance edge moves: a button used to inherit a letter-spacing
439
+ or a case from an ancestor that set one, and now draws `normal` and `none` unless the style set
440
+ names others. Measured over seven of the documentation site's pages, the kitchen sink among
441
+ them, no button sits under such an ancestor.
442
+ `--cue-style-control-case` is not yet part of the style contract; a later release adds it.
443
+
444
+ - 3d481fc: `AppBar`'s bottom rule can be dashed. The style contract gains one optional name, `--cue-style-chrome-rule-style`, for the rule's line style, beside the `--cue-style-chrome-rule` that already sets its ink (looks-fidelity round 5, plan V.2: Z17). Its value rule is `solid` or `dashed`, the two that a measured row needs.
445
+
446
+ - **`AppBar.Root` reads it** through the slot its own `border-b` already reads, Tailwind's `--tw-border-style`, rather than through a second `border-bottom-style` declaration. A caller's own style class, such as `className="border-dotted"`, therefore still wins as it did: it writes `border-style` itself, and Tailwind emits it after `border-b`. A raw declaration would have been emitted after it and beaten it.
447
+ - **The fallback is `solid`.** That is the slot's own initial value, and the solid rule every bar drew before. The name is `initial` on the shared `[data-style]` reset and `console` declines it, so under no set, and under every set that does not name it, the bar draws exactly what it did.
448
+
449
+ - 3d481fc: `Footer`'s two rules can be dashed. The style contract gains one optional name, `--cue-style-footer-rule-style`, for the line style of both of the footer's rules: the one across its top and the one over its fine print (looks-fidelity round 5, plan V.2: T120, T121). Its value rule is `solid` or `dashed`, as for `--cue-style-chrome-rule-style`, the app bar's.
450
+
451
+ - **`Footer` reads it on both rules** through the slot their own `border-t` utilities already read, Tailwind's `--tw-border-style`, rather than through a second `border-top-style` declaration. The slot does not inherit, so the landmark and the fine-print row each fill it. A caller's own style class, such as `className="border-dotted"`, therefore still wins on the landmark as it did: it writes `border-style` itself, and Tailwind emits it after the width utilities. A raw declaration would have been emitted after it and beaten it.
452
+ - **The fallback is `solid`.** That is the slot's own initial value, and the solid rules every footer drew before. The name is `initial` on the shared `[data-style]` reset and `console` declines it, so under no set, and under every set that does not name it, the footer draws exactly what it did.
453
+ - **A name of its own, not the app bar's.** A source can style the two ends of a page apart: stripe.com draws the rule under its header solid and both of its footer's rules dashed. `Band`'s rule does not read it either.
454
+
455
+ - 88c6245: The package manifest names four more presets: `kiln`, `porcelain`, `tender` and `zine`.
456
+
457
+ `@cueplusplus/ui/manifest/manifest.json`'s `themes` now lists all four in their alphabetical slots — `kiln` between `hivehub` and `luma`, `porcelain` between `luma` and `quotamate`, `tender` between `snuffle` and `terminal`, `zine` after `venu` — and `manifest/tokens.json` carries each entry: the four `@cueplusplus/theme-*` packages, both modes, the five base density rungs. That list is what a tool or an agent reads to learn which palettes exist before it suggests one, so anything that reads it now offers all four too.
458
+
459
+ Nothing in the library changed to make room: a theme is still an application's choice, so to use one install its package beside `@cueplusplus/theme-base`, import its `theme.css` after `@cueplusplus/ui/styles.css`, and hand its manifest to `<ThemeProvider themes>`.
460
+
461
+ - 25945dd: The package manifest names an eleventh preset, `graphite`.
462
+
463
+ `@cueplusplus/ui/manifest/manifest.json`'s `themes` now lists `graphite` between `dusk` and `hivehub`, and `manifest/tokens.json` carries its entry — `@cueplusplus/theme-graphite`, both modes, the five base density rungs. That list is what a tool or an agent reads to learn which palettes exist before it suggests one, so anything that reads it now offers `graphite` too.
464
+
465
+ Nothing in the library changed to make room: a theme is still an application's choice, so to use it install `@cueplusplus/theme-graphite` beside `@cueplusplus/theme-base`, import its `theme.css` after `@cueplusplus/ui/styles.css`, and hand its manifest to `<ThemeProvider themes>`.
466
+
467
+ ### Patch Changes
468
+
469
+ - a6afdd2: **`Band`'s `separation` table names every shipped style set** (`@cueplusplus/ui`, documentation only). Under `kiln`, `separation="ground"` paints the recessed `--cue-sunken` ground and `separation="rule"` draws nothing, because the set's `--cue-band-rule` is now `0px`; `Footer` keeps its own rule there through `--cue-style-footer-rule`. `tender`, `zine` and `porcelain` draw the 1px rule and paint no ground, as `console` does. No class changes: the table is what the token layer already emits, and `band.test.tsx` now holds all nine rows (`:root` and the eight sets) to it.
470
+ - 8970b22: A returning visitor's stored theme paints the first frame, nested providers follow the page's theme,
471
+ rung and mode live, and a `Preview` stage's font pairing reaches its overlays.
472
+
473
+ - **The root provider no longer restates its props on its own element before it has restored the
474
+ visitor's preferences.** `prepaintScript()` stamps the stored theme, rung, mode, style set and
475
+ pack on `<html>` before first paint, but the root `ThemeProvider` rendered its element — which
476
+ wraps every node of content — with `data-theme`, `data-density` and `data-mode` (and `data-style`
477
+ / `data-paint` when named) taken from its props, plus the props' `color-scheme`. That shadowed the
478
+ pre-paint stamp for the whole page until hydration caught up, so everyone whose stored theme was
479
+ not the default saw one frame of the default. It was invisible while the default theme looked
480
+ like bare `:root`, and a full-page flash under any other. A root that persists (the default) now
481
+ renders `data-cue-root` and no axis attribute in its server markup and first client render, and
482
+ stamps what it restored — the same values as `<html>` — once the restore lands, before the first
483
+ paint. If you read `data-theme` off the provider's element before hydration, read it off `<html>`
484
+ instead. A root with `persistPreferences={false}` stamps its props from the first render, as
485
+ before.
486
+ - **A `Preview` stage's font pairing reaches what opens on it.** `<Preview font="plex">` stamped
487
+ `data-font` on its stage and told nothing else, so a select, menu or popover opened on the stage
488
+ came up in the page's pairing, and `useTheme().font` read on the stage reported the page's. The
489
+ stage now republishes its pairing the way it already republished its theme, mode, density, style
490
+ set and pack. A stage that names a pairing also takes `font-sans`, so its text with no font class
491
+ of its own follows the stage's pairing instead of keeping the family it inherited. A stage that
492
+ names no pairing renders exactly as before.
493
+ - **A nested `ThemeProvider` that names no theme, density or mode now follows the page's live.** It
494
+ used to copy the ambient theme once when it mounted, open on its theme's preferred density rather
495
+ than the page's, and open `dark` whatever the page was — and stamp all three on its own element
496
+ for good. So a theme, density or mode the root restored from storage after the page loaded, or a
497
+ picker changed later, stopped at every nested provider. Now such a provider stamps none of the
498
+ three: its region inherits the page's, and `useTheme()` inside it and the overlays it opens report
499
+ the page's, as they change. A nested provider that names a theme or a mode keeps it and stamps it
500
+ together with the density and mode (or theme) it follows, since a theme's light palette and its
501
+ density rules need them on one element; one that names only a density stamps it the way a
502
+ `<Density>` island does. If you relied on a nested provider with no `density` opening on its
503
+ theme's preferred rung, or with no `mode` opening `dark`, pass the prop.
504
+
505
+ - 69b6cbb: Three font pairings, four style sets and three new paint packs — the tokens for the four
506
+ remaining Looks (spec 2026-09-26 §8) — plus `grain` retuned to its own measurement.
507
+
508
+ Font pairings (`FONTS` now names twelve):
509
+
510
+ - `inter-source` — Inter over Source Code Pro, stripe.com's own recommendation once Söhne
511
+ is refused (Klim Type Foundry, licensee-only). Both faces are already delivered by every
512
+ app that ships `inter` or `source`.
513
+ - `dm` — DM Sans over Space Mono, with Anybody as the display face. The first pairing whose
514
+ `font-display` does not restate `font-sans`: reachable only because a style set can now
515
+ route `--cue-style-display-face` to `var(--cue-font-display)` (R-13).
516
+ - `calsans` — Cal Sans over Paper Mono, both self-hosted through `next/font/local` rather
517
+ than `next/font/google` (R-15), since Google Fonts serves neither in the cut this pairing
518
+ needs.
519
+
520
+ Style sets (`STYLE_SETS` now names eight): `tender` (stripe.com), `zine` (greptile.com),
521
+ `kiln` (replit.com) and `porcelain` (coss.com/ui). Each declares the full twelve-name
522
+ contract, including the three names every set has carried since `graphite` —
523
+ `style-control-face`, `style-display-face`, `style-seam-color`.
524
+
525
+ Paint packs (`PAINTS` now names ten): `plume` (stripe.com, a soft low-alpha bloom), `matte`
526
+ (replit.com, a flat shadow off the theme's own data-ground with the glass blur turned off)
527
+ and `glaze` (coss.com/ui, a light shadow ladder with a soft accent glow). Each declares all
528
+ thirty-one names. `grain` is retuned to its own measurement against greptile.com: its texture
529
+ now carries `stitchTiles='stitch'` (without it the tile seams every 200px, which the live
530
+ site never does), its screen moves from a 14px soft dot to the site's own 24px hard dot at
531
+ fg 15%, and its glass turns opaque to match the site's flat, unblurred header.
532
+
533
+ `@cueplusplus/theme-base`'s manifest schema recognises all three new pairings as base
534
+ pairings a theme package can override, the same as every pairing before them.
535
+
536
+ `@cueplusplus/ui`: the built-in paint devices now also cover a console shell's page ground,
537
+ not only `<Band separation="ground">` — `AppShell.Root` carries the same texture overlay
538
+ `Band` does (R-14), so a pack with a texture (today, only `grain`) reaches the whole page.
539
+ Every pack whose texture is `none` renders this as a no-op. The package manifest also picks
540
+ up the new pairings, sets and packs in its generated type unions and docs; nothing else in
541
+ the library's runtime code changes.
542
+
543
+ `@cueplusplus/studio-mcp` carries a comment fix only: `@repo/studio-core`'s catalogue
544
+ docblock named "nine fonts" among the closed lists it republishes, and that count is now
545
+ twelve. Nothing about the catalogue's shape or values moves.
546
+
547
+ - 2d8eff5: A ninth font pairing, `geist-mono`, and `bevel` now matches the site it is measured from.
548
+
549
+ `geist-mono` pairs Geist with Geist Mono — the first pairing here that holds its sans and its
550
+ mono to one type family. Every pairing before it reaches for a different family on its
551
+ monospace half, `geist` itself included (Geist over JetBrains Mono); this is the pairing that
552
+ matches agent-native.com, whose buttons, labels and kbd are set entirely in Geist Mono.
553
+ `data-font="geist-mono"` resolves to nothing until your app delivers `--cue-face-geist-mono`,
554
+ the same way it delivers any other webfont pairing's faces — see
555
+ `FONT_PAIRINGS["geist-mono"].faces`.
556
+
557
+ `bevel`'s stroke and glass are retuned against a proper measurement of the site, in both
558
+ modes, rather than the dark-mode-only pass they shipped with:
559
+
560
+ - `stroke-angle` is `140deg`, not `180`.
561
+ - `stroke-from` is `var(--cue-border-strong)` — an exact share of the theme's own
562
+ border-strong in both modes, where the fg-tint it replaces missed light mode by a wide
563
+ margin.
564
+ - `stroke-to` is `color-mix(in oklch, var(--cue-fg-subtle) 19%, transparent)`, closer to the
565
+ measured endpoint than the formula it replaces in both modes at once.
566
+ - `glass-ink` is the page background at 90% under `blur(12px)`, not a raised surface at 88%
567
+ under `blur(10px)` — the site's own header sits over the page, not over a card.
568
+
569
+ Nothing else about the pack moves. It still declares all thirty-one paint names, and
570
+ `packages/tokens/test/paint.test.mjs` still holds it to that contract.
571
+
572
+ `@cueplusplus/theme-base`'s manifest schema now recognises `geist-mono` as a base pairing
573
+ too, so a theme package can write `fontPairings.overrides["geist-mono"]` the way it already
574
+ can for every other base pairing; `adds` refuses the name, the same as it refuses `geist`.
575
+
576
+ `@cueplusplus/ui`'s manifest picks up the new pairing's type union and the retuned pack's
577
+ values in its generated docs; nothing in the library's own runtime code changes.
578
+
579
+ `@cueplusplus/studio-mcp` carries a comment fix only: `@repo/studio-core`'s catalogue
580
+ docblock named "eight fonts" among the closed lists it republishes, and that count is now
581
+ nine too. Nothing about the catalogue's shape or values moves.
582
+
583
+ - 8e23076: A theme island under a style set or a paint pack now paints its own borders, inks and band ground,
584
+ not the page's.
585
+
586
+ A pack's and a set's values read other axes — `bevel`'s stroke is the theme's border, every pack's
587
+ shade and rim inks are mixes of the theme's foreground, `marketing`'s band rule and ground are the
588
+ theme's border and surface — and CSS resolves a custom property where it is declared. With the set
589
+ or pack stamped only on the page, a region below it in another theme inherited values already
590
+ resolved against the page's theme: a `dusk` region inside a `cue` page under `bevel` drew `cue`'s
591
+ borders, and a light region inside a dark page kept the dark ones.
592
+
593
+ - **A nested `ThemeProvider` that names a `theme` or a `mode` now restates the style set and pack in
594
+ force** as `data-style` and `data-paint` on its own element, so they re-resolve against its theme.
595
+ It is still the page's set and pack, followed live: a picker that changes the page's pack moves
596
+ the region's with it, and `useTheme()`, storage and `<html>` are untouched. A nested provider that
597
+ names its own `styleSet` or `paint` keeps it, as before; one that names nothing, or only a
598
+ `density`, still stamps nothing.
599
+ - **A `Preview` stage with a `theme`, a `mode` or a `font` restates them the same way**, so a
600
+ specimen on a `dusk` stage draws `dusk`'s strokes under a `bevel` page. A stage that names only a
601
+ `density`, or nothing, is unchanged, and so is one that names its own `styleSet` or `paint`.
602
+ - Overlays were never affected: a portal already stamps every axis on its own container.
603
+
604
+ Under a root that persists, these islands restate nothing in their server markup or on their first
605
+ client render, so they inherit the visitor's stored set and pack from `<html>` rather than repeating
606
+ the app's defaults over them; each restates once it has mounted, before the first paint. The root's
607
+ restore itself changes nothing an island reads, so a streamed Suspense boundary full of stages
608
+ still hydrates in place instead of being rendered again on the client.
609
+
610
+ If you stamp `data-theme` on an element by hand inside a styled or painted page, restate
611
+ `data-style` and `data-paint` beside it yourself, or use a nested `ThemeProvider`, which does it for
612
+ you. `<Density>` still restates a set only when you pass `styleSet`: a rung changes no ink.
613
+ `@cueplusplus/tokens` emits the same stylesheet as before; the note in its build that described this
614
+ trade as yours to carry now says the library carries it for its own islands.
615
+
616
+ - 9275ffc: `FieldLabel`, `Eyebrow`, a table head, `Stat` labels, group and section headings and a dozen
617
+ more chassis captions take their face, case and tracking from the style set; the shared
618
+ recessed control chassis — every text field, textarea, number field, combobox and the rest of
619
+ what a person types into — takes its face from it too.
620
+
621
+ Twenty-five sites read the new `--cue-style-label-face` and `--cue-style-label-case`, falling
622
+ back to `font-mono` and `uppercase` — what they have always worn — so nothing changes under no
623
+ style set or under `console`, `editorial`, `marketing`, `graphite` or `zine`. Under `tender`,
624
+ `kiln` or `porcelain` they read sans and sentence case instead, matching the sites those Looks
625
+ are measured from. `--cue-style-label-tracking` follows the same rule but is optional: `FieldLabel`
626
+ falls back to its own tighter tracking, `Eyebrow` to its own wider one, and the rest to the plain
627
+ rung — each exactly what it rendered before — and only the three sans sets declare one shared
628
+ value, converging every label onto it. `forms/_chassis.ts`'s shared input chassis reads
629
+ `--cue-style-input-face`, falling back to `font-mono`, so the same set of Looks reads sans for
630
+ typed text too.
631
+
632
+ Two calls that already forced their own face are unchanged on purpose: `color-picker.tsx`'s hex
633
+ field keeps `font-mono` regardless of the set (a hex code is content, not voice), and
634
+ `primitives/avatar.tsx`, `primitives/chip.tsx` and `chat/agent-pile.tsx`'s avatar initials keep
635
+ `font-mono uppercase` too — a rendered initial or a tag's text is the value being shown, not a
636
+ chassis caption.
637
+
638
+ Inside a stamped style set, the four are resolved where the set is stamped, exactly as
639
+ `--cue-style-control-face` already is — an island in another theme, pairing or font has to
640
+ restate the set to get its own, and the library's islands do that for you.
641
+
642
+ **The rest of the chrome now reads `--cue-style-control-face` too**, the existing name #205
643
+ gave `Button`, `IconButton` and the `Tabs` trigger: a menu row, a select/combobox/autocomplete
644
+ option, a tooltip's popup, a checkbox/switch/radio's option text, a segmented control and toggle
645
+ item, the command palette's input and its rows, a breadcrumb link, `Link` and a nav-menu trigger
646
+ and link all fall back to `font-mono` — again, what every one of them has always worn — so under
647
+ no style set or under a mono-voiced one they are unchanged, and under `tender`, `kiln` or
648
+ `porcelain` they read sans like the buttons beside them. No new contract name: none of these
649
+ sites was uppercase-tracked, so none needed the label axis. Left mono on purpose: a value chip's
650
+ user-typed content (`forms/_listbox.ts`'s `valueChipClasses`) and the general-purpose `Item`
651
+ media-object row — both hold arbitrary caller content, the same category as a table cell.
652
+
653
+ `Preview`, `Density` and `ThemeProvider` already accept `styleSet="tender" | "kiln" | "porcelain"`.
654
+
655
+ - 07d8524: `PageShell`'s title no longer collapses to one word per line beside a wide `actions` slot.
656
+
657
+ The header row laid the title block (`min-w-0`) and the actions slot (`shrink-0`) out with
658
+ `flex` and no wrap, so an actions slot wider than the remaining row — the docs site's component
659
+ pages pass a peer-dependency chip row plus the markdown twin, copy button and two agent
660
+ hand-off buttons, together nearly 940px — squeezed the title down to whatever width was left,
661
+ sometimes under 30px, wrapping every word onto its own line. The header now wraps
662
+ (`flex-wrap`), the title block keeps a floor of `min-w-[min(100%,20rem)]` so it is never
663
+ squeezed below a readable width (or below its container's full width, on a narrower page), and
664
+ the actions slot trades its fixed `shrink-0` for `min-w-0` so it can shrink and wrap its own
665
+ children instead of forcing the title to give way. On a row with room for both, nothing
666
+ changes; when there is not enough room, the actions slot now drops to its own line under the
667
+ title and wraps there.
668
+
669
+ - 36dfdd0: A paint pack is called a paint pack now, not a "look pack".
670
+
671
+ A **Look** is now a named bundle — one theme, font pairing, style set and paint pack chosen
672
+ together — so the finish axis's values stopped borrowing the word. The prose moved and nothing
673
+ else did:
674
+
675
+ - **`@cueplusplus/tokens`:** every pack's `$description`, and the docblocks the build writes over
676
+ `PAINTS` and `PAINT_CONTRACT` in `tokens.js` and `tokens.d.ts`.
677
+ - **`@cueplusplus/ui`:** the JSDoc on the `paint` props of `ThemeProvider`, `Density` and `Preview`,
678
+ on `useTheme().paint` and `setPaint`, on `prepaintScript()`'s paint options and on `isPaint`, and
679
+ the component manifest generated from it.
680
+
681
+ `halo`'s and `hatch`'s descriptions stop counting the presets they read under: both packs'
682
+ inks are shares of the theme's own colours, so they read under every preset, not "all ten".
683
+
684
+ No identifier changes: `PAINTS`, `DEFAULT_PAINT`, `PAINT_CONTRACT`, the `Paint` type, the
685
+ `data-paint` attribute and every file name are exactly as they were.
686
+
687
+ - 080462c: A pack named on `ThemeProvider` now reaches the overlays it opens, and `setPaint` repaints the whole page.
688
+
689
+ Two things were wrong with the paint axis as 0.16.0 shipped it, and both showed in the surfaces a
690
+ pack moves most:
691
+
692
+ - **Overlays opened under a provider's pack carried none.** `<ThemeProvider paint="halo">` stamped
693
+ its own element and `<html>`, but a popover, menu, dialog or tooltip opened inside it got no
694
+ `data-paint` on its portal container. At the root nobody noticed, because an overlay mounted on
695
+ `<body>` inherits `<html data-paint>`. Under a nested provider — `<ThemeProvider paint="lift">`
696
+ around one region of a page — nothing covered for it, and that region's overlays opened in the
697
+ page's finish rather than the region's. A nested provider that names no pack also reported none
698
+ from `useTheme().paint` under a painted one; it now reports the pack in force, as `styleSet`
699
+ always has.
700
+ - **A nested provider that names no pack or style set now follows the outer one live.** It used to
701
+ copy the outer value once, when it mounted, and stamp that copy on its own element — so a pack or
702
+ set restored from storage after the page loaded, or changed later at the root, stopped at every
703
+ nested provider, which kept whatever the root held on its first render. The style set has had this
704
+ since it shipped. Now it stamps neither, and its region, `useTheme()` inside it and its overlays
705
+ all follow the outer value; a nested provider that names a pack or set keeps it, as before.
706
+ - **`setPaint` on its own left `<html>` behind.** It moved the provider's element and not the
707
+ document's, so the page ground and every overlay — a paint picker's own dropdown included — kept
708
+ the previous pack until some other setting changed. The whole page repaints at once now.
709
+
710
+ **`PAINTS`, `DEFAULT_PAINT` and the `Paint` type are exported from `@cueplusplus/ui/system`** and
711
+ the package root, beside `STYLE_SETS`. Five public signatures already named `Paint`, but the type
712
+ lived only in `@cueplusplus/tokens`, which pnpm does not let an app import unless the app installed
713
+ it too. You can now type a pack, and list the packs to build a picker, with no second dependency.
714
+
715
+ Nothing changes for an app that never names a pack: no `data-paint` is stamped anywhere, and the
716
+ stored preference is the same object it always was.
717
+
718
+ - 36dfdd0: Documentation that counted the presets stopped counting what no longer holds.
719
+
720
+ - **Every theme package's README** counted the presets beside it when it pointed at the theming
721
+ guide — "the other nine presets", "the other ten", or in `theme-base` and `theme-tools` "the ten
722
+ shipped presets" — and `theme-tools` opened by saying "the ten presets in this repository are
723
+ built by it too". Fifteen ship now, and the next one would make any count wrong again, so each
724
+ line reads "the other presets" (or "the shipped presets", or "the presets") — the wording the
725
+ newest presets already use.
726
+ - **`CueMark`, and its `BrandTone`,** said a single element "is correct in all ten presets"; it is
727
+ correct in every preset, and the docs and the component manifest now say so.
728
+
729
+ - **`theme-tools`' CSS emitter** said "all ten presets are `complete`" in the docblock on its
730
+ light-block rule; every preset here is `complete`, and it now says so without a count.
731
+
732
+ Nothing else changed: no token, no value, no export.
733
+
734
+ - 002f95a: Restoring a visitor's stored theme, pairing, style set or pack no longer throws away streamed
735
+ content that is still hydrating.
736
+
737
+ A `ThemeProvider` that persists renders its props on the server, then restores the visitor's stored
738
+ choice in its first commit. On a streamed page some Suspense boundaries are still server HTML at that
739
+ moment — waiting on a lazily loaded module, still streaming, or streamed and queued for React's
740
+ batched reveal — and React treats a boundary under a changed context as changed, whatever it reads.
741
+ One it cannot hydrate right then it renders again on the client, fallback first, and discards the
742
+ server HTML that arrives for it later; for a boundary still streaming or queued it does this on every
743
+ lane, so making the restore a transition does not help. Whenever the stored choice differed from the
744
+ page's default, that was a blank-and-redraw on every load.
745
+
746
+ The restore now moves no context value. Each provider still hands its values down through context,
747
+ and a setter or a changed prop moves them exactly as before — readers re-render in the same commit,
748
+ and a change made in a transition stays one. What the restore corrects is posted beside the context
749
+ instead: every reader inside the library picks it up by itself, hydrating first against what the
750
+ server rendered, and no boundary is told that anything changed. The same holds for the colour scheme
751
+ `mode="system"` reads from the OS.
752
+
753
+ `useTheme().font` now hydrates against the pairing the server rendered and catches up with the
754
+ restore, like every other axis: a component that rendered it into markup used to hydrate against HTML
755
+ naming the default, and React regenerated its whole boundary for the mismatch. Portal containers and
756
+ `<html>` still carry the stored pairing from the first commit, so no overlay makes the browser fetch
757
+ the default's webfont. A boundary that hydrates after a setter has run hydrates against what the
758
+ server rendered too, not against the setter's value.
759
+
760
+ A context now moves only when its own value does. A setter handed the value already in force does
761
+ nothing — no re-render and no write to storage — so an effect that re-asserts a preference on every
762
+ render stays one render. `setPaint` no longer re-renders a component that only lists the rungs on
763
+ offer. And a `themes` array built inline, equal to the last one, is treated as the same registry: a
764
+ parent re-rendering the provider while the page hydrates moves nothing. `useThemes()`,
765
+ `useDensities()` and `useFonts()` sit out a restore unless their own list changed.
766
+
767
+ - a6afdd2: A modal's scrim no longer fades by its own `opacity`. An element under opacity 1 is a backdrop root, so while the scrim faded in, the paint pack's `--cue-paint-scrim-filter` on its `::before` had nothing to blur: under `glaze` (`blur(8px)`) the page stayed sharp for the whole 150ms fade, snapped to the blur when it ended, and lost it on the first frame of the exit. `scrimClasses` — behind `Dialog`, `AlertDialog`, `Sheet`, `Drawer` and `CommandPalette` — now keeps the scrim at opacity 1 and fades its parts over the same 150ms: its background from `transparent`, the `::before` by its own opacity, and its own `backdrop-filter` from `none` on the entering and leaving frames, so a `backdropClassName="backdrop-blur-*"` still fades in rather than snapping. Under every other pack, and with no pack, the scrim renders as it did.
768
+ - c1f6b7c: `Button`, `IconButton` and the `Tabs` trigger take their face from the style set, and seam
769
+ grids take their hairline colour from it.
770
+
771
+ The three controls read `--cue-style-control-face`, falling back to `--cue-font-mono` — the
772
+ face they have always worn — so nothing changes under no style set or under any set that
773
+ ships today. `SeamGrid`, `SeamList` and `<Card seam>` read `--cue-style-seam-color` for the
774
+ gaps between their cells, and for their rim when they draw one, falling back to
775
+ `--cue-border`; under the new `graphite` set the seams draw lighter than the rules between
776
+ bands. A bordered seam container now clips its background to the padding box, which paints
777
+ nothing different under an opaque ink and keeps a translucent one from doubling under the
778
+ rim.
779
+
780
+ Inside a stamped style set, the face and the seam ink are resolved where the set is stamped,
781
+ so an island in another theme or pairing has to restate the set to get its own. The library's
782
+ islands do that for you: a nested `ThemeProvider` that names a `theme` or `mode`, and a
783
+ `Preview` stage that names a `theme`, `mode` or `font`, restate the set in force beside it, so a
784
+ `dusk` region under a `graphite` page draws `dusk`'s seams and a `plex` stage's buttons wear
785
+ Plex Mono. Only an element you stamp `data-theme` or `data-font` on by hand has to restate
786
+ `data-style` itself.
787
+
788
+ `Preview`, `Density` and `ThemeProvider` accept `styleSet="graphite"`.
789
+
790
+ - Updated dependencies [a6afdd2]
791
+ - Updated dependencies [a6afdd2]
792
+ - Updated dependencies [a6afdd2]
793
+ - Updated dependencies [a6afdd2]
794
+ - Updated dependencies [a6afdd2]
795
+ - Updated dependencies [a6afdd2]
796
+ - Updated dependencies [d205951]
797
+ - Updated dependencies [68e485b]
798
+ - Updated dependencies [af8b102]
799
+ - Updated dependencies [68e485b]
800
+ - Updated dependencies [e56ebf3]
801
+ - Updated dependencies [e56ebf3]
802
+ - Updated dependencies [e56ebf3]
803
+ - Updated dependencies [e56ebf3]
804
+ - Updated dependencies [e56ebf3]
805
+ - Updated dependencies [68e485b]
806
+ - Updated dependencies [68e485b]
807
+ - Updated dependencies [69b6cbb]
808
+ - Updated dependencies [2d8eff5]
809
+ - Updated dependencies [c1f6b7c]
810
+ - Updated dependencies [f2c514d]
811
+ - Updated dependencies [8e23076]
812
+ - Updated dependencies [9275ffc]
813
+ - Updated dependencies [36dfdd0]
814
+ - Updated dependencies [36dfdd0]
815
+ - Updated dependencies [e56ebf3]
816
+ - Updated dependencies [68e485b]
817
+ - Updated dependencies [3d481fc]
818
+ - Updated dependencies [3d481fc]
819
+ - Updated dependencies [3d481fc]
820
+ - Updated dependencies [3d481fc]
821
+ - Updated dependencies [3d481fc]
822
+ - Updated dependencies [3d481fc]
823
+ - Updated dependencies [3d481fc]
824
+ - Updated dependencies [3d481fc]
825
+ - @cueplusplus/tokens@0.17.0
826
+ - @cueplusplus/theme-base@1.1.0
827
+
828
+ ## 0.16.0
829
+
830
+ ### Minor Changes
831
+
832
+ - 42021e4: Every overlay draws its shadow from a composite a look pack can move.
833
+
834
+ Dialogs, menus, popovers, tooltips, toasts, drawers, sheets, the command palette, the
835
+ select and combobox popups and the log viewer's jump button all drew
836
+ `shadow-[0_8px_24px_rgba(0,0,0,0.4)]` — the same literal in four places. They now share
837
+ one four-layer recipe: a hairline, a contact shadow, a bloom and an inset top light.
838
+
839
+ **Nothing looks different.** At the defaults three of the four layers are transparent and
840
+ the bloom is that exact literal. Measured rather than asserted: in Chromium the recipe and
841
+ the literal render byte for byte; in WebKit 42 channels of roughly 264,000 differ by 1/255,
842
+ which is compositing rounding and below what a display can show.
843
+
844
+ What it buys is that `--cue-paint-shadow-scale` moves the whole ladder at once and any
845
+ layer switches off by letting its ink resolve to `transparent` — so a pack can give every
846
+ floating surface a deeper shadow, a tighter one, or a lit top edge, without touching a
847
+ component.
848
+
849
+ Overlays also adopt the gradient stroke deferred from the previous release, and keep their
850
+ own rim colour while doing it: the recipe's stops fall back to `--cue-border-overlay`, not
851
+ `--cue-border`, because some themes match that token to the surface on purpose so the rim
852
+ vanishes.
853
+
854
+ `AppWindowFrame` keeps its literal shadow. Its bloom is twice as dark as every other
855
+ surface's, and giving it the shared recipe would have lightened it.
856
+
857
+ - 6e2fd3b: Every edge fade in the library follows one token.
858
+
859
+ `Tabs`, `Toolbar`, `SegmentedControl`, `ScrollableTabsList` and `AppBar` soften their
860
+ overflowing edges with a mask that reached in a fixed 24px. That distance is
861
+ `--cue-paint-fade-length` now, so a `[data-paint]` pack can make every one of them
862
+ shorter or longer at once.
863
+
864
+ **Nothing looks different.** The token's default is the same 24px, measured pixel for
865
+ pixel in Chromium and WebKit — with a 64px override in the same test, so the comparison
866
+ is one that could have failed.
867
+
868
+ `edgeFadeMask(edges, fadePx)` is unchanged when you pass a reach of your own: an explicit
869
+ number still wins, because a caller that has measured its own fade is not asking for the
870
+ axis's.
871
+
872
+ - 40c9de0: `AppBar`'s frosted glass is a look pack's to change, and a consumer's backdrop utilities still work.
873
+
874
+ The bar drew `bg-surface-1/95 backdrop-blur`. It now spends `--cue-paint-glass-filter` and
875
+ `--cue-paint-glass-ink`, so a `[data-paint]` pack can make the chrome heavier, clearer, or
876
+ tinted — or turn the blur off entirely — without touching the component.
877
+
878
+ **Nothing looks different**, measured pixel for pixel against what the bar drew before, in
879
+ Chromium and WebKit, over a hard-edged background so the blur has something to smear.
880
+
881
+ **And `className` still composes.** This is the part worth knowing if you style `AppBar`
882
+ from outside: passing `backdrop-brightness-50` or `backdrop-saturate-150` through
883
+ `className` adds to the bar's blur rather than replacing it. The obvious implementation —
884
+ a plain `backdrop-filter` declaration — would have silently deleted the blur the moment you
885
+ passed any backdrop utility of your own. That case is now a test.
886
+
887
+ The opaque fallback behind `@supports not (backdrop-filter: …)` is unchanged: a browser
888
+ without backdrop filters still gets a solid bar rather than a translucent one over the page.
889
+
890
+ - e53619a: The first look pack: `halo`, and the glow it paints.
891
+
892
+ `<ThemeProvider paint="halo">` — or `data-paint="halo"` on any element — gives primary
893
+ buttons a soft two-stop glow in the theme's own accent, doubling on hover. It is the first
894
+ value the paint axis has other than `none`, so it is also the first time the axis changes
895
+ what a page looks like rather than only standing ready to.
896
+
897
+ **Nothing changes unless you ask.** Unstamped, both stops have zero blur and a transparent
898
+ ink, so the button renders exactly as it did — measured pixel for pixel in Chromium and
899
+ WebKit, alongside the other half of the same test: that stamping `halo` does change it.
900
+
901
+ A pack names no colour of its own. `halo`'s two inks are a share of `--cue-accent`, so it
902
+ reads correctly under all ten shipped themes rather than carrying one palette's blue into
903
+ the others.
904
+
905
+ Two fixes ride along. `--cue-paint-glow-blur` and `-blur-far` were validated against the
906
+ rim's 0–4px rule, so no usable halo radius was accepted — the first pack to set one was
907
+ refused at 12px. They take 0–64px now. And `Button`'s `primary` tone is the only component
908
+ that spends the glow; every other tone is untouched.
909
+
910
+ - 3d0c3fd: A seventh look pack: `grain`, a fine fractal noise over every surface.
911
+
912
+ `<ThemeProvider paint="grain">`, or `<Density paint="grain">` over a subtree, lays a
913
+ 200×200 fractal-noise tile across the surfaces that carry the texture recipe. It is the
914
+ quietest pack in the catalogue by design — 12% opacity, no blend mode — and it is the
915
+ only one that spends `--cue-paint-texture`, a name the library has carried since the
916
+ texture slice with nothing able to use it.
917
+
918
+ Measured from greptile.com, whose ground is an `feTurbulence fractalNoise` data URI at
919
+ 0.85 baseFrequency over five octaves, composited at roughly 12% effective opacity across
920
+ every pixel of the site. The tile here is that filter at those parameters, generated
921
+ rather than copied: it is 331 bytes of SVG inline in the pack, so nothing is fetched and
922
+ no asset ships.
923
+
924
+ **It is deliberately below the bar.** Every other pack clears the threshold this system
925
+ sets for shipping one; `grain` reaches about 62% of its site and ships anyway, as the
926
+ proof that a pack is worth having for what it refuses as much as for what it paints. Its
927
+ `refuses` note names the four of six screens it cannot claim, the twelve divider forms
928
+ and the band-frame furniture that belong to components rather than to a finish, the
929
+ hexagon control silhouette, and the handwriting type stack.
930
+
931
+ Nothing changes for a page that does not ask for it: `grain` is opt-in like every pack,
932
+ and the provider still stamps no `data-paint` at all.
933
+
934
+ - 4d851a0: `Panel` and `Card` can take an inset ring, and a `Band`'s ground can take a repeating pattern.
935
+
936
+ Two more devices reach the paint axis, which means every one of its thirty-one names is now
937
+ spent by something: `--cue-paint-rim-width` and `-rim-ink` draw a hairline ring inside a
938
+ panel's or a card's radius, and `--cue-paint-ground-pattern` with `-size` lays a repeating
939
+ geometry under a band's content.
940
+
941
+ **Nothing changes unless you ask.** The ring's width is `0px` and its ink is transparent;
942
+ the pattern is `none`. Measured pixel for pixel in Chromium and WebKit, with both devices
943
+ switched on in the same tests so the comparisons are ones that could have failed.
944
+
945
+ The ring is a `box-shadow`, so a `Band` or a `Card` that already draws one cannot take it —
946
+ and **form controls deliberately do not**. `forced-colors: active` discards shadows
947
+ entirely, and a control's ring is a focus indicator: it stays a real outline, which is what
948
+ a forced-colors user actually sees.
949
+
950
+ A pattern and a texture are different layers and compose: a pattern is the host's own
951
+ background image, a texture is noise on a pseudo-element above it.
952
+
953
+ - 5fcc6b4: Form controls and cards draw their border as a gradient stroke, so a look pack can tint it.
954
+
955
+ `Input`, `Textarea`, `Select`, `Combobox`, `Autocomplete`, `SearchInput`, `OTPField`,
956
+ `InputGroup`, the date and colour fields, `MusicalTimeInput` and the rest of the recessed
957
+ control family — and `Card` — now paint their line from two background layers with a
958
+ transparent border between them, rather than from `border border-border`.
959
+
960
+ **Nothing looks different.** At the defaults both gradient stops are `--cue-border` and a
961
+ one-colour gradient paints a flat field, so the line is the same one device-pixel of the
962
+ same colour over the same fill. That is measured rather than asserted: the straight edges
963
+ and the interior are pixel-identical in Chromium and WebKit, and with square corners the
964
+ two are identical everywhere. On a rounded corner they differ by sub-pixel antialiasing —
965
+ invisible at 1×, and bounded by the test rather than claimed away.
966
+
967
+ What it buys is that `--cue-paint-stroke-from`, `-to`, `-angle` and `-width` now reach
968
+ every one of those surfaces, so a `[data-paint]` pack can give the whole family a gradient
969
+ edge, a thicker rule or a different angle without touching a component.
970
+
971
+ A seamed `Card` keeps its old border: its fill is `--cue-border` — the gaps between its
972
+ rows _are_ the line — and the recipe is keyed by fill.
973
+
974
+ `Toggle` and `ToggleGroup` also lose ten custom properties from their published manifests.
975
+ They never painted them: the entries came from a type-only import of the control chassis,
976
+ and the manifest lists what a component spends. `--cue-sunken`, `--cue-focus` and
977
+ `--cue-border` were among them, so this was wrong before the gradient stroke existed.
978
+
979
+ - bcd0738: A `Band`'s ground can carry a grain or pattern overlay.
980
+
981
+ `<Band separation="ground">` now spends `--cue-paint-texture`, `-texture-size`,
982
+ `-texture-opacity` and `-texture-blend`, so a `[data-paint]` pack can lay a noise tile or
983
+ a repeating pattern over the band's ground without touching the component.
984
+
985
+ **Nothing changes unless you ask.** At the defaults `texture` is `none` and the overlay
986
+ paints nothing — measured against the same band with _no_ overlay element at all, which is
987
+ the comparison that matters, since the change adds a `::before` where there was none.
988
+
989
+ The overlay is `pointer-events-none` and covers its host exactly, so it never intercepts a
990
+ click or disturbs the band's own background.
991
+
992
+ `--cue-paint-texture` takes a `data:` URI or an absolute `https://` URL and nothing else —
993
+ the token layer ships no binary, and the build says so by name if you try something else.
994
+
995
+ ### Patch Changes
996
+
997
+ - ac712b3: `ThemeProvider`'s `nonce` now documents what it does not reach, which matters more than what it does.
998
+
999
+ Nothing about the prop's behaviour changes. What changes is that its documentation — the prop's
1000
+ own docblock, and so the manifest an agent reads — stops promising coverage it never had. If you
1001
+ serve a nonce-based Content-Security-Policy, five things are worth checking:
1002
+
1003
+ - **Your pre-paint `<script>` needs the nonce by hand.** `prepaintScript()` returns the script's
1004
+ text; the element is yours, and Next.js never nonces a plain `<script>`.
1005
+ - **The density layer reads the nonce from this prop only.** Not from an outer `CSPProvider`, and
1006
+ not from an outer `ThemeProvider` — a nested provider that sets its own `overrides.densities`
1007
+ needs its own `nonce`. If you render your own `CSPProvider` and leave this prop unset, Base UI's
1008
+ pre-hydration `<script>` takes its nonce in server-rendered HTML and its scrollbar rule takes it
1009
+ wherever React creates that rule in the browser; the density layer, if you set
1010
+ `overrides.densities`, is not covered.
1011
+ - **A server-rendered ScrollArea's Base UI style ships without a nonce under Next.js 16**, whatever
1012
+ this prop or your own `CSPProvider` says: React's server renderer (19.2, and the canary Next.js 16
1013
+ bundles) writes that element's nonce only from a style-specific render option that Next does not
1014
+ pass. Allow it by hash —
1015
+ `'sha256-kLmvWqfziFavKtqHqRsb90f006UAK2Dmd0It5Iz2KFA='` for Base UI 1.7.0 — or switch Base UI's
1016
+ element off and ship its two rules yourself.
1017
+ - **Re-rendering your own `CSPProvider` inside needs the nonce on it.** If you turn on Base UI's
1018
+ `disableStyleElements`, render `<CSPProvider nonce={nonce} disableStyleElements>` inside
1019
+ `ThemeProvider`'s children — with the nonce, or Base UI's pre-hydration `<script>` below it loses
1020
+ it.
1021
+ - **A policy whose `style-src` (or, without one, `default-src`) carries a nonce or a hash, or lacks
1022
+ `'unsafe-inline'`, needs an explicit `style-src-attr 'unsafe-inline'`.** A nonce cannot cover a
1023
+ style attribute, the provider root and many components carry one, and a nonce or hash in the
1024
+ governing list makes the browser ignore `'unsafe-inline'`.
1025
+
1026
+ This also corrects three earlier notes. 0.14.1 said Base UI's element appears wherever a Select, a
1027
+ Popover or a ScrollArea does: a Popover never renders it, and a Select renders it only once its popup
1028
+ mounts in the browser. 0.14.0 said nothing else in this library emits a `<style>` element:
1029
+ `ThemeConfigurator` does, with no nonce. And 0.14.0 said `style-src-attr` is `'unsafe-inline'` or
1030
+ `'none'` and that only `'none'` drops the root's declarations: a nonce in `style-src` drops them too
1031
+ when no `style-src-attr` is set, and `'unsafe-hashes'` with a hash of each value is a third form. `docs/CONSUMING.md` §4.5 has the whole of it, including
1032
+ `paint="grain"` needing `img-src data:`, statically rendered pages, and rolling out under
1033
+ `Content-Security-Policy-Report-Only` first.
1034
+
1035
+ - 3fc83a6: Four more look packs: `hatch`, `lift`, `frost` and `bevel`.
1036
+
1037
+ `<ThemeProvider paint="frost">` — or `data-paint` on any element — now picks from six
1038
+ finishes rather than two:
1039
+
1040
+ - **`hatch`** lays a faint diagonal weave under a band's ground and puts a hairline ring on
1041
+ the panels and cards above it.
1042
+ - **`lift`** deepens the shadow ladder and adds a lit top edge, so overlays read as sitting
1043
+ above the page rather than in it.
1044
+ - **`frost`** is heavy glass on the chrome, a long edge fade, and a shadow that reads as
1045
+ distance.
1046
+ - **`bevel`** gives surfaces a gradient edge that catches light at the top and loses it at
1047
+ the bottom, with a lighter glass over the chrome.
1048
+
1049
+ **No pack names a colour of its own.** Every ink is a share of the theme's own palette, so
1050
+ each of the six reads correctly under all ten shipped themes rather than carrying one
1051
+ site's blue into the others — and the build refuses a literal hue by name if one is ever
1052
+ written.
1053
+
1054
+ Each pack is a complete statement of a finish rather than a diff against whatever is above
1055
+ it, so switching between them — or nesting one inside another — changes only what the pack
1056
+ is for. `paint="none"` inside a packed subtree really does reset it, and still renders
1057
+ identically to no pack at all.
1058
+
1059
+ `@cueplusplus/ui`'s manifest records the four new pack values against the three components that stamp the axis, which is how the studio and the docs playground know to offer them.
1060
+
1061
+ - f12d280: The READMEs now describe the package you install, not the one from three releases ago.
1062
+
1063
+ `@cueplusplus/tokens`'s README opened by calling itself "two of the system's three DOM axes" and
1064
+ called `axes.css` "the two axes". It is four of five — density, font, style set and paint live
1065
+ here, and the fifth, `[data-theme]`, is the theme packages' — so its axis table gains `[data-style]`
1066
+ (page composition, 13 names) and `[data-paint]` (the finish, 18 names and 13 inks, off until a page
1067
+ stamps it), its export table names `STYLE_SETS`, `PAINTS`, the style and paint contracts and the
1068
+ paint inks beside the rest, and its quick start says the rule that applies to `DENSITIES` applies
1069
+ to all four: build a picker from the exported list, never a hand-written one.
1070
+
1071
+ `@cueplusplus/ui`'s quick start now says what the provider's four axes each change, that `paint` is
1072
+ off until you pass a pack, and where the seven packs and a nonce-based Content-Security-Policy are
1073
+ written up — including that `paint="grain"` needs `img-src data:`. It also says which axes a
1074
+ subtree can change: `<Density>` re-scopes `density`, `styleSet` and `paint`, and the font pairing is
1075
+ the root's alone, because it lives on `<html>`.
1076
+
1077
+ - Updated dependencies [e53619a]
1078
+ - Updated dependencies [840aa92]
1079
+ - Updated dependencies [4eb3b42]
1080
+ - Updated dependencies [3fc83a6]
1081
+ - Updated dependencies [3d0c3fd]
1082
+ - Updated dependencies [0371094]
1083
+ - Updated dependencies [f12d280]
1084
+ - @cueplusplus/tokens@0.16.0
1085
+
3
1086
  ## 0.15.0
4
1087
 
5
1088
  ### Minor Changes