@astryxdesign/theme-stone 0.7.3 → 0.7.4-canary.10b832e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/stoneTheme.ts CHANGED
@@ -4,65 +4,66 @@
4
4
  * Stone Theme
5
5
  *
6
6
  * A warm, earthy neutral theme inspired by natural stone and sandstone.
7
- * Core palette: #28282A, #84848B, #D8D8DB, #f3f3f5, #FFFFFF
7
+ * Colors reference the reviewed Stone palette generated from palette.config.json.
8
8
  * Montserrat for headings, Figtree for body, JetBrains Mono for code.
9
9
  */
10
10
 
11
11
  import {defineTheme, defineSyntaxTheme} from '@astryxdesign/core/theme';
12
12
  import {stoneIconRegistry} from './icons';
13
+ import {stonePaletteRefs} from './stonePaletteRefs.generated';
14
+
15
+ const {blue, cyan, green, neutral, orange, pink, purple, red, teal, yellow} =
16
+ stonePaletteRefs;
17
+
18
+ const lightDark = (light: string, dark: string): string =>
19
+ `light-dark(${light}, ${dark})`;
20
+ const withAlpha = (color: string, alpha: string): string => `${color}${alpha}`;
13
21
 
14
22
  /**
15
- * Input status border overrides (per-component, per-status). All 9 input
16
- * components share inputStatusBorderStyles in core, which read
17
- * --color-{success,warning,error} (T30 light / T80 dark = saturated text
18
- * tone). Stone redefines those vars inside each input's status scope to
19
- * T60 light / T70 dark so the border (and the matching status icon) reads
20
- * as a softer hue rim, in line with the gentle T90 status message bubble.
23
+ * Input status borders and icons use softer mid-ramp stops than status text.
24
+ * All supported input components share this one mapping so their status
25
+ * treatment remains consistent.
21
26
  */
22
27
  const INPUT_STATUS_VARS = {
23
28
  'status:success': {
24
- '--color-success': 'light-dark(#7f977e, #99b298)', // Green T60 / T70
29
+ '--color-success': lightDark(green.light[55], green.dark[70]),
25
30
  },
26
31
  'status:warning': {
27
- '--color-warning': 'light-dark(#9f8f68, #bbaa81)', // Yellow T60 / T70
32
+ '--color-warning': lightDark(yellow.light[55], yellow.dark[70]),
28
33
  },
29
34
  'status:error': {
30
- '--color-error': 'light-dark(#a58b86, #c0a5a1)', // Red T60 / T70
35
+ '--color-error': lightDark(red.light[60], red.dark[70]),
31
36
  },
32
37
  } as const;
33
38
 
34
39
  /**
35
- * Stone syntax palette — light values snap to T40 / T45 stops on the
36
- * stone categorical ramps (per audit drawer); dark values stay at T70.
37
- *
38
- * `string` and `property` both land on Teal T40 — intentional; the audit
39
- * unified them since green and teal are visually adjacent at T40 and
40
- * the stone neutral palette doesn't carry a distinct green stop.
40
+ * Stone syntax uses mid-ramp colors in light mode and lighter stops in dark
41
+ * mode. Light strings and properties share Teal; dark strings use Green 70,
42
+ * while dark properties remain Teal.
41
43
  */
42
44
  const stoneSyntax = defineSyntaxTheme({
43
45
  name: 'astryx-stone',
44
46
  tokens: {
45
- keyword: ['#645a72', '#b2a7c1'], // Purple T40 / T70
46
- string: ['#4e6357', '#9bb19a'], // Teal T40 / Green T70
47
- comment: ['#5e5e5e', '#ababb0'], // Stone Neutral T40 / T70
48
- number: ['#755752', '#bea792'], // Red T40 / Orange T70
49
- function: ['#506072', '#99adc6'], // Blue T40 / T70
50
- type: ['#645a72', '#b2a7c1'], // Purple T40 / T70
51
- variable: ['#5e5e5e', '#ababb0'], // Stone Neutral T40 / T70
52
- operator: ['#5e5e5e', '#ababb0'], // Stone Neutral T40 / T70
53
- constant: ['#755752', '#bea792'], // Red T40 / Orange T70
54
- tag: ['#775751', '#c7a39d'], // Red T40 / T70
55
- attribute: ['#79693f', '#b6aa90'], // Yellow T45 / T70
56
- property: ['#4e6357', '#94b2a0'], // Teal T40 / T70
57
- punctuation: ['#5e5e5e', '#ababb0'], // Stone Neutral T40 / T70
58
- background: ['#f3f3f5', '#171719'],
59
- // Diff rows: the muted green/red at 25% in light and 20% in dark keep
60
- // every token at or above 4.5:1 on the tint; the markers are the tinted
61
- // text tokens (8.1:1 light, 8.8:1 dark on their tints).
62
- added: ['#d0e9ce40', '#b4cdb233'],
63
- removed: ['#f9dcd740', '#dcc0bc33'],
64
- 'added-marker': ['#374c36', '#d0e9ce'],
65
- 'removed-marker': ['#58413e', '#f9dcd7'],
47
+ keyword: [purple.light[40], purple.dark[70]],
48
+ string: [teal.light[40], green.dark[70]],
49
+ comment: [neutral.light[40], neutral.dark[70]],
50
+ number: [red.light[40], orange.dark[70]],
51
+ function: [blue.light[40], blue.dark[70]],
52
+ type: [purple.light[40], purple.dark[70]],
53
+ variable: [neutral.light[40], neutral.dark[70]],
54
+ operator: [neutral.light[40], neutral.dark[70]],
55
+ constant: [red.light[40], orange.dark[70]],
56
+ tag: [red.light[40], red.dark[70]],
57
+ attribute: [yellow.light[40], yellow.dark[70]],
58
+ property: [teal.light[40], teal.dark[70]],
59
+ punctuation: [neutral.light[40], neutral.dark[70]],
60
+ background: [neutral.light[95], neutral.dark[5]],
61
+ // Translucent diff rows retain each token's contrast while the opaque
62
+ // markers carry the same Green and Red families as their row tint.
63
+ added: [withAlpha(green.light[90], '40'), withAlpha(green.dark[80], '33')],
64
+ removed: [withAlpha(red.light[90], '40'), withAlpha(red.dark[80], '33')],
65
+ 'added-marker': [green.light[30], green.dark[90]],
66
+ 'removed-marker': [red.light[30], red.dark[90]],
66
67
  },
67
68
  });
68
69
 
@@ -151,145 +152,135 @@ export const stoneTheme = defineTheme({
151
152
  syntax: stoneSyntax,
152
153
 
153
154
  tokens: {
154
- // =========================================================================
155
- // Colors — warm stone palette
156
- // Core: #28282A, #84848B, #D8D8DB, #f3f3f5, #FFFFFF
157
- // =========================================================================
158
-
159
- // Core semantic — all neutrals H=291
160
- // Stone 900 T=16 C=1.4, Stone 500 T=55 C=4, Stone 300 T=86 C=1.6, Stone 100 T=96 C=1
161
- '--color-accent': ['#25252a', '#f3f3f5'], // light: Stone Neutral T15
162
- '--color-accent-muted': ['#25252a14', '#f3f3f520'], // light: Stone Neutral T15 · 8% / dark: T96 · 12.5%
163
- '--color-neutral': ['#25252a0f', '#f3f3f51a'], // light: Stone Neutral T15 · 6% / dark: T96 · 10%
164
- '--color-background-surface': ['#ffffff', '#1b1b1f'], // dark: Stone Neutral T10
165
- '--color-background-body': ['#f3f3f5', '#111015'], // dark: Stone Neutral T5
166
- '--color-overlay': ['#25252a80', '#28282acc'], // light: Stone Neutral T15 · 50% / dark: 80%
167
- '--color-overlay-hover': ['#25252a0d', '#f3f3f50d'], // light: Stone Neutral T15 · 5% / dark: T96 · 5%
168
- '--color-overlay-pressed': ['#25252a1a', '#f3f3f51a'], // light: Stone Neutral T15 · 10% / dark: T96 · 10%
169
- '--color-background-muted': ['#e2e2e8', '#3b3b3f'], // light: Stone Neutral T90
170
-
171
- // Text — H=291
172
- '--color-text-primary': ['#25252a', '#f3f3f5'], // light: Stone Neutral T15
173
- // T40/T70 keeps normal secondary text above AA on every stone surface,
174
- // including the muted and tinted fills that components pair it with.
175
- '--color-text-secondary': ['#5e5e63', '#ababb0'], // Stone Neutral T40 / T70
176
- '--color-text-disabled': ['#d7d7da', '#5e5e61'], // T86 C=1.6 / T40 C=2
177
- '--color-text-accent': ['#25252a', '#f3f3f5'], // light: Stone Neutral T15
178
- '--color-on-dark': '#FFFFFF',
179
- '--color-on-light': ['#25252a', '#28282a'], // light: Stone Neutral T15
180
- '--color-on-accent': ['#ffffff', '#25252a'], // dark: Stone Neutral T15
181
- // Text on top of matching status surface (badge fill, banner content).
182
- '--color-on-success': ['#374c36', '#d0e9ce'], // Green T30 / T90
183
- '--color-on-error': ['#58413e', '#f9dcd7'], // Red T30 / T90
184
- '--color-on-warning': ['#524622', '#f4e1b7'], // Yellow T30 / T90
185
-
186
- // Icon — H=291
187
- '--color-icon-accent': ['#25252a', '#f3f3f5'], // light: Stone Neutral T15
188
- '--color-icon-primary': ['#25252a', '#f3f3f5'], // light: Stone Neutral T15
189
- '--color-icon-secondary': ['#83838a', '#9d9da3'], // T55 C=4 / T65 C=3
190
- '--color-icon-disabled': ['#d7d7da', '#5e5e61'], // T86 C=1.6 / T40 C=2
191
-
192
- // Surface variants — H=291
193
- '--color-background-card': ['#FFFFFF', '#242325'], // T14
194
- '--color-background-popover': ['#ffffff', '#25252a'], // dark: Stone Neutral T15
195
- '--color-background-inverted': ['#25252a', '#f3f3f5'], // light: Stone Neutral T15
196
-
197
- // Status / Sentiment — T50 from palette for icons/borders (visible color)
198
- '--color-success': ['#374c36', '#b4cdb2'], // Green T30 / T80
199
- '--color-success-muted': ['#d0e9ce', '#b4cdb2'], // Green T90 / T80
200
- '--color-error': ['#58413e', '#dcc0bc'], // Red T30 / T80
201
- '--color-error-muted': ['#f9dcd7', '#dcc0bc'], // Red T90 / T80
202
- '--color-warning': ['#524622', '#d7c59c'], // Yellow T30 / T80
203
- '--color-warning-muted': ['#f4e1b7', '#d7c59c'], // Yellow T90 / T80
204
-
205
- // Border — H=291
206
- '--color-border': ['#e2e2e8', '#f3f3f51a'], // light: Stone Neutral T90 / dark: T96 · 10%
207
- '--color-border-emphasized': ['#83838a', '#5e5e61'], // T55 C=4 / T40 C=2
208
-
209
- // Effects — H=291
210
- '--color-skeleton': ['#d4d4da', '#5e5e64'], // T85 / T40 from H=291 C=3
211
- '--color-shadow': ['#25252a1a', '#0000004d'], // light: Stone Neutral T15 · 10% / dark: 30%
212
- '--color-tint-hover': ['black', 'white'],
155
+ // Core neutrals
156
+ '--color-accent': [neutral.light[15], neutral.dark[95]],
157
+ '--color-accent-muted': [
158
+ withAlpha(neutral.light[15], '14'),
159
+ withAlpha(neutral.dark[95], '20'),
160
+ ],
161
+ '--color-neutral': [
162
+ withAlpha(neutral.light[15], '0f'),
163
+ withAlpha(neutral.dark[95], '1a'),
164
+ ],
165
+ '--color-background-surface': [neutral.light[100], neutral.dark[10]],
166
+ '--color-background-body': [neutral.light[95], neutral.dark[5]],
167
+ '--color-overlay': [
168
+ withAlpha(neutral.light[15], '80'),
169
+ withAlpha(neutral.dark[15], 'cc'),
170
+ ],
171
+ '--color-overlay-hover': [
172
+ withAlpha(neutral.light[15], '0d'),
173
+ withAlpha(neutral.dark[95], '0d'),
174
+ ],
175
+ '--color-overlay-pressed': [
176
+ withAlpha(neutral.light[15], '1a'),
177
+ withAlpha(neutral.dark[95], '1a'),
178
+ ],
179
+ '--color-background-muted': [neutral.light[90], neutral.dark[25]],
180
+
181
+ // Text
182
+ '--color-text-primary': [neutral.light[15], neutral.dark[95]],
183
+ // These stops keep normal secondary text readable on Stone's body,
184
+ // muted, and categorical surfaces.
185
+ '--color-text-secondary': [neutral.light[40], neutral.dark[70]],
186
+ '--color-text-disabled': [neutral.light[85], neutral.dark[40]],
187
+ '--color-text-accent': [neutral.light[15], neutral.dark[95]],
188
+ '--color-on-dark': neutral.light[100],
189
+ '--color-on-light': [neutral.light[15], neutral.dark[15]],
190
+ '--color-on-accent': [neutral.light[100], neutral.dark[15]],
191
+ '--color-on-success': [green.light[30], green.dark[90]],
192
+ '--color-on-error': [red.light[30], red.dark[90]],
193
+ '--color-on-warning': [yellow.light[30], yellow.dark[90]],
194
+
195
+ // Icon
196
+ '--color-icon-accent': [neutral.light[15], neutral.dark[95]],
197
+ '--color-icon-primary': [neutral.light[15], neutral.dark[95]],
198
+ '--color-icon-secondary': [neutral.light[55], neutral.dark[65]],
199
+ '--color-icon-disabled': [neutral.light[85], neutral.dark[40]],
200
+
201
+ // Surface variants
202
+ '--color-background-card': [neutral.light[100], neutral.dark[15]],
203
+ '--color-background-popover': [neutral.light[100], neutral.dark[20]],
204
+ '--color-background-inverted': [neutral.light[15], neutral.dark[95]],
205
+
206
+ // Status / sentiment
207
+ '--color-success': [green.light[30], green.dark[80]],
208
+ '--color-success-muted': [green.light[90], green.dark[80]],
209
+ '--color-error': [red.light[30], red.dark[80]],
210
+ '--color-error-muted': [red.light[90], red.dark[80]],
211
+ '--color-warning': [yellow.light[30], yellow.dark[80]],
212
+ '--color-warning-muted': [yellow.light[90], yellow.dark[80]],
213
+
214
+ // Border
215
+ '--color-border': [neutral.light[90], withAlpha(neutral.dark[95], '1a')],
216
+ '--color-border-emphasized': [neutral.light[55], neutral.dark[40]],
217
+
218
+ // Effects
219
+ '--color-skeleton': [neutral.light[85], neutral.dark[40]],
220
+ '--color-shadow': [
221
+ withAlpha(neutral.light[15], '1a'),
222
+ withAlpha(neutral.dark[0], '4d'),
223
+ ],
224
+ '--color-tint-hover': [neutral.light[0], neutral.dark[100]],
213
225
 
214
226
  // Typography override
215
227
  '--text-supporting-size': '12px',
216
228
 
217
- // Categorical hues
218
- // Light: T90 solid bg + T30 text (pastel surface, dark text)
219
- // Dark: T35 solid bg + T90 text — snaps to canonical palette stops
220
- // per theming-infra.mdc §7. T90 dark text is the SAME hex as
221
- // the light-mode bg pastel — clean palette symmetry, ~6–9:1
222
- // contrast on the T35 surface across all hues (passes AA Body).
223
- // Borders: light T85 / dark T25 — one step inward from surface in both
224
- // modes, matching the light-mode T90/T85 spacing.
225
-
226
- // Categorical — Blue H=265 C=10
227
- '--color-background-blue': ['#d7e4f5', '#485362'], // light T90 / dark T35
228
- '--color-border-blue': ['#c9d6e7', '#313c4a'], // light T85 / dark T25
229
- '--color-icon-blue': ['#3c4856', '#d7e4f5'], // light T30 / dark T90
230
- '--color-text-blue': ['#3c4856', '#d7e4f5'],
231
-
232
- // Categorical — Cyan H=190 C=10
233
- '--color-background-cyan': ['#cce8e5', '#3e5755'],
234
- '--color-border-cyan': ['#bedad7', '#28403e'],
235
- '--color-icon-cyan': ['#334b49', '#cce8e5'],
236
- '--color-text-cyan': ['#334b49', '#cce8e5'],
237
-
238
- // Categorical — Gray (pure neutral, C=0). Same T35/T25/T90 pattern from
239
- // the neutral H=291 C=3 ramp.
240
- '--color-background-gray': ['#e2e2e8', '#525257'], // light: Stone Neutral T90
241
- '--color-border-gray': ['#d4d4da', '#3b3b3f'], // light: Stone Neutral T85
242
- '--color-icon-gray': ['#46464b', '#e2e2e8'], // light: Stone Neutral T30
243
- '--color-text-gray': ['#46464b', '#e2e2e8'], // light: Stone Neutral T30
244
-
245
- // Categorical — Green H=142 C=17
246
- '--color-background-green': ['#d0e9ce', '#425841'],
247
- '--color-border-green': ['#c2dbc0', '#2b402b'],
248
- '--color-icon-green': ['#374c36', '#d0e9ce'],
249
- '--color-text-green': ['#374c36', '#d0e9ce'],
250
-
251
- // Categorical — Orange H=70 C=22
252
- '--color-background-orange': ['#ffdcbb', '#684d32'],
253
- '--color-border-orange': ['#f1ceae', '#4f361c'],
254
- '--color-icon-orange': ['#5b4227', '#ffdcbb'],
255
- '--color-text-orange': ['#5b4227', '#ffdcbb'],
256
-
257
- // Categorical — Pink H=340 C=9
258
- '--color-background-pink': ['#f0dde8', '#5e4e57'],
259
- '--color-border-pink': ['#e2cfda', '#463740'],
260
- '--color-icon-pink': ['#52424c', '#f0dde8'],
261
- '--color-text-pink': ['#52424c', '#f0dde8'],
262
-
263
- // Categorical — Purple H=307 C=11
264
- '--color-background-purple': ['#e8dff3', '#564f60'],
265
- '--color-border-purple': ['#d9d1e5', '#3f3949'],
266
- '--color-icon-purple': ['#4b4454', '#e8dff3'],
267
- '--color-text-purple': ['#4b4454', '#e8dff3'],
268
-
269
- // Categorical — Red H=33 C=11
270
- '--color-background-red': ['#f9dcd7', '#644d49'],
271
- '--color-border-red': ['#ebcec9', '#4c3633'],
272
- '--color-icon-red': ['#58413e', '#f9dcd7'],
273
- '--color-text-red': ['#58413e', '#f9dcd7'],
274
-
275
- // Categorical — Teal H=158 C=9
276
- '--color-background-teal': ['#d4e7dc', '#46564d'],
277
- '--color-border-teal': ['#c6d9ce', '#303f36'],
278
- '--color-icon-teal': ['#3b4a41', '#d4e7dc'],
279
- '--color-text-teal': ['#3b4a41', '#d4e7dc'],
280
-
281
- // Categorical — Yellow H=90 C=23
282
- '--color-background-yellow': ['#f4e1b7', '#5e512d'],
283
- '--color-border-yellow': ['#e5d3a9', '#463a18'],
284
- '--color-icon-yellow': ['#524622', '#f4e1b7'],
285
- '--color-text-yellow': ['#524622', '#f4e1b7'],
286
-
287
- // =========================================================================
288
- // Radius — clean and subtle
289
- // --radius-none and --radius-full are always fixed and must never be
290
- // scaled by a theme (see defineTheme's radius config docs) — 0 and
291
- // 9999px respectively, matching @astryxdesign/core's own defaults.
292
- // =========================================================================
229
+ // Categorical
230
+ // Light mode pairs pastel stop 90 surfaces with stop 30 foregrounds.
231
+ // Dark mode pairs stop 35 surfaces with stop 90 foregrounds; borders move
232
+ // one step inward in both modes.
233
+ '--color-background-blue': [blue.light[90], blue.dark[35]],
234
+ '--color-border-blue': [blue.light[85], blue.dark[25]],
235
+ '--color-icon-blue': [blue.light[30], blue.dark[90]],
236
+ '--color-text-blue': [blue.light[30], blue.dark[90]],
237
+
238
+ '--color-background-cyan': [cyan.light[90], cyan.dark[35]],
239
+ '--color-border-cyan': [cyan.light[85], cyan.dark[25]],
240
+ '--color-icon-cyan': [cyan.light[30], cyan.dark[90]],
241
+ '--color-text-cyan': [cyan.light[30], cyan.dark[90]],
242
+
243
+ '--color-background-gray': [neutral.light[90], neutral.dark[35]],
244
+ '--color-border-gray': [neutral.light[85], neutral.dark[25]],
245
+ '--color-icon-gray': [neutral.light[30], neutral.dark[90]],
246
+ '--color-text-gray': [neutral.light[30], neutral.dark[90]],
247
+
248
+ '--color-background-green': [green.light[90], green.dark[35]],
249
+ '--color-border-green': [green.light[85], green.dark[25]],
250
+ '--color-icon-green': [green.light[30], green.dark[90]],
251
+ '--color-text-green': [green.light[30], green.dark[90]],
252
+
253
+ '--color-background-orange': [orange.light[90], orange.dark[35]],
254
+ '--color-border-orange': [orange.light[85], orange.dark[25]],
255
+ '--color-icon-orange': [orange.light[30], orange.dark[90]],
256
+ '--color-text-orange': [orange.light[30], orange.dark[90]],
257
+
258
+ '--color-background-pink': [pink.light[90], pink.dark[35]],
259
+ '--color-border-pink': [pink.light[85], pink.dark[25]],
260
+ '--color-icon-pink': [pink.light[30], pink.dark[90]],
261
+ '--color-text-pink': [pink.light[30], pink.dark[90]],
262
+
263
+ '--color-background-purple': [purple.light[90], purple.dark[35]],
264
+ '--color-border-purple': [purple.light[85], purple.dark[25]],
265
+ '--color-icon-purple': [purple.light[30], purple.dark[90]],
266
+ '--color-text-purple': [purple.light[30], purple.dark[90]],
267
+
268
+ '--color-background-red': [red.light[90], red.dark[35]],
269
+ '--color-border-red': [red.light[85], red.dark[25]],
270
+ '--color-icon-red': [red.light[30], red.dark[90]],
271
+ '--color-text-red': [red.light[30], red.dark[90]],
272
+
273
+ '--color-background-teal': [teal.light[90], teal.dark[35]],
274
+ '--color-border-teal': [teal.light[85], teal.dark[25]],
275
+ '--color-icon-teal': [teal.light[30], teal.dark[90]],
276
+ '--color-text-teal': [teal.light[30], teal.dark[90]],
277
+
278
+ '--color-background-yellow': [yellow.light[90], yellow.dark[35]],
279
+ '--color-border-yellow': [yellow.light[85], yellow.dark[25]],
280
+ '--color-icon-yellow': [yellow.light[30], yellow.dark[90]],
281
+ '--color-text-yellow': [yellow.light[30], yellow.dark[90]],
282
+
283
+ // Radius
293
284
  '--radius-none': '0px',
294
285
  '--radius-inner': '0.25rem',
295
286
  '--radius-element': '0.5rem',
@@ -297,17 +288,15 @@ export const stoneTheme = defineTheme({
297
288
  '--radius-page': '1.5rem',
298
289
  '--radius-full': '9999px',
299
290
 
300
- // =========================================================================
301
291
  // Shadows
302
- // =========================================================================
303
- '--shadow-low': '0 2px 4px #28282A0D, 0 4px 8px #28282A1A',
304
- '--shadow-med': '0 2px 4px #28282A0D, 0 4px 12px #28282A1A',
305
- '--shadow-high': '0 4px 6px #28282A1A, 0 12px 24px #28282A26',
306
- '--shadow-inset-hover': 'inset 0px 0px 0px 2px #28282A30',
307
- '--shadow-inset-selected': 'inset 0px 0px 0px 2px #28282A50',
308
- '--shadow-inset-success': 'inset 0px 0px 0px 2px #83838a30',
309
- '--shadow-inset-warning': 'inset 0px 0px 0px 2px #83838a30',
310
- '--shadow-inset-error': 'inset 0px 0px 0px 2px #83838a30',
292
+ '--shadow-low': `0 2px 4px ${withAlpha(neutral.light[15], '0d')}, 0 4px 8px ${withAlpha(neutral.light[15], '1a')}`,
293
+ '--shadow-med': `0 2px 4px ${withAlpha(neutral.light[15], '0d')}, 0 4px 12px ${withAlpha(neutral.light[15], '1a')}`,
294
+ '--shadow-high': `0 4px 6px ${withAlpha(neutral.light[15], '1a')}, 0 12px 24px ${withAlpha(neutral.light[15], '26')}`,
295
+ '--shadow-inset-hover': `inset 0 0 0 2px ${withAlpha(neutral.light[15], '30')}`,
296
+ '--shadow-inset-selected': `inset 0 0 0 2px ${withAlpha(neutral.light[15], '50')}`,
297
+ '--shadow-inset-success': `inset 0 0 0 2px ${withAlpha(neutral.light[55], '30')}`,
298
+ '--shadow-inset-warning': `inset 0 0 0 2px ${withAlpha(neutral.light[55], '30')}`,
299
+ '--shadow-inset-error': `inset 0 0 0 2px ${withAlpha(neutral.light[55], '30')}`,
311
300
  },
312
301
 
313
302
  components: {
@@ -322,7 +311,8 @@ export const stoneTheme = defineTheme({
322
311
  },
323
312
  },
324
313
 
325
- // Semantic variants point at categorical hue tokens — single source of truth.
314
+ // Badges, banners, and field status messages share the categorical
315
+ // surfaces and foregrounds so each semantic state has one visual source.
326
316
  badge: {
327
317
  'variant:info': {
328
318
  backgroundColor: 'var(--color-background-blue)',
@@ -346,10 +336,8 @@ export const stoneTheme = defineTheme({
346
336
  },
347
337
  },
348
338
 
349
- // StyleX paints the banner surface from @layer priority4 (above
350
- // @layer astryx-theme), so a direct backgroundColor override loses the
351
- // cascade. Redefine the muted token instead so StyleX's var() resolves
352
- // to the categorical bg in our scope.
339
+ // Banner surface declarations live above the theme layer, so redirect the
340
+ // semantic variables here instead of attempting a losing direct fill.
353
341
  banner: {
354
342
  'status:info': {
355
343
  '--color-accent-muted': 'var(--color-background-blue)',
@@ -377,44 +365,38 @@ export const stoneTheme = defineTheme({
377
365
  },
378
366
  },
379
367
 
380
- // Fill: light = T90 (same hex as banner/badge surface — fill reads as
381
- // the same color family as the matching status surface). Dark = T70.
382
- // Hexes from the preview Tonal Palettes ramp. accent (default) +
383
- // indeterminate both route to blue for the in-progress / loading look.
368
+ // Progress fills use the same family as their matching status surface;
369
+ // the darker stop in dark mode keeps the channel visible on dark tracks.
384
370
  'progress-bar-fill': {
385
371
  'variant:accent': {
386
- backgroundColor: 'light-dark(#d7e4f5, #a0acbc)', // Blue T90 / T70
372
+ backgroundColor: lightDark(blue.light[90], blue.dark[70]),
387
373
  },
388
374
  'variant:success': {
389
- backgroundColor: 'light-dark(#d0e9ce, #9ab298)', // Green T90 / T70
375
+ backgroundColor: lightDark(green.light[90], green.dark[70]),
390
376
  },
391
377
  'variant:warning': {
392
- backgroundColor: 'light-dark(#f4e1b7, #bbaa82)', // Yellow T90 / T70
378
+ backgroundColor: lightDark(yellow.light[90], yellow.dark[70]),
393
379
  },
394
380
  'variant:error': {
395
- backgroundColor: 'light-dark(#f9dcd7, #c0a5a0)', // Red T90 / T70
381
+ backgroundColor: lightDark(red.light[90], red.dark[70]),
396
382
  },
397
383
  },
398
384
 
399
- // Track default --color-background-muted reads near-body in stone;
400
- // redirect to --color-skeleton so the channel stays visible.
385
+ // The default muted track is too close to Stone's body surface.
401
386
  'progress-bar-track': {
402
387
  base: {
403
388
  backgroundColor: 'var(--color-skeleton)',
404
389
  },
405
390
  },
406
391
 
407
- // Switch off-state track reads --color-background-gray by default.
408
- // Redefine it inside the switch scope to --color-skeleton, matching
409
- // the ProgressBar track. The on-state reads --color-accent (unaffected);
410
- // disabled-off also picks up --color-skeleton for consistency.
392
+ // Match the Switch off-state track to the visible ProgressBar track.
411
393
  switch: {
412
394
  base: {
413
395
  '--color-background-gray': 'var(--color-skeleton)',
414
396
  },
415
397
  },
416
398
 
417
- // FieldStatus surface matches badge — see badge override above.
399
+ // FieldStatus surfaces match the corresponding badge and banner family.
418
400
  'field-status': {
419
401
  'type:success': {
420
402
  backgroundColor: 'var(--color-background-green)',
@@ -427,8 +409,7 @@ export const stoneTheme = defineTheme({
427
409
  },
428
410
  },
429
411
 
430
- // Input status borders + icons across all 9 input components share the
431
- // same softer T60/T70 redirection. See INPUT_STATUS_VARS above.
412
+ // Every input status border and icon uses INPUT_STATUS_VARS above.
432
413
  'text-input': INPUT_STATUS_VARS,
433
414
  'text-area': INPUT_STATUS_VARS,
434
415
  'number-input': INPUT_STATUS_VARS,
@@ -460,9 +441,11 @@ export const stoneTheme = defineTheme({
460
441
  });
461
442
 
462
443
  /**
463
- * Raw tonal palettes — every color at every tone step (0–100 in 5s).
464
- * Same hue and chroma used to derive all theme tokens.
465
- * Use these for custom components or data visualization.
444
+ * Frozen released compatibility palettes. These values preserve the public
445
+ * `stonePalettes` numeric stops, `hue`, and `chroma` for existing consumers;
446
+ * the maintained theme renders selected stops from
447
+ * `stonePalettes.generated.ts` instead. Components should consume semantic
448
+ * theme tokens, and charts should use the data-visualization color API.
466
449
  */
467
450
  export const stonePalettes = {
468
451
  neutral: {