@cueplusplus/ui 0.14.1 → 0.16.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 (182) hide show
  1. package/CHANGELOG.md +415 -0
  2. package/README.md +26 -0
  3. package/dist/agent-runtime/tool-call-card.js +1 -1
  4. package/dist/chat/message-list.js +2 -1
  5. package/dist/chat/message.js +1 -1
  6. package/dist/chrome/_tabs-scroll.d.ts +17 -1
  7. package/dist/chrome/_tabs-scroll.js +20 -3
  8. package/dist/chrome/app-bar.js +2 -1
  9. package/dist/chrome/band.js +13 -5
  10. package/dist/chrome/eyebrow.js +1 -1
  11. package/dist/chrome/footer.js +1 -1
  12. package/dist/chrome/panel.js +2 -1
  13. package/dist/chrome/section-header.js +1 -1
  14. package/dist/color/color-field.d.ts +2 -1
  15. package/dist/color/color-picker.d.ts +2 -1
  16. package/dist/configurator/configurator.js +1 -1
  17. package/dist/configurator/export-dialog.js +1 -1
  18. package/dist/configurator/panel-sections.js +1 -1
  19. package/dist/configurator/token-editor.js +1 -1
  20. package/dist/date/calendar.js +2 -2
  21. package/dist/date/date-field.d.ts +2 -1
  22. package/dist/date/date-picker.d.ts +2 -1
  23. package/dist/date/date-range-picker.d.ts +2 -1
  24. package/dist/date/time-field.d.ts +2 -1
  25. package/dist/elements/context-usage.js +3 -3
  26. package/dist/elements/transcript-rules.js +1 -1
  27. package/dist/forms/_chassis-size.d.ts +22 -0
  28. package/dist/forms/_chassis.d.ts +3 -10
  29. package/dist/forms/_chassis.js +2 -1
  30. package/dist/forms/autocomplete.d.ts +2 -1
  31. package/dist/forms/combobox.d.ts +2 -1
  32. package/dist/forms/env-var-input.d.ts +2 -1
  33. package/dist/forms/field.js +1 -1
  34. package/dist/forms/index.d.ts +2 -1
  35. package/dist/forms/input-group.d.ts +2 -1
  36. package/dist/forms/input.d.ts +2 -1
  37. package/dist/forms/multi-select.d.ts +2 -1
  38. package/dist/forms/otp-field.d.ts +2 -1
  39. package/dist/forms/password-input.d.ts +2 -1
  40. package/dist/forms/scrub-input.d.ts +2 -1
  41. package/dist/forms/search-input.d.ts +2 -1
  42. package/dist/forms/select.d.ts +2 -1
  43. package/dist/forms/select.js +2 -1
  44. package/dist/forms/slider.js +1 -1
  45. package/dist/forms/tags-input.d.ts +2 -1
  46. package/dist/forms/toggle-group.d.ts +1 -1
  47. package/dist/forms/toggle.d.ts +1 -1
  48. package/dist/index.d.ts +2 -1
  49. package/dist/instruments/code-block.js +1 -1
  50. package/dist/instruments/ledger.js +1 -1
  51. package/dist/instruments/log-viewer.js +2 -1
  52. package/dist/instruments/progress.js +1 -1
  53. package/dist/instruments/stat.js +1 -1
  54. package/dist/instruments/table.js +2 -2
  55. package/dist/instruments/terminal-frame.js +1 -1
  56. package/dist/layout/_ground.js +1 -1
  57. package/dist/layout/card.js +3 -1
  58. package/dist/layout/collapsible.js +1 -1
  59. package/dist/layout/description-list.js +1 -1
  60. package/dist/layout/preview.d.ts +13 -1
  61. package/dist/layout/preview.js +16 -9
  62. package/dist/layout/sidebar.js +1 -1
  63. package/dist/layout/stepper.js +1 -1
  64. package/dist/midi/musical-time-input.d.ts +2 -1
  65. package/dist/overlays/_surface.d.ts +2 -2
  66. package/dist/overlays/_surface.js +4 -2
  67. package/dist/overlays/command-palette.js +1 -1
  68. package/dist/overlays/toast.js +1 -1
  69. package/dist/primitives/button.js +2 -1
  70. package/dist/primitives/chip.d.ts +1 -1
  71. package/dist/primitives/chip.js +2 -2
  72. package/dist/system/_paint-elevation.js +9 -0
  73. package/dist/system/_paint-glass.js +46 -0
  74. package/dist/system/_paint-glow.js +32 -0
  75. package/dist/system/_paint-ground-pattern.js +30 -0
  76. package/dist/system/_paint-rim.js +41 -0
  77. package/dist/system/_paint-stroke-sunken.js +19 -0
  78. package/dist/system/_paint-stroke-surface-1.js +19 -0
  79. package/dist/system/_paint-stroke-surface-2.js +27 -0
  80. package/dist/system/_paint-texture.js +53 -0
  81. package/dist/system/density.d.ts +11 -2
  82. package/dist/system/density.js +29 -9
  83. package/dist/system/portal.js +8 -2
  84. package/dist/system/prepaint.d.ts +18 -1
  85. package/dist/system/prepaint.js +8 -2
  86. package/dist/system/theme-provider.d.ts +64 -38
  87. package/dist/system/theme-provider.js +70 -23
  88. package/dist/system/vocabulary.d.ts +1 -1
  89. package/dist/system/vocabulary.js +14 -2
  90. package/manifest/components/alert-dialog.json +13 -1
  91. package/manifest/components/app-bar.json +4 -0
  92. package/manifest/components/autocomplete.json +13 -1
  93. package/manifest/components/band.json +9 -2
  94. package/manifest/components/button.json +4 -0
  95. package/manifest/components/calendar.json +3 -1
  96. package/manifest/components/card.json +6 -0
  97. package/manifest/components/channel-matrix.json +13 -1
  98. package/manifest/components/chart-tooltip-content.json +13 -1
  99. package/manifest/components/chip.json +1 -0
  100. package/manifest/components/code-block.json +2 -1
  101. package/manifest/components/collapsible.json +2 -1
  102. package/manifest/components/color-field.json +4 -0
  103. package/manifest/components/color-picker.json +4 -0
  104. package/manifest/components/colors-section.json +2 -1
  105. package/manifest/components/combobox.json +13 -1
  106. package/manifest/components/command-palette.json +13 -1
  107. package/manifest/components/composer.json +4 -0
  108. package/manifest/components/context-menu.json +13 -1
  109. package/manifest/components/context-usage.json +1 -0
  110. package/manifest/components/date-field.json +4 -0
  111. package/manifest/components/date-picker.json +4 -0
  112. package/manifest/components/date-range-picker.json +4 -0
  113. package/manifest/components/density.json +19 -0
  114. package/manifest/components/description-list.json +2 -1
  115. package/manifest/components/dialog.json +13 -1
  116. package/manifest/components/disclosure.json +2 -1
  117. package/manifest/components/dmx-bar.json +13 -1
  118. package/manifest/components/dmx-strip.json +13 -1
  119. package/manifest/components/drawer.json +13 -1
  120. package/manifest/components/dropdown-menu.json +13 -1
  121. package/manifest/components/env-var-input.json +4 -0
  122. package/manifest/components/export-dialog.json +2 -1
  123. package/manifest/components/eyebrow.json +2 -1
  124. package/manifest/components/field-description.json +2 -1
  125. package/manifest/components/field-error.json +2 -1
  126. package/manifest/components/field-label.json +2 -1
  127. package/manifest/components/field.json +2 -1
  128. package/manifest/components/footer.json +1 -0
  129. package/manifest/components/frames.json +2 -1
  130. package/manifest/components/hover-card.json +13 -1
  131. package/manifest/components/input-group.json +4 -0
  132. package/manifest/components/input.json +4 -0
  133. package/manifest/components/ledger.json +2 -1
  134. package/manifest/components/log-viewer.json +7 -0
  135. package/manifest/components/menubar.json +13 -1
  136. package/manifest/components/message-list.json +7 -0
  137. package/manifest/components/message.json +2 -1
  138. package/manifest/components/multi-select.json +13 -1
  139. package/manifest/components/musical-time-input.json +4 -0
  140. package/manifest/components/navigation-menu.json +13 -1
  141. package/manifest/components/number-field.json +4 -0
  142. package/manifest/components/otp-field.json +4 -0
  143. package/manifest/components/panel-header.json +2 -0
  144. package/manifest/components/panel.json +2 -0
  145. package/manifest/components/password-input.json +4 -0
  146. package/manifest/components/popover.json +13 -1
  147. package/manifest/components/preset-section.json +2 -1
  148. package/manifest/components/preview.json +21 -1
  149. package/manifest/components/progress.json +2 -1
  150. package/manifest/components/scrollable-tabs-list.json +1 -0
  151. package/manifest/components/scrub-input.json +4 -0
  152. package/manifest/components/search-input.json +4 -0
  153. package/manifest/components/section-header.json +2 -1
  154. package/manifest/components/segmented-control.json +1 -0
  155. package/manifest/components/select.json +11 -0
  156. package/manifest/components/shape-section.json +2 -1
  157. package/manifest/components/sheet.json +13 -1
  158. package/manifest/components/sidebar.json +2 -1
  159. package/manifest/components/slider.json +2 -1
  160. package/manifest/components/stat.json +1 -0
  161. package/manifest/components/stepper.json +2 -1
  162. package/manifest/components/table-scroll-region.json +2 -1
  163. package/manifest/components/table.json +2 -1
  164. package/manifest/components/tabs.json +1 -0
  165. package/manifest/components/tags-input.json +13 -1
  166. package/manifest/components/terminal-frame.json +1 -0
  167. package/manifest/components/textarea.json +4 -0
  168. package/manifest/components/theme-configurator.json +13 -1
  169. package/manifest/components/theme-provider.json +20 -1
  170. package/manifest/components/time-boundary.json +2 -1
  171. package/manifest/components/time-field.json +4 -0
  172. package/manifest/components/toast.json +13 -0
  173. package/manifest/components/toggle-group.json +1 -19
  174. package/manifest/components/toggle.json +0 -6
  175. package/manifest/components/token-editor.json +2 -1
  176. package/manifest/components/tool-call-card.json +2 -1
  177. package/manifest/components/toolbar.json +1 -0
  178. package/manifest/components/tooltip.json +13 -1
  179. package/manifest/components/unread-divider.json +2 -1
  180. package/manifest/manifest.json +94 -94
  181. package/manifest/tokens.json +48 -2
  182. package/package.json +6 -6
package/CHANGELOG.md CHANGED
@@ -1,5 +1,420 @@
1
1
  # @cueplusplus/ui
2
2
 
3
+ ## 0.16.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 42021e4: Every overlay draws its shadow from a composite a look pack can move.
8
+
9
+ Dialogs, menus, popovers, tooltips, toasts, drawers, sheets, the command palette, the
10
+ select and combobox popups and the log viewer's jump button all drew
11
+ `shadow-[0_8px_24px_rgba(0,0,0,0.4)]` — the same literal in four places. They now share
12
+ one four-layer recipe: a hairline, a contact shadow, a bloom and an inset top light.
13
+
14
+ **Nothing looks different.** At the defaults three of the four layers are transparent and
15
+ the bloom is that exact literal. Measured rather than asserted: in Chromium the recipe and
16
+ the literal render byte for byte; in WebKit 42 channels of roughly 264,000 differ by 1/255,
17
+ which is compositing rounding and below what a display can show.
18
+
19
+ What it buys is that `--cue-paint-shadow-scale` moves the whole ladder at once and any
20
+ layer switches off by letting its ink resolve to `transparent` — so a pack can give every
21
+ floating surface a deeper shadow, a tighter one, or a lit top edge, without touching a
22
+ component.
23
+
24
+ Overlays also adopt the gradient stroke deferred from the previous release, and keep their
25
+ own rim colour while doing it: the recipe's stops fall back to `--cue-border-overlay`, not
26
+ `--cue-border`, because some themes match that token to the surface on purpose so the rim
27
+ vanishes.
28
+
29
+ `AppWindowFrame` keeps its literal shadow. Its bloom is twice as dark as every other
30
+ surface's, and giving it the shared recipe would have lightened it.
31
+
32
+ - 6e2fd3b: Every edge fade in the library follows one token.
33
+
34
+ `Tabs`, `Toolbar`, `SegmentedControl`, `ScrollableTabsList` and `AppBar` soften their
35
+ overflowing edges with a mask that reached in a fixed 24px. That distance is
36
+ `--cue-paint-fade-length` now, so a `[data-paint]` pack can make every one of them
37
+ shorter or longer at once.
38
+
39
+ **Nothing looks different.** The token's default is the same 24px, measured pixel for
40
+ pixel in Chromium and WebKit — with a 64px override in the same test, so the comparison
41
+ is one that could have failed.
42
+
43
+ `edgeFadeMask(edges, fadePx)` is unchanged when you pass a reach of your own: an explicit
44
+ number still wins, because a caller that has measured its own fade is not asking for the
45
+ axis's.
46
+
47
+ - 40c9de0: `AppBar`'s frosted glass is a look pack's to change, and a consumer's backdrop utilities still work.
48
+
49
+ The bar drew `bg-surface-1/95 backdrop-blur`. It now spends `--cue-paint-glass-filter` and
50
+ `--cue-paint-glass-ink`, so a `[data-paint]` pack can make the chrome heavier, clearer, or
51
+ tinted — or turn the blur off entirely — without touching the component.
52
+
53
+ **Nothing looks different**, measured pixel for pixel against what the bar drew before, in
54
+ Chromium and WebKit, over a hard-edged background so the blur has something to smear.
55
+
56
+ **And `className` still composes.** This is the part worth knowing if you style `AppBar`
57
+ from outside: passing `backdrop-brightness-50` or `backdrop-saturate-150` through
58
+ `className` adds to the bar's blur rather than replacing it. The obvious implementation —
59
+ a plain `backdrop-filter` declaration — would have silently deleted the blur the moment you
60
+ passed any backdrop utility of your own. That case is now a test.
61
+
62
+ The opaque fallback behind `@supports not (backdrop-filter: …)` is unchanged: a browser
63
+ without backdrop filters still gets a solid bar rather than a translucent one over the page.
64
+
65
+ - e53619a: The first look pack: `halo`, and the glow it paints.
66
+
67
+ `<ThemeProvider paint="halo">` — or `data-paint="halo"` on any element — gives primary
68
+ buttons a soft two-stop glow in the theme's own accent, doubling on hover. It is the first
69
+ value the paint axis has other than `none`, so it is also the first time the axis changes
70
+ what a page looks like rather than only standing ready to.
71
+
72
+ **Nothing changes unless you ask.** Unstamped, both stops have zero blur and a transparent
73
+ ink, so the button renders exactly as it did — measured pixel for pixel in Chromium and
74
+ WebKit, alongside the other half of the same test: that stamping `halo` does change it.
75
+
76
+ A pack names no colour of its own. `halo`'s two inks are a share of `--cue-accent`, so it
77
+ reads correctly under all ten shipped themes rather than carrying one palette's blue into
78
+ the others.
79
+
80
+ Two fixes ride along. `--cue-paint-glow-blur` and `-blur-far` were validated against the
81
+ rim's 0–4px rule, so no usable halo radius was accepted — the first pack to set one was
82
+ refused at 12px. They take 0–64px now. And `Button`'s `primary` tone is the only component
83
+ that spends the glow; every other tone is untouched.
84
+
85
+ - 3d0c3fd: A seventh look pack: `grain`, a fine fractal noise over every surface.
86
+
87
+ `<ThemeProvider paint="grain">`, or `<Density paint="grain">` over a subtree, lays a
88
+ 200×200 fractal-noise tile across the surfaces that carry the texture recipe. It is the
89
+ quietest pack in the catalogue by design — 12% opacity, no blend mode — and it is the
90
+ only one that spends `--cue-paint-texture`, a name the library has carried since the
91
+ texture slice with nothing able to use it.
92
+
93
+ Measured from greptile.com, whose ground is an `feTurbulence fractalNoise` data URI at
94
+ 0.85 baseFrequency over five octaves, composited at roughly 12% effective opacity across
95
+ every pixel of the site. The tile here is that filter at those parameters, generated
96
+ rather than copied: it is 331 bytes of SVG inline in the pack, so nothing is fetched and
97
+ no asset ships.
98
+
99
+ **It is deliberately below the bar.** Every other pack clears the threshold this system
100
+ sets for shipping one; `grain` reaches about 62% of its site and ships anyway, as the
101
+ proof that a pack is worth having for what it refuses as much as for what it paints. Its
102
+ `refuses` note names the four of six screens it cannot claim, the twelve divider forms
103
+ and the band-frame furniture that belong to components rather than to a finish, the
104
+ hexagon control silhouette, and the handwriting type stack.
105
+
106
+ Nothing changes for a page that does not ask for it: `grain` is opt-in like every pack,
107
+ and the provider still stamps no `data-paint` at all.
108
+
109
+ - 4d851a0: `Panel` and `Card` can take an inset ring, and a `Band`'s ground can take a repeating pattern.
110
+
111
+ Two more devices reach the paint axis, which means every one of its thirty-one names is now
112
+ spent by something: `--cue-paint-rim-width` and `-rim-ink` draw a hairline ring inside a
113
+ panel's or a card's radius, and `--cue-paint-ground-pattern` with `-size` lays a repeating
114
+ geometry under a band's content.
115
+
116
+ **Nothing changes unless you ask.** The ring's width is `0px` and its ink is transparent;
117
+ the pattern is `none`. Measured pixel for pixel in Chromium and WebKit, with both devices
118
+ switched on in the same tests so the comparisons are ones that could have failed.
119
+
120
+ The ring is a `box-shadow`, so a `Band` or a `Card` that already draws one cannot take it —
121
+ and **form controls deliberately do not**. `forced-colors: active` discards shadows
122
+ entirely, and a control's ring is a focus indicator: it stays a real outline, which is what
123
+ a forced-colors user actually sees.
124
+
125
+ A pattern and a texture are different layers and compose: a pattern is the host's own
126
+ background image, a texture is noise on a pseudo-element above it.
127
+
128
+ - 5fcc6b4: Form controls and cards draw their border as a gradient stroke, so a look pack can tint it.
129
+
130
+ `Input`, `Textarea`, `Select`, `Combobox`, `Autocomplete`, `SearchInput`, `OTPField`,
131
+ `InputGroup`, the date and colour fields, `MusicalTimeInput` and the rest of the recessed
132
+ control family — and `Card` — now paint their line from two background layers with a
133
+ transparent border between them, rather than from `border border-border`.
134
+
135
+ **Nothing looks different.** At the defaults both gradient stops are `--cue-border` and a
136
+ one-colour gradient paints a flat field, so the line is the same one device-pixel of the
137
+ same colour over the same fill. That is measured rather than asserted: the straight edges
138
+ and the interior are pixel-identical in Chromium and WebKit, and with square corners the
139
+ two are identical everywhere. On a rounded corner they differ by sub-pixel antialiasing —
140
+ invisible at 1×, and bounded by the test rather than claimed away.
141
+
142
+ What it buys is that `--cue-paint-stroke-from`, `-to`, `-angle` and `-width` now reach
143
+ every one of those surfaces, so a `[data-paint]` pack can give the whole family a gradient
144
+ edge, a thicker rule or a different angle without touching a component.
145
+
146
+ A seamed `Card` keeps its old border: its fill is `--cue-border` — the gaps between its
147
+ rows _are_ the line — and the recipe is keyed by fill.
148
+
149
+ `Toggle` and `ToggleGroup` also lose ten custom properties from their published manifests.
150
+ They never painted them: the entries came from a type-only import of the control chassis,
151
+ and the manifest lists what a component spends. `--cue-sunken`, `--cue-focus` and
152
+ `--cue-border` were among them, so this was wrong before the gradient stroke existed.
153
+
154
+ - bcd0738: A `Band`'s ground can carry a grain or pattern overlay.
155
+
156
+ `<Band separation="ground">` now spends `--cue-paint-texture`, `-texture-size`,
157
+ `-texture-opacity` and `-texture-blend`, so a `[data-paint]` pack can lay a noise tile or
158
+ a repeating pattern over the band's ground without touching the component.
159
+
160
+ **Nothing changes unless you ask.** At the defaults `texture` is `none` and the overlay
161
+ paints nothing — measured against the same band with _no_ overlay element at all, which is
162
+ the comparison that matters, since the change adds a `::before` where there was none.
163
+
164
+ The overlay is `pointer-events-none` and covers its host exactly, so it never intercepts a
165
+ click or disturbs the band's own background.
166
+
167
+ `--cue-paint-texture` takes a `data:` URI or an absolute `https://` URL and nothing else —
168
+ the token layer ships no binary, and the build says so by name if you try something else.
169
+
170
+ ### Patch Changes
171
+
172
+ - ac712b3: `ThemeProvider`'s `nonce` now documents what it does not reach, which matters more than what it does.
173
+
174
+ Nothing about the prop's behaviour changes. What changes is that its documentation — the prop's
175
+ own docblock, and so the manifest an agent reads — stops promising coverage it never had. If you
176
+ serve a nonce-based Content-Security-Policy, five things are worth checking:
177
+
178
+ - **Your pre-paint `<script>` needs the nonce by hand.** `prepaintScript()` returns the script's
179
+ text; the element is yours, and Next.js never nonces a plain `<script>`.
180
+ - **The density layer reads the nonce from this prop only.** Not from an outer `CSPProvider`, and
181
+ not from an outer `ThemeProvider` — a nested provider that sets its own `overrides.densities`
182
+ needs its own `nonce`. If you render your own `CSPProvider` and leave this prop unset, Base UI's
183
+ pre-hydration `<script>` takes its nonce in server-rendered HTML and its scrollbar rule takes it
184
+ wherever React creates that rule in the browser; the density layer, if you set
185
+ `overrides.densities`, is not covered.
186
+ - **A server-rendered ScrollArea's Base UI style ships without a nonce under Next.js 16**, whatever
187
+ this prop or your own `CSPProvider` says: React's server renderer (19.2, and the canary Next.js 16
188
+ bundles) writes that element's nonce only from a style-specific render option that Next does not
189
+ pass. Allow it by hash —
190
+ `'sha256-kLmvWqfziFavKtqHqRsb90f006UAK2Dmd0It5Iz2KFA='` for Base UI 1.7.0 — or switch Base UI's
191
+ element off and ship its two rules yourself.
192
+ - **Re-rendering your own `CSPProvider` inside needs the nonce on it.** If you turn on Base UI's
193
+ `disableStyleElements`, render `<CSPProvider nonce={nonce} disableStyleElements>` inside
194
+ `ThemeProvider`'s children — with the nonce, or Base UI's pre-hydration `<script>` below it loses
195
+ it.
196
+ - **A policy whose `style-src` (or, without one, `default-src`) carries a nonce or a hash, or lacks
197
+ `'unsafe-inline'`, needs an explicit `style-src-attr 'unsafe-inline'`.** A nonce cannot cover a
198
+ style attribute, the provider root and many components carry one, and a nonce or hash in the
199
+ governing list makes the browser ignore `'unsafe-inline'`.
200
+
201
+ This also corrects three earlier notes. 0.14.1 said Base UI's element appears wherever a Select, a
202
+ Popover or a ScrollArea does: a Popover never renders it, and a Select renders it only once its popup
203
+ mounts in the browser. 0.14.0 said nothing else in this library emits a `<style>` element:
204
+ `ThemeConfigurator` does, with no nonce. And 0.14.0 said `style-src-attr` is `'unsafe-inline'` or
205
+ `'none'` and that only `'none'` drops the root's declarations: a nonce in `style-src` drops them too
206
+ 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
207
+ `paint="grain"` needing `img-src data:`, statically rendered pages, and rolling out under
208
+ `Content-Security-Policy-Report-Only` first.
209
+
210
+ - 3fc83a6: Four more look packs: `hatch`, `lift`, `frost` and `bevel`.
211
+
212
+ `<ThemeProvider paint="frost">` — or `data-paint` on any element — now picks from six
213
+ finishes rather than two:
214
+
215
+ - **`hatch`** lays a faint diagonal weave under a band's ground and puts a hairline ring on
216
+ the panels and cards above it.
217
+ - **`lift`** deepens the shadow ladder and adds a lit top edge, so overlays read as sitting
218
+ above the page rather than in it.
219
+ - **`frost`** is heavy glass on the chrome, a long edge fade, and a shadow that reads as
220
+ distance.
221
+ - **`bevel`** gives surfaces a gradient edge that catches light at the top and loses it at
222
+ the bottom, with a lighter glass over the chrome.
223
+
224
+ **No pack names a colour of its own.** Every ink is a share of the theme's own palette, so
225
+ each of the six reads correctly under all ten shipped themes rather than carrying one
226
+ site's blue into the others — and the build refuses a literal hue by name if one is ever
227
+ written.
228
+
229
+ Each pack is a complete statement of a finish rather than a diff against whatever is above
230
+ it, so switching between them — or nesting one inside another — changes only what the pack
231
+ is for. `paint="none"` inside a packed subtree really does reset it, and still renders
232
+ identically to no pack at all.
233
+
234
+ `@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.
235
+
236
+ - f12d280: The READMEs now describe the package you install, not the one from three releases ago.
237
+
238
+ `@cueplusplus/tokens`'s README opened by calling itself "two of the system's three DOM axes" and
239
+ called `axes.css` "the two axes". It is four of five — density, font, style set and paint live
240
+ here, and the fifth, `[data-theme]`, is the theme packages' — so its axis table gains `[data-style]`
241
+ (page composition, 13 names) and `[data-paint]` (the finish, 18 names and 13 inks, off until a page
242
+ stamps it), its export table names `STYLE_SETS`, `PAINTS`, the style and paint contracts and the
243
+ paint inks beside the rest, and its quick start says the rule that applies to `DENSITIES` applies
244
+ to all four: build a picker from the exported list, never a hand-written one.
245
+
246
+ `@cueplusplus/ui`'s quick start now says what the provider's four axes each change, that `paint` is
247
+ off until you pass a pack, and where the seven packs and a nonce-based Content-Security-Policy are
248
+ written up — including that `paint="grain"` needs `img-src data:`. It also says which axes a
249
+ subtree can change: `<Density>` re-scopes `density`, `styleSet` and `paint`, and the font pairing is
250
+ the root's alone, because it lives on `<html>`.
251
+
252
+ - Updated dependencies [e53619a]
253
+ - Updated dependencies [840aa92]
254
+ - Updated dependencies [4eb3b42]
255
+ - Updated dependencies [3fc83a6]
256
+ - Updated dependencies [3d0c3fd]
257
+ - Updated dependencies [0371094]
258
+ - Updated dependencies [f12d280]
259
+ - @cueplusplus/tokens@0.16.0
260
+
261
+ ## 0.15.0
262
+
263
+ ### Minor Changes
264
+
265
+ - 5493c5a: A style set can now say what colour the line between two bands is.
266
+
267
+ `band-rule` was only ever its WIDTH. The colour was the literal string
268
+ `border-border`, spelled twice — once in `SEPARATION_PAINT` and once in
269
+ `Footer`'s own class list — so a set could say how thick the rule is and had no
270
+ way to say what it was made of.
271
+
272
+ `--cue-band-rule-color` joins the style-set contract, which becomes six required
273
+ names. It takes `var(--cue-border)`, `var(--cue-border-subtle)`,
274
+ `var(--cue-border-strong)` or `transparent` — structural inks only, because a
275
+ brand colour on a structural line belongs to a different axis. The `:root`
276
+ default and all three shipped sets declare `var(--cue-border)`, which is
277
+ byte-for-byte what both call sites drew before, so this is a no-op until a set
278
+ spends it.
279
+
280
+ Measured across thirteen reference sites on 2026-09-22: every one that separates
281
+ bands by a line picks a line lighter than its box edge. `--cue-border` is a box
282
+ edge, and repeating a box edge between sections is what `--cue-border-subtle`'s
283
+ own docblock argues against one layer down. Until now no axis could express the
284
+ difference.
285
+
286
+ - c6e26c0: `Density`, `Preview` and portals carry the paint axis
287
+
288
+ `<Density paint>` and `<Preview paint>` stamp `data-paint` on their subtree, and
289
+ a portal opened inside either follows it — the same three-publisher arrangement
290
+ the style axis already has, for the same reason: a portal mounts on `<body>` and
291
+ inherits nothing from the DOM it was written in, so it has to be told.
292
+
293
+ ```tsx
294
+ <Density density="compact" paint="none">
295
+ <Toolbar />
296
+ </Density>
297
+
298
+ <Preview paint="none">
299
+ <Card>…</Card>
300
+ </Preview>
301
+ ```
302
+
303
+ **Absent means inherit, and `none` is a value rather than an absence.** An island
304
+ that names no pack stamps no attribute and passes the ambient pack straight
305
+ through; `none` restates the `:root` defaults, which is what a subtree stamps to
306
+ opt _out_ of a pack its parent set. Collapsing the two would make every unpainted
307
+ subtree override its parent instead of inheriting from it.
308
+
309
+ New: `PaintContext`, and a `paint` prop on `DensityProps` and `PreviewProps`.
310
+ `CuePortalStamp` gains a `paint` field.
311
+
312
+ The provider half — a `paint` prop on `<ThemeProvider>`, persistence, and the
313
+ blocking prepaint script — is not here. This is the island path, which works on
314
+ its own: a subtree can re-scope the axis without a provider, exactly as
315
+ `<Density styleSet>` does.
316
+
317
+ - e7a2405: `ThemeProvider` carries the paint axis, and persists it
318
+
319
+ `<ThemeProvider paint>` stamps `data-paint`, `useTheme()` reports it and
320
+ `setPaint()` switches it, and the blocking pre-paint script puts it on `<html>`
321
+ before the first frame — so a page restored from storage does not flash an
322
+ unpainted frame before React commits.
323
+
324
+ ```tsx
325
+ <ThemeProvider theme="cue" paint="none">
326
+ …
327
+ </ThemeProvider>;
328
+
329
+ const { paint, setPaint } = useTheme();
330
+ ```
331
+
332
+ **An app that never touches the axis writes the object it always wrote, byte for
333
+ byte.** The pack is persisted only when there is one — the rule `styleSet`
334
+ already follows — because a `"paint": null` in storage would be a value the
335
+ pre-paint script has to hold an opinion about for ever, for a preference nobody
336
+ expressed.
337
+
338
+ **The root never promotes an ambient pack.** `useTheme().paint` reports the pack
339
+ in force, but the `data-paint` stamp stays on the provider's own state, so a
340
+ `<Density paint>` island cannot become a document-wide attribute and from there
341
+ reach storage and the next load.
342
+
343
+ New: `paint` on `ThemeProviderProps` and `PrepaintDefaults`, `paint` and
344
+ `setPaint` on the `useTheme()` value, `isPaint()` beside `isStyleSet()`, and
345
+ `paint` on `PersistedPreferences`.
346
+
347
+ The skills learn the axis too: `ui-theming` documents five axes rather than four,
348
+ and the generated token reference carries the eighteen paint names — so an agent
349
+ asked to compose a page can find `--cue-paint-glow-blur` instead of spelling a
350
+ shadow literal by hand.
351
+
352
+ - d5c4183: Letter spacing becomes a token a style set can retune.
353
+
354
+ The system had already decided this and never finished it. `leading-ui` is spent
355
+ 63 times through a token against 2 literals. The only tracking name that existed,
356
+ `tracking-label`, was spent **zero** times — while 34 hard-coded `tracking-[…]`
357
+ literals sat across 27 chassis files at six distinct values.
358
+
359
+ Three names join the style-set contract, at the values those literals already
360
+ held: `tracking-caps` (0.15em, 23 call sites), `tracking-caps-tight` (0.1em, 5)
361
+ and `tracking-caps-loose` (0.2em, 1 — `Eyebrow`, the one place the system spends
362
+ the accent on pure typography, so a set that wants a different kicker has
363
+ nowhere else to say so). Two optional names join beside `style-display`:
364
+ `style-tracking-display` and `style-leading-display`, the latter a second name
365
+ rather than a widened `leading-prose` because a display register routinely sits
366
+ under 1 and a paragraph must not.
367
+
368
+ 32 literals become token spends. Two survive deliberately: `tracking-[inherit]`
369
+ on `Stepper`, which is a pass-through rather than a value, and `tracking-[0.06em]`
370
+ on `Chip`'s tag, one call site at a value no other rung shares.
371
+
372
+ `tracking-label` stays in the frozen base and does **not** move. Its three call
373
+ sites now spend `--cue-tracking-label` instead of a literal, which finally makes
374
+ a declared-and-never-spent token do its job.
375
+
376
+ Measured across thirteen reference sites on 2026-09-22: a display tracking is
377
+ missing in twelve of them — more than any single paint device. Apple's curve is
378
+ non-monotone (-0.022em at 17px, +0.012em at 19px, 0 at 40px, -0.015em at 80px);
379
+ vercel wants -0.02/-0.04/-0.06em; stripe -0.025em. None of it was expressible.
380
+
381
+ Every value is unchanged. The defaults restate the literals they replace.
382
+
383
+ ### Patch Changes
384
+
385
+ - 9c7041a: The dot screen and the app bar's glass spend paint tokens
386
+
387
+ `Preview` and `Frames`' dots ground reads `--cue-paint-screen` and
388
+ `--cue-paint-screen-size` instead of spelling the gradient out.
389
+
390
+ **Nothing renders differently, and that is proved in a browser rather than
391
+ argued.** Each token's `:root` default is the value its literal held, so a page
392
+ that never stamps `data-paint` computes exactly what it computed before.
393
+ `tests/browser/paint-noop.spec.ts` measures it on the built site: the adopted
394
+ utility and the literal it replaced compute the same `background-image` and
395
+ `background-size`, and every value is required to be non-`none` first — because two absences would satisfy an equality, and "the dots
396
+ stopped painting" is the regression that guards against.
397
+
398
+ A pack can now retune the finish without touching a component.
399
+
400
+ **One duplicate collapsed.** `apps/docs`' ground picker carried a hand-copied
401
+ second spelling of the same gradient, with a comment saying it was "the same
402
+ gradient `Preview`'s own `dots` ground paints" — and nothing tied the two
403
+ together. Both spend the token now, so they are the same value rather than the
404
+ same text.
405
+
406
+ **`AppBar` keeps `backdrop-blur`.** Adopting `--cue-paint-glass-filter` there was
407
+ tried and reverted: Tailwind composes every backdrop utility into one
408
+ declaration, so a raw `[backdrop-filter:var(…)]` would stop a consumer's
409
+ `backdrop-brightness-50` from combining with the bar's blur. The glass slice
410
+ owns that decision.
411
+
412
+ - Updated dependencies [a20e98e]
413
+ - Updated dependencies [5493c5a]
414
+ - Updated dependencies [96f6f6b]
415
+ - Updated dependencies [d5c4183]
416
+ - @cueplusplus/tokens@0.15.0
417
+
3
418
  ## 0.14.1
4
419
 
5
420
  ### Patch Changes
package/README.md CHANGED
@@ -53,6 +53,32 @@ To stop the defaults flashing on first paint, add `prepaintScript()` beside the
53
53
  both the same array — [§4 of `CONSUMING.md`](https://github.com/cueplusplus/cue-ui/blob/main/docs/CONSUMING.md#4-the-provider)
54
54
  is the whole layout.
55
55
 
56
+ Beside `theme` and `mode`, the provider takes four axes, and each one changes a single thing:
57
+ `density` the geometry, `font` the typeface pairing, `styleSet` the page composition, and `paint`
58
+ the finish — rims, strokes, elevation, glow, glass, texture and edge fades. `paint` is off unless
59
+ you ask for it: the provider stamps no `data-paint`, so a page looks exactly as it did until you
60
+ pass one of `none`, `halo`, `hatch`, `lift`, `frost`, `bevel` or `grain`. Any subtree can take its
61
+ own with `<Density paint="frost">` — the same island that re-scopes `density` and `styleSet`. The
62
+ font pairing is the one axis a subtree cannot change: it lives on `<html>`, so it is the root's.
63
+
64
+ ```tsx
65
+ import cue from "@cueplusplus/theme-cue";
66
+ import { ThemeProvider } from "@cueplusplus/ui/system";
67
+
68
+ export function App({ children }: { children: React.ReactNode }) {
69
+ return (
70
+ <ThemeProvider themes={[cue]} theme="cue" density="compact" mode="system" paint="halo">
71
+ {children}
72
+ </ThemeProvider>
73
+ );
74
+ }
75
+ ```
76
+
77
+ The seven packs, where each was measured from and what each refuses:
78
+ <https://ui.cueplusplus.com/docs/paint>. Serving a nonce-based Content-Security-Policy? Read
79
+ [§4.5 of `CONSUMING.md`](https://github.com/cueplusplus/cue-ui/blob/main/docs/CONSUMING.md#45-content-security-policy-the-nonce-prop-and-what-it-does-not-reach)
80
+ before you ship it — `paint="grain"` alone needs `img-src data:`.
81
+
56
82
  ## What it ships
57
83
 
58
84
  Common components come from the root entry. Groups that need an optional peer have a subpath of
@@ -25,7 +25,7 @@ const DANGER_TONES = {
25
25
  */
26
26
  const HEADER = "flex min-w-0 items-center gap-(--cue-space-2) border-0 bg-transparent p-0 text-start font-mono text-(length:--cue-text-ui) text-fg-muted outline-none focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-accent";
27
27
  /** The label over a block in the body, in the same eyebrow as a message header. */
28
- const EYEBROW = "font-mono text-(length:--cue-text-micro) tracking-[0.15em] uppercase text-fg-subtle";
28
+ const EYEBROW = "font-mono text-(length:--cue-text-micro) tracking-(--cue-tracking-caps) uppercase text-fg-subtle";
29
29
  /**
30
30
  * An LLM's own tool call, shown while it runs and after.
31
31
  *
@@ -2,6 +2,7 @@
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { ChevronDownGlyph } from "./_glyphs.js";
4
4
  import { useIsomorphicLayoutEffect } from "../system/use-isomorphic-layout-effect.js";
5
+ import { ELEVATION_2 } from "../system/_paint-elevation.js";
5
6
  import * as React from "react";
6
7
  import { jsx, jsxs } from "react/jsx-runtime";
7
8
  //#region src/chat/message-list.tsx
@@ -131,7 +132,7 @@ const MessageList = React.forwardRef(function MessageList({ className, children,
131
132
  }), behind ? /* @__PURE__ */ jsxs("button", {
132
133
  type: "button",
133
134
  "data-slot": "message-list-jump",
134
- className: "absolute bottom-(--cue-space-4) left-1/2 flex -translate-x-1/2 cursor-pointer items-center gap-(--cue-space-2) rounded-(--radius-control) border border-border-overlay bg-surface-2 px-(--cue-space-4) py-(--cue-space-2) font-mono text-(length:--cue-text-label) text-fg shadow-[0_8px_24px_rgba(0,0,0,0.4)] outline-none hover:border-accent hover:text-accent focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-1 focus-visible:outline-accent",
135
+ className: `absolute bottom-(--cue-space-4) left-1/2 flex -translate-x-1/2 cursor-pointer items-center gap-(--cue-space-2) rounded-(--radius-control) border border-border-overlay bg-surface-2 px-(--cue-space-4) py-(--cue-space-2) font-mono text-(length:--cue-text-label) text-fg ${ELEVATION_2} outline-none hover:border-accent hover:text-accent focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-1 focus-visible:outline-accent`,
135
136
  onClick: jumpToLatest,
136
137
  children: [/* @__PURE__ */ jsx(ChevronDownGlyph, { className: "size-icon-sm" }), jumpLabel]
137
138
  }) : null]
@@ -72,7 +72,7 @@ const Message = React.forwardRef(function Message({ className, role = "agent", a
72
72
  children: [
73
73
  hasHeader ? /* @__PURE__ */ jsxs("div", {
74
74
  "data-slot": "message-header",
75
- className: "flex min-w-0 items-baseline justify-between gap-(--cue-space-3) font-mono text-(length:--cue-text-micro) tracking-[0.15em] uppercase",
75
+ className: "flex min-w-0 items-baseline justify-between gap-(--cue-space-3) font-mono text-(length:--cue-text-micro) tracking-(--cue-tracking-caps) uppercase",
76
76
  children: [name === void 0 ? null : /* @__PURE__ */ jsx("span", {
77
77
  "data-slot": "message-author",
78
78
  className: cn("min-w-0 truncate", role === "user" ? "text-accent-fg opacity-70" : "text-(--agent-color)"),
@@ -56,8 +56,24 @@ declare function computeScrollEdges(scrollLeft: number, scrollWidth: number, cli
56
56
  * overflowing edge is often the gap between two tabs, and fading empty space is
57
57
  * invisible — hence the chevron buttons in the component.
58
58
  *
59
+ * **The default reach is a custom property, not a number**, so a look pack can
60
+ * lengthen or shorten every edge fade in the library at once. It is written as
61
+ * `var(--cue-paint-fade-length,24px)` with the fallback spelled out, because an
62
+ * ink or a paint name is declared with a `:root` default here but the mask is
63
+ * also built by this function in isolation — a test calling it with no DOM
64
+ * would otherwise produce a gradient with an unresolvable stop.
65
+ *
66
+ * `--cue-paint-fade-length` is `24px` at `:root` and {@link TAB_FADE_PX} is 24,
67
+ * so the swap renders identically: measured pixel for pixel in Chromium and
68
+ * WebKit, with a 64px pack changing 15,360 channels to prove the probe could
69
+ * see a difference.
70
+ *
71
+ * An explicit `fadePx` still wins, and stays a plain number: a caller that has
72
+ * measured its own reach is not asking for the axis's.
73
+ *
59
74
  * @param edges Which edges overflow, from {@link computeScrollEdges}.
60
- * @param fadePx How far the fade reaches in. Defaults to {@link TAB_FADE_PX}.
75
+ * @param fadePx How far the fade reaches in. Omitted, it follows
76
+ * `--cue-paint-fade-length`, whose own default is {@link TAB_FADE_PX}.
61
77
  * @returns A `linear-gradient(...)` value, or `undefined` when nothing
62
78
  * overflows — no mask property at all, rather than a fully opaque one, so the
63
79
  * common case creates no compositing layer.
@@ -59,15 +59,32 @@ function computeScrollEdges(scrollLeft, scrollWidth, clientWidth) {
59
59
  * overflowing edge is often the gap between two tabs, and fading empty space is
60
60
  * invisible — hence the chevron buttons in the component.
61
61
  *
62
+ * **The default reach is a custom property, not a number**, so a look pack can
63
+ * lengthen or shorten every edge fade in the library at once. It is written as
64
+ * `var(--cue-paint-fade-length,24px)` with the fallback spelled out, because an
65
+ * ink or a paint name is declared with a `:root` default here but the mask is
66
+ * also built by this function in isolation — a test calling it with no DOM
67
+ * would otherwise produce a gradient with an unresolvable stop.
68
+ *
69
+ * `--cue-paint-fade-length` is `24px` at `:root` and {@link TAB_FADE_PX} is 24,
70
+ * so the swap renders identically: measured pixel for pixel in Chromium and
71
+ * WebKit, with a 64px pack changing 15,360 channels to prove the probe could
72
+ * see a difference.
73
+ *
74
+ * An explicit `fadePx` still wins, and stays a plain number: a caller that has
75
+ * measured its own reach is not asking for the axis's.
76
+ *
62
77
  * @param edges Which edges overflow, from {@link computeScrollEdges}.
63
- * @param fadePx How far the fade reaches in. Defaults to {@link TAB_FADE_PX}.
78
+ * @param fadePx How far the fade reaches in. Omitted, it follows
79
+ * `--cue-paint-fade-length`, whose own default is {@link TAB_FADE_PX}.
64
80
  * @returns A `linear-gradient(...)` value, or `undefined` when nothing
65
81
  * overflows — no mask property at all, rather than a fully opaque one, so the
66
82
  * common case creates no compositing layer.
67
83
  */
68
- function edgeFadeMask(edges, fadePx = 24) {
84
+ function edgeFadeMask(edges, fadePx) {
69
85
  if (!edges.start && !edges.end) return void 0;
70
- return `linear-gradient(to right, ${edges.start ? `transparent 0px, black ${fadePx}px` : "black 0px"}, ${edges.end ? `black calc(100% - ${fadePx}px), transparent 100%` : "black 100%"})`;
86
+ const reach = fadePx === void 0 ? `var(--cue-paint-fade-length,24px)` : `${fadePx}px`;
87
+ return `linear-gradient(to right, ${edges.start ? `transparent 0px, black ${reach}` : "black 0px"}, ${edges.end ? `black calc(100% - ${reach}), transparent 100%` : "black 100%"})`;
71
88
  }
72
89
  //#endregion
73
90
  export { TAB_FADE_PX, computeScrollEdges, edgeFadeMask };
@@ -2,6 +2,7 @@ import { cn } from "../lib/cn.js";
2
2
  import { Link } from "../layout/link.js";
3
3
  import { Separator } from "../primitives/separator.js";
4
4
  import { EdgeScrollNav } from "./_edge-scroller.js";
5
+ import { GLASS_CLASSES } from "../system/_paint-glass.js";
5
6
  import * as React from "react";
6
7
  import { jsx } from "react/jsx-runtime";
7
8
  //#region src/chrome/app-bar.tsx
@@ -53,7 +54,7 @@ const AppBarRoot = React.forwardRef(function AppBarRoot({ className, sticky = tr
53
54
  return /* @__PURE__ */ jsx("header", {
54
55
  ref,
55
56
  "data-slot": "app-bar",
56
- className: cn("flex h-(--cue-chrome-toolbar) w-full shrink-0 items-center gap-(--cue-space-4) border-b border-border bg-surface-1/95 px-(--cue-space-5) backdrop-blur", sticky ? "sticky top-0 z-40" : null, className),
57
+ className: cn(`flex h-(--cue-chrome-toolbar) w-full shrink-0 items-center gap-(--cue-space-4) border-b border-border px-(--cue-space-5) ${GLASS_CLASSES}`, sticky ? "sticky top-0 z-40" : null, className),
57
58
  ...elementProps
58
59
  });
59
60
  });
@@ -1,6 +1,8 @@
1
1
  import { cn } from "../lib/cn.js";
2
2
  import { Container } from "../layout/container.js";
3
3
  import { bandClasses } from "./_band.js";
4
+ import { TEXTURE_CLASSES } from "../system/_paint-texture.js";
5
+ import { GROUND_PATTERN_CLASSES } from "../system/_paint-ground-pattern.js";
4
6
  import * as React from "react";
5
7
  import { jsx } from "react/jsx-runtime";
6
8
  //#region src/chrome/band.tsx
@@ -16,13 +18,19 @@ import { jsx } from "react/jsx-runtime";
16
18
  * the argument.
17
19
  *
18
20
  * `rule`'s entry is the colour and not the width: the width is
19
- * `--cue-band-rule` and belongs to the chassis, and both elements name
20
- * `border-border` in their own class list rather than inheriting it from the
21
- * other.
21
+ * `--cue-band-rule` and belongs to the chassis, and both elements name the ink
22
+ * in their own class list rather than inheriting it from the other.
23
+ *
24
+ * That ink is now a token. It was the literal `border-border`, spelled here and
25
+ * again in `Footer`, which meant a style set could say how THICK the line
26
+ * between two bands is and had no way to say what colour it was — and every
27
+ * site measured in the 2026-09-22 corpus that separates bands by a line picks
28
+ * one lighter than its box edge. `--cue-band-rule-color` defaults to
29
+ * `var(--cue-border)` on `:root`, which is byte-for-byte what this drew before.
22
30
  */
23
31
  const SEPARATION_PAINT = {
24
- rule: "border-border",
25
- ground: "bg-(--cue-band-ground)",
32
+ rule: "border-(--cue-band-rule-color)",
33
+ ground: `bg-(--cue-band-ground) ${GROUND_PATTERN_CLASSES} ${TEXTURE_CLASSES}`,
26
34
  bleed: null,
27
35
  none: null
28
36
  };
@@ -22,7 +22,7 @@ const Eyebrow = React.forwardRef(function Eyebrow({ className, slashes = true, c
22
22
  return /* @__PURE__ */ jsxs("span", {
23
23
  ref,
24
24
  "data-slot": "eyebrow",
25
- className: cn("inline-flex items-center gap-(--cue-space-2) font-mono text-(length:--cue-text-label) tracking-[0.2em] text-accent uppercase", className),
25
+ className: cn("inline-flex items-center gap-(--cue-space-2) font-mono text-(length:--cue-text-label) tracking-(--cue-tracking-caps-loose) text-accent uppercase", className),
26
26
  ...elementProps,
27
27
  children: [slashes ? /* @__PURE__ */ jsx("span", {
28
28
  "data-slot": "eyebrow-glyph",
@@ -66,7 +66,7 @@ const Footer = React.forwardRef(function Footer({ className, columnClassName, wi
66
66
  ref,
67
67
  "data-slot": "footer",
68
68
  "data-separation": "rule",
69
- className: cn(bandClasses("rule"), "border-border", className),
69
+ className: cn(bandClasses("rule"), "border-(--cue-band-rule-color)", className),
70
70
  ...elementProps,
71
71
  children: /* @__PURE__ */ jsxs(Container, {
72
72
  width,
@@ -1,4 +1,5 @@
1
1
  import { cn } from "../lib/cn.js";
2
+ import { RIM_INSET } from "../system/_paint-rim.js";
2
3
  import * as React from "react";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
4
5
  //#region src/chrome/panel.tsx
@@ -28,7 +29,7 @@ const Panel = React.forwardRef(function Panel({ className, ...elementProps }, re
28
29
  return /* @__PURE__ */ jsx("div", {
29
30
  ref,
30
31
  "data-slot": "panel",
31
- className: cn("overflow-hidden rounded-(--radius-surface) border border-border bg-surface-1", className),
32
+ className: cn(`overflow-hidden rounded-(--radius-surface) border border-border bg-surface-1 ${RIM_INSET}`, className),
32
33
  ...elementProps
33
34
  });
34
35
  });