@verdify/tokens 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,12 @@
1
+ Copyright (c) 2026 Verdify.
2
+
3
+ All rights reserved.
4
+
5
+ This repository contains confidential and proprietary architecture documentation
6
+ for the Verdify ecosystem (Verdify, Spare, Veraq). It is shared with employees,
7
+ contractors, and authorized partners under the terms of their respective
8
+ agreements. No license — express or implied — is granted to copy, distribute,
9
+ or create derivative works outside those agreements.
10
+
11
+ Replace this file with the organization's chosen license before any public or
12
+ open-source release of any portion of the ecosystem.
@@ -10,8 +10,58 @@
10
10
  [data-adaptive="dusk"] {
11
11
  --color-surface-canvas: #1a1a26;
12
12
  --color-text-primary: #c8d0de;
13
+ --color-surface-raised: #1f2638;
14
+ --color-surface-input: #1f2638;
15
+ --color-surface-border: #4a5567;
16
+ --color-surface-border-muted: #2a3142;
17
+ --color-text-secondary: #8a95a8;
18
+ --color-text-muted: #4a5567;
19
+ --color-text-disabled: #2a3142;
20
+ --color-text-inverse: #0b0f19;
21
+ --color-action-secondary-bg: #1f2638;
22
+ --color-action-secondary-fg: #c8d0de;
23
+ --color-action-secondary-border: #4a5567;
24
+ --color-action-secondary-bg-hover: #1f2638;
25
+ --color-action-ghost-fg: #c8d0de;
26
+ --color-action-ghost-bg-hover: #1f2638;
27
+ --color-border-default: #4a5567;
28
+ --color-border-strong: #2a3142;
29
+ --color-control-bg: #1f2638;
30
+ --color-control-border: #4a5567;
31
+ --color-control-fg: #c8d0de;
32
+ --color-control-placeholder: #4a5567;
33
+ --color-status-verified-on-surface: #00d17a;
34
+ --color-status-signal-on-surface: #4d9dff;
35
+ --color-status-caution-on-surface: #f5a623;
36
+ --color-status-critical-on-surface: #ff4d4d;
37
+ --focus-ring-casing: #c8d0de;
13
38
  }
14
39
  [data-adaptive="night"] {
15
40
  --color-surface-canvas: #060912;
16
41
  --color-text-primary: #c8d0de;
42
+ --color-surface-raised: #0f1320;
43
+ --color-surface-input: #161b2a;
44
+ --color-surface-border: #1f2638;
45
+ --color-surface-border-muted: #2a3142;
46
+ --color-text-secondary: #8a95a8;
47
+ --color-text-muted: #4a5567;
48
+ --color-text-disabled: #2a3142;
49
+ --color-text-inverse: #0b0f19;
50
+ --color-action-secondary-bg: #0f1320;
51
+ --color-action-secondary-fg: #c8d0de;
52
+ --color-action-secondary-border: #1f2638;
53
+ --color-action-secondary-bg-hover: #161b2a;
54
+ --color-action-ghost-fg: #c8d0de;
55
+ --color-action-ghost-bg-hover: #0f1320;
56
+ --color-border-default: #1f2638;
57
+ --color-border-strong: #2a3142;
58
+ --color-control-bg: #161b2a;
59
+ --color-control-border: #1f2638;
60
+ --color-control-fg: #c8d0de;
61
+ --color-control-placeholder: #4a5567;
62
+ --color-status-verified-on-surface: #00d17a;
63
+ --color-status-signal-on-surface: #4d9dff;
64
+ --color-status-caution-on-surface: #f5a623;
65
+ --color-status-critical-on-surface: #ff4d4d;
66
+ --focus-ring-casing: #c8d0de;
17
67
  }
package/dist/preset.css CHANGED
@@ -66,18 +66,22 @@
66
66
  --color-action-destructive-fg: #fbfcfe;
67
67
  --color-action-destructive-border: #be3939;
68
68
  --color-status-verified-fg: #007947;
69
+ --color-status-verified-on-surface: #007947;
69
70
  --color-status-verified-bg: #e8ecf4;
70
71
  --color-status-verified-border: #007947;
71
72
  --color-status-verified-accent: #00d17a;
72
73
  --color-status-signal-fg: #346bad;
74
+ --color-status-signal-on-surface: #346bad;
73
75
  --color-status-signal-bg: #e8ecf4;
74
76
  --color-status-signal-border: #346bad;
75
77
  --color-status-signal-accent: #4d9dff;
76
78
  --color-status-caution-fg: #8e6014;
79
+ --color-status-caution-on-surface: #8e6014;
77
80
  --color-status-caution-bg: #e8ecf4;
78
81
  --color-status-caution-border: #8e6014;
79
82
  --color-status-caution-accent: #f5a623;
80
83
  --color-status-critical-fg: #be3939;
84
+ --color-status-critical-on-surface: #be3939;
81
85
  --color-status-critical-bg: #e8ecf4;
82
86
  --color-status-critical-border: #be3939;
83
87
  --color-status-critical-accent: #ff4d4d;
@@ -96,6 +100,7 @@
96
100
  --focus-ring-width: 2px;
97
101
  --focus-ring-color: #4d9dff;
98
102
  --focus-ring-offset: 2px;
103
+ --focus-ring-casing: #0b0f19;
99
104
  --font-family-sans: Inter, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
100
105
  --font-family-mono: 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace;
101
106
  --font-weight-regular: 400;
package/dist/tokens.css CHANGED
@@ -60,6 +60,18 @@
60
60
  --color-text-disabled: #b0baca; /** Disabled text — low-contrast, deliberate. Aliases mist.400; downstream consumers may alternatively compose text.primary with state.opacity.disabled (0.38) for a different visual register. */
61
61
  --color-text-inverse: #fbfcfe; /** Text on dark surfaces (e.g. obsidian backdrop, dark scrim). Aliases mist.50 — the lightest neutral. Distinct from on-brand: inverse is for neutral-dark contexts; on-brand is reserved for brand backgrounds. */
62
62
  --color-text-on-brand: #fbfcfe; /** Text on brand backgrounds (e.g. CTA buttons). Constant per brand discipline. */
63
+ --color-dark-surface-raised: #0f1320; /** Raised surface · cards — dark family (dusk/night). Mirrors surface.raised in light. */
64
+ --color-dark-surface-input: #161b2a; /** Input / well — dark family (dusk/night). */
65
+ --color-dark-surface-border: #1f2638; /** Border / divider — dark family (dusk/night). */
66
+ --color-dark-surface-border-muted: #2a3142; /** Muted border — dark family (dusk/night). */
67
+ --color-dark-text-secondary: #8a95a8; /** Secondary text — dark family (dusk/night); 6.6:1 on night canvas. */
68
+ --color-dark-text-muted: #4a5567; /** Muted text — dark family; de-emphasized, same sub-UI register as light muted (~2.3-2.6:1). */
69
+ --color-dark-text-disabled: #2a3142; /** Disabled text — dark family; low-contrast, deliberate (contrast-exempt). */
70
+ --color-dark-text-inverse: #0b0f19; /** Text on light surfaces within a dark context — dark family. (0 current component uses.) */
71
+ --color-dusk-surface-raised: #1f2638; /** Raised surface · cards — DUSK band only. The dusk canvas (#1a1a26, L≈0.011) is lighter than the shared dark family's raised (obsidian.850, L≈0.0067), which inverted elevation. Obsidian.700 (L≈0.0196) sits ABOVE the dusk canvas so cards read raised, while secondary text still clears AA (≈5.0:1). */
72
+ --color-dusk-surface-input: #1f2638; /** Input / well — DUSK band only. Same tone as dusk raised (lifted above the dusk canvas); distinguished from cards by its border. Obsidian.700 keeps muted text at the ≈2.0:1 perceptible floor (obsidian.600 would drop it to ~1.7:1 and fail). */
73
+ --color-dusk-surface-border: #4a5567; /** Border / divider — DUSK band only. Obsidian.500 (L≈0.089) gives inputs/cards a visible boundary on the dusk canvas (≈2.3:1) where the shared dark border (obsidian.700) would be ~invisible. */
74
+ --color-dusk-surface-border-muted: #2a3142; /** Muted border — DUSK band only; the softer divider above the dusk canvas. */
63
75
  --color-scrim-light: rgba(11, 15, 25, 0.5); /** Modal/sheet backdrop on light surfaces — obsidian-900 at 50% opacity (per BR-2 spec §4). */
64
76
  --color-scrim-dark: rgba(6, 9, 18, 0.7); /** Modal/sheet backdrop on dark surfaces — obsidian-950 at 70% opacity for stronger isolation. */
65
77
  --color-action-primary-bg: #7053e5; /** Primary action background — Sovereign Violet. The single high-emphasis CTA per surface. — AA-darkened (brand-strong, 5.04:1 with white). */
@@ -77,18 +89,22 @@
77
89
  --color-action-destructive-fg: #fbfcfe; /** Text/icon on a destructive action. */
78
90
  --color-action-destructive-border: #be3939; /** Destructive action border. — AA-darkened (critical-strong, 5.34:1 with white). */
79
91
  --color-status-verified-fg: #007947; /** Verified status foreground — Verified Green darkened to WCAG AA (#007947, ≥4.5:1 on the chip bg). The in-product success state; never the brand. */
92
+ --color-status-verified-on-surface: #007947; /** Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip. */
80
93
  --color-status-verified-bg: #e8ecf4; /** Verified status chip background — neutral; color carried by fg/border (restraint over volume). */
81
94
  --color-status-verified-border: #007947; /** Verified status border — AA-dark shade (≥3:1 non-text). */
82
95
  --color-status-verified-accent: #00d17a; /** Verified bright decorative accent (#00D17A) — for icons/fills where contrast is not a text/border requirement. */
83
96
  --color-status-signal-fg: #346bad; /** Informational status foreground — Signal darkened to WCAG AA (#346BAD, ≥4.5:1 on the chip bg). */
97
+ --color-status-signal-on-surface: #346bad; /** Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip. */
84
98
  --color-status-signal-bg: #e8ecf4; /** Informational status chip background — neutral. */
85
99
  --color-status-signal-border: #346bad; /** Informational status border — AA-dark shade (≥3:1 non-text). */
86
100
  --color-status-signal-accent: #4d9dff; /** Signal bright decorative accent (#4D9DFF) — for icons/fills. */
87
101
  --color-status-caution-fg: #8e6014; /** Caution status foreground — Caution darkened to WCAG AA (#8E6014, ≥4.5:1 on the chip bg); pending / in-progress. */
102
+ --color-status-caution-on-surface: #8e6014; /** Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip. */
88
103
  --color-status-caution-bg: #e8ecf4; /** Caution status chip background — neutral. */
89
104
  --color-status-caution-border: #8e6014; /** Caution status border — AA-dark shade (≥3:1 non-text). */
90
105
  --color-status-caution-accent: #f5a623; /** Caution bright decorative accent (#F5A623) — for icons/fills. */
91
106
  --color-status-critical-fg: #be3939; /** Critical status foreground — Critical darkened to WCAG AA (#BE3939, ≥4.5:1 on the chip bg); error / failure. */
107
+ --color-status-critical-on-surface: #be3939; /** Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip. */
92
108
  --color-status-critical-bg: #e8ecf4; /** Critical status chip background — neutral. */
93
109
  --color-status-critical-border: #be3939; /** Critical status border — AA-dark shade (≥3:1 non-text). */
94
110
  --color-status-critical-accent: #ff4d4d; /** Critical bright decorative accent (#FF4D4D) — for icons/fills. */
@@ -105,8 +121,9 @@
105
121
  --container-xl: 80rem; /** Container max-width at xl breakpoint */
106
122
  --container-2xl: 96rem; /** Container max-width at 2xl breakpoint */
107
123
  --focus-ring-width: 2px; /** Focus ring width. Per WCAG 2.4.7. */
108
- --focus-ring-color: #4d9dff; /** Focus ring color — semantic.signal (#4D9DFF). Contrast ≥3:1 verified in Task 7 (contrast-validation). */
109
- --focus-ring-offset: 2px; /** Focus ring offset (gap between target and ring). */
124
+ --focus-ring-color: #4d9dff; /** Focus ring identity layer — semantic.signal (#4D9DFF). NOT ≥3:1 on light surfaces alone (2.56:1 on canvas); the casing layer carries WCAG 1.4.11 contrast (see ring.casing). */
125
+ --focus-ring-offset: 2px; /** Focus ring offset (gap between target and ring); renders the ring on the page surface, not on a filled control. */
126
+ --focus-ring-casing: #0b0f19; /** Two-tone focus ring contrast layer — the band's AAA text color, so the indicator has a ≥3:1 edge on every surface (light: dark ink ≈17:1; dark: light text ≈11:1+). Per WCAG 1.4.11. */
110
127
  --font-family-sans: Inter, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; /** Primary UI and reading family — Inter Variable per BR-1 §5.1. System fallbacks listed in priority order. */
111
128
  --font-family-mono: 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace; /** Technical family for IDs, hashes, code, timestamps — JetBrains Mono Variable per BR-1 §5.1. */
112
129
  --font-weight-regular: 400; /** Body / paragraph weight */
package/dist/tokens.d.ts CHANGED
@@ -101,6 +101,28 @@ declare const tokens: {
101
101
  inverse: DesignToken;
102
102
  "on-brand": DesignToken;
103
103
  };
104
+ dark: {
105
+ surface: {
106
+ raised: DesignToken;
107
+ input: DesignToken;
108
+ border: DesignToken;
109
+ "border-muted": DesignToken;
110
+ };
111
+ text: {
112
+ secondary: DesignToken;
113
+ muted: DesignToken;
114
+ disabled: DesignToken;
115
+ inverse: DesignToken;
116
+ };
117
+ };
118
+ dusk: {
119
+ surface: {
120
+ raised: DesignToken;
121
+ input: DesignToken;
122
+ border: DesignToken;
123
+ "border-muted": DesignToken;
124
+ };
125
+ };
104
126
  scrim: {
105
127
  light: DesignToken;
106
128
  dark: DesignToken;
@@ -132,24 +154,28 @@ declare const tokens: {
132
154
  status: {
133
155
  verified: {
134
156
  fg: DesignToken;
157
+ "on-surface": DesignToken;
135
158
  bg: DesignToken;
136
159
  border: DesignToken;
137
160
  accent: DesignToken;
138
161
  };
139
162
  signal: {
140
163
  fg: DesignToken;
164
+ "on-surface": DesignToken;
141
165
  bg: DesignToken;
142
166
  border: DesignToken;
143
167
  accent: DesignToken;
144
168
  };
145
169
  caution: {
146
170
  fg: DesignToken;
171
+ "on-surface": DesignToken;
147
172
  bg: DesignToken;
148
173
  border: DesignToken;
149
174
  accent: DesignToken;
150
175
  };
151
176
  critical: {
152
177
  fg: DesignToken;
178
+ "on-surface": DesignToken;
153
179
  bg: DesignToken;
154
180
  border: DesignToken;
155
181
  accent: DesignToken;
@@ -179,6 +205,7 @@ declare const tokens: {
179
205
  width: DesignToken;
180
206
  color: DesignToken;
181
207
  offset: DesignToken;
208
+ casing: DesignToken;
182
209
  };
183
210
  };
184
211
  font: {
package/dist/tokens.js CHANGED
@@ -1176,6 +1176,274 @@ module.exports = {
1176
1176
  path: ["color", "text", "on-brand"],
1177
1177
  },
1178
1178
  },
1179
+ dark: {
1180
+ surface: {
1181
+ raised: {
1182
+ $value: "#0f1320",
1183
+ $type: "color",
1184
+ $description:
1185
+ "Raised surface · cards — dark family (dusk/night). Mirrors surface.raised in light.",
1186
+ filePath: "src/tokens/color.tokens.json",
1187
+ isSource: true,
1188
+ original: {
1189
+ $value: "{color.neutral.obsidian.850}",
1190
+ $type: "color",
1191
+ $description:
1192
+ "Raised surface · cards — dark family (dusk/night). Mirrors surface.raised in light.",
1193
+ },
1194
+ name: "ColorDarkSurfaceRaised",
1195
+ attributes: {
1196
+ category: "color",
1197
+ type: "dark",
1198
+ item: "surface",
1199
+ subitem: "raised",
1200
+ },
1201
+ path: ["color", "dark", "surface", "raised"],
1202
+ },
1203
+ input: {
1204
+ $value: "#161b2a",
1205
+ $type: "color",
1206
+ $description: "Input / well — dark family (dusk/night).",
1207
+ filePath: "src/tokens/color.tokens.json",
1208
+ isSource: true,
1209
+ original: {
1210
+ $value: "{color.neutral.obsidian.800}",
1211
+ $type: "color",
1212
+ $description: "Input / well — dark family (dusk/night).",
1213
+ },
1214
+ name: "ColorDarkSurfaceInput",
1215
+ attributes: {
1216
+ category: "color",
1217
+ type: "dark",
1218
+ item: "surface",
1219
+ subitem: "input",
1220
+ },
1221
+ path: ["color", "dark", "surface", "input"],
1222
+ },
1223
+ border: {
1224
+ $value: "#1f2638",
1225
+ $type: "color",
1226
+ $description: "Border / divider — dark family (dusk/night).",
1227
+ filePath: "src/tokens/color.tokens.json",
1228
+ isSource: true,
1229
+ original: {
1230
+ $value: "{color.neutral.obsidian.700}",
1231
+ $type: "color",
1232
+ $description: "Border / divider — dark family (dusk/night).",
1233
+ },
1234
+ name: "ColorDarkSurfaceBorder",
1235
+ attributes: {
1236
+ category: "color",
1237
+ type: "dark",
1238
+ item: "surface",
1239
+ subitem: "border",
1240
+ },
1241
+ path: ["color", "dark", "surface", "border"],
1242
+ },
1243
+ "border-muted": {
1244
+ $value: "#2a3142",
1245
+ $type: "color",
1246
+ $description: "Muted border — dark family (dusk/night).",
1247
+ filePath: "src/tokens/color.tokens.json",
1248
+ isSource: true,
1249
+ original: {
1250
+ $value: "{color.neutral.obsidian.600}",
1251
+ $type: "color",
1252
+ $description: "Muted border — dark family (dusk/night).",
1253
+ },
1254
+ name: "ColorDarkSurfaceBorderMuted",
1255
+ attributes: {
1256
+ category: "color",
1257
+ type: "dark",
1258
+ item: "surface",
1259
+ subitem: "border-muted",
1260
+ },
1261
+ path: ["color", "dark", "surface", "border-muted"],
1262
+ },
1263
+ },
1264
+ text: {
1265
+ secondary: {
1266
+ $value: "#8a95a8",
1267
+ $type: "color",
1268
+ $description:
1269
+ "Secondary text — dark family (dusk/night); 6.6:1 on night canvas.",
1270
+ filePath: "src/tokens/color.tokens.json",
1271
+ isSource: true,
1272
+ original: {
1273
+ $value: "{color.neutral.obsidian.400}",
1274
+ $type: "color",
1275
+ $description:
1276
+ "Secondary text — dark family (dusk/night); 6.6:1 on night canvas.",
1277
+ },
1278
+ name: "ColorDarkTextSecondary",
1279
+ attributes: {
1280
+ category: "color",
1281
+ type: "dark",
1282
+ item: "text",
1283
+ subitem: "secondary",
1284
+ },
1285
+ path: ["color", "dark", "text", "secondary"],
1286
+ },
1287
+ muted: {
1288
+ $value: "#4a5567",
1289
+ $type: "color",
1290
+ $description:
1291
+ "Muted text — dark family; de-emphasized, same sub-UI register as light muted (~2.3-2.6:1).",
1292
+ filePath: "src/tokens/color.tokens.json",
1293
+ isSource: true,
1294
+ original: {
1295
+ $value: "{color.neutral.obsidian.500}",
1296
+ $type: "color",
1297
+ $description:
1298
+ "Muted text — dark family; de-emphasized, same sub-UI register as light muted (~2.3-2.6:1).",
1299
+ },
1300
+ name: "ColorDarkTextMuted",
1301
+ attributes: {
1302
+ category: "color",
1303
+ type: "dark",
1304
+ item: "text",
1305
+ subitem: "muted",
1306
+ },
1307
+ path: ["color", "dark", "text", "muted"],
1308
+ },
1309
+ disabled: {
1310
+ $value: "#2a3142",
1311
+ $type: "color",
1312
+ $description:
1313
+ "Disabled text — dark family; low-contrast, deliberate (contrast-exempt).",
1314
+ filePath: "src/tokens/color.tokens.json",
1315
+ isSource: true,
1316
+ original: {
1317
+ $value: "{color.neutral.obsidian.600}",
1318
+ $type: "color",
1319
+ $description:
1320
+ "Disabled text — dark family; low-contrast, deliberate (contrast-exempt).",
1321
+ },
1322
+ name: "ColorDarkTextDisabled",
1323
+ attributes: {
1324
+ category: "color",
1325
+ type: "dark",
1326
+ item: "text",
1327
+ subitem: "disabled",
1328
+ },
1329
+ path: ["color", "dark", "text", "disabled"],
1330
+ },
1331
+ inverse: {
1332
+ $value: "#0b0f19",
1333
+ $type: "color",
1334
+ $description:
1335
+ "Text on light surfaces within a dark context — dark family. (0 current component uses.)",
1336
+ filePath: "src/tokens/color.tokens.json",
1337
+ isSource: true,
1338
+ original: {
1339
+ $value: "{color.neutral.mist.950}",
1340
+ $type: "color",
1341
+ $description:
1342
+ "Text on light surfaces within a dark context — dark family. (0 current component uses.)",
1343
+ },
1344
+ name: "ColorDarkTextInverse",
1345
+ attributes: {
1346
+ category: "color",
1347
+ type: "dark",
1348
+ item: "text",
1349
+ subitem: "inverse",
1350
+ },
1351
+ path: ["color", "dark", "text", "inverse"],
1352
+ },
1353
+ },
1354
+ },
1355
+ dusk: {
1356
+ surface: {
1357
+ raised: {
1358
+ $value: "#1f2638",
1359
+ $type: "color",
1360
+ $description:
1361
+ "Raised surface · cards — DUSK band only. The dusk canvas (#1a1a26, L≈0.011) is lighter than the shared dark family's raised (obsidian.850, L≈0.0067), which inverted elevation. Obsidian.700 (L≈0.0196) sits ABOVE the dusk canvas so cards read raised, while secondary text still clears AA (≈5.0:1).",
1362
+ filePath: "src/tokens/color.tokens.json",
1363
+ isSource: true,
1364
+ original: {
1365
+ $value: "{color.neutral.obsidian.700}",
1366
+ $type: "color",
1367
+ $description:
1368
+ "Raised surface · cards — DUSK band only. The dusk canvas (#1a1a26, L≈0.011) is lighter than the shared dark family's raised (obsidian.850, L≈0.0067), which inverted elevation. Obsidian.700 (L≈0.0196) sits ABOVE the dusk canvas so cards read raised, while secondary text still clears AA (≈5.0:1).",
1369
+ },
1370
+ name: "ColorDuskSurfaceRaised",
1371
+ attributes: {
1372
+ category: "color",
1373
+ type: "dusk",
1374
+ item: "surface",
1375
+ subitem: "raised",
1376
+ },
1377
+ path: ["color", "dusk", "surface", "raised"],
1378
+ },
1379
+ input: {
1380
+ $value: "#1f2638",
1381
+ $type: "color",
1382
+ $description:
1383
+ "Input / well — DUSK band only. Same tone as dusk raised (lifted above the dusk canvas); distinguished from cards by its border. Obsidian.700 keeps muted text at the ≈2.0:1 perceptible floor (obsidian.600 would drop it to ~1.7:1 and fail).",
1384
+ filePath: "src/tokens/color.tokens.json",
1385
+ isSource: true,
1386
+ original: {
1387
+ $value: "{color.neutral.obsidian.700}",
1388
+ $type: "color",
1389
+ $description:
1390
+ "Input / well — DUSK band only. Same tone as dusk raised (lifted above the dusk canvas); distinguished from cards by its border. Obsidian.700 keeps muted text at the ≈2.0:1 perceptible floor (obsidian.600 would drop it to ~1.7:1 and fail).",
1391
+ },
1392
+ name: "ColorDuskSurfaceInput",
1393
+ attributes: {
1394
+ category: "color",
1395
+ type: "dusk",
1396
+ item: "surface",
1397
+ subitem: "input",
1398
+ },
1399
+ path: ["color", "dusk", "surface", "input"],
1400
+ },
1401
+ border: {
1402
+ $value: "#4a5567",
1403
+ $type: "color",
1404
+ $description:
1405
+ "Border / divider — DUSK band only. Obsidian.500 (L≈0.089) gives inputs/cards a visible boundary on the dusk canvas (≈2.3:1) where the shared dark border (obsidian.700) would be ~invisible.",
1406
+ filePath: "src/tokens/color.tokens.json",
1407
+ isSource: true,
1408
+ original: {
1409
+ $value: "{color.neutral.obsidian.500}",
1410
+ $type: "color",
1411
+ $description:
1412
+ "Border / divider — DUSK band only. Obsidian.500 (L≈0.089) gives inputs/cards a visible boundary on the dusk canvas (≈2.3:1) where the shared dark border (obsidian.700) would be ~invisible.",
1413
+ },
1414
+ name: "ColorDuskSurfaceBorder",
1415
+ attributes: {
1416
+ category: "color",
1417
+ type: "dusk",
1418
+ item: "surface",
1419
+ subitem: "border",
1420
+ },
1421
+ path: ["color", "dusk", "surface", "border"],
1422
+ },
1423
+ "border-muted": {
1424
+ $value: "#2a3142",
1425
+ $type: "color",
1426
+ $description:
1427
+ "Muted border — DUSK band only; the softer divider above the dusk canvas.",
1428
+ filePath: "src/tokens/color.tokens.json",
1429
+ isSource: true,
1430
+ original: {
1431
+ $value: "{color.neutral.obsidian.600}",
1432
+ $type: "color",
1433
+ $description:
1434
+ "Muted border — DUSK band only; the softer divider above the dusk canvas.",
1435
+ },
1436
+ name: "ColorDuskSurfaceBorderMuted",
1437
+ attributes: {
1438
+ category: "color",
1439
+ type: "dusk",
1440
+ item: "surface",
1441
+ subitem: "border-muted",
1442
+ },
1443
+ path: ["color", "dusk", "surface", "border-muted"],
1444
+ },
1445
+ },
1446
+ },
1179
1447
  scrim: {
1180
1448
  light: {
1181
1449
  $value: "#0b0f1980",
@@ -1543,6 +1811,28 @@ module.exports = {
1543
1811
  },
1544
1812
  path: ["color", "status", "verified", "fg"],
1545
1813
  },
1814
+ "on-surface": {
1815
+ $value: "#007947",
1816
+ $type: "color",
1817
+ $description:
1818
+ "Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip.",
1819
+ filePath: "src/tokens/component.tokens.json",
1820
+ isSource: true,
1821
+ original: {
1822
+ $value: "{color.semantic.verified-strong}",
1823
+ $type: "color",
1824
+ $description:
1825
+ "Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip.",
1826
+ },
1827
+ name: "ColorStatusVerifiedOnSurface",
1828
+ attributes: {
1829
+ category: "color",
1830
+ type: "status",
1831
+ item: "verified",
1832
+ subitem: "on-surface",
1833
+ },
1834
+ path: ["color", "status", "verified", "on-surface"],
1835
+ },
1546
1836
  bg: {
1547
1837
  $value: "#e8ecf4",
1548
1838
  $type: "color",
@@ -1633,6 +1923,28 @@ module.exports = {
1633
1923
  },
1634
1924
  path: ["color", "status", "signal", "fg"],
1635
1925
  },
1926
+ "on-surface": {
1927
+ $value: "#346bad",
1928
+ $type: "color",
1929
+ $description:
1930
+ "Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip.",
1931
+ filePath: "src/tokens/component.tokens.json",
1932
+ isSource: true,
1933
+ original: {
1934
+ $value: "{color.semantic.signal-strong}",
1935
+ $type: "color",
1936
+ $description:
1937
+ "Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip.",
1938
+ },
1939
+ name: "ColorStatusSignalOnSurface",
1940
+ attributes: {
1941
+ category: "color",
1942
+ type: "status",
1943
+ item: "signal",
1944
+ subitem: "on-surface",
1945
+ },
1946
+ path: ["color", "status", "signal", "on-surface"],
1947
+ },
1636
1948
  bg: {
1637
1949
  $value: "#e8ecf4",
1638
1950
  $type: "color",
@@ -1721,6 +2033,28 @@ module.exports = {
1721
2033
  },
1722
2034
  path: ["color", "status", "caution", "fg"],
1723
2035
  },
2036
+ "on-surface": {
2037
+ $value: "#8e6014",
2038
+ $type: "color",
2039
+ $description:
2040
+ "Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip.",
2041
+ filePath: "src/tokens/component.tokens.json",
2042
+ isSource: true,
2043
+ original: {
2044
+ $value: "{color.semantic.caution-strong}",
2045
+ $type: "color",
2046
+ $description:
2047
+ "Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip.",
2048
+ },
2049
+ name: "ColorStatusCautionOnSurface",
2050
+ attributes: {
2051
+ category: "color",
2052
+ type: "status",
2053
+ item: "caution",
2054
+ subitem: "on-surface",
2055
+ },
2056
+ path: ["color", "status", "caution", "on-surface"],
2057
+ },
1724
2058
  bg: {
1725
2059
  $value: "#e8ecf4",
1726
2060
  $type: "color",
@@ -1809,6 +2143,28 @@ module.exports = {
1809
2143
  },
1810
2144
  path: ["color", "status", "critical", "fg"],
1811
2145
  },
2146
+ "on-surface": {
2147
+ $value: "#be3939",
2148
+ $type: "color",
2149
+ $description:
2150
+ "Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip.",
2151
+ filePath: "src/tokens/component.tokens.json",
2152
+ isSource: true,
2153
+ original: {
2154
+ $value: "{color.semantic.critical-strong}",
2155
+ $type: "color",
2156
+ $description:
2157
+ "Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip.",
2158
+ },
2159
+ name: "ColorStatusCriticalOnSurface",
2160
+ attributes: {
2161
+ category: "color",
2162
+ type: "status",
2163
+ item: "critical",
2164
+ subitem: "on-surface",
2165
+ },
2166
+ path: ["color", "status", "critical", "on-surface"],
2167
+ },
1812
2168
  bg: {
1813
2169
  $value: "#e8ecf4",
1814
2170
  $type: "color",
@@ -2132,14 +2488,14 @@ module.exports = {
2132
2488
  $value: "#4d9dff",
2133
2489
  $type: "color",
2134
2490
  $description:
2135
- "Focus ring color — semantic.signal (#4D9DFF). Contrast ≥3:1 verified in Task 7 (contrast-validation).",
2491
+ "Focus ring identity layer — semantic.signal (#4D9DFF). NOT ≥3:1 on light surfaces alone (2.56:1 on canvas); the casing layer carries WCAG 1.4.11 contrast (see ring.casing).",
2136
2492
  filePath: "src/tokens/focus.tokens.json",
2137
2493
  isSource: true,
2138
2494
  original: {
2139
2495
  $value: "{color.semantic.signal}",
2140
2496
  $type: "color",
2141
2497
  $description:
2142
- "Focus ring color — semantic.signal (#4D9DFF). Contrast ≥3:1 verified in Task 7 (contrast-validation).",
2498
+ "Focus ring identity layer — semantic.signal (#4D9DFF). NOT ≥3:1 on light surfaces alone (2.56:1 on canvas); the casing layer carries WCAG 1.4.11 contrast (see ring.casing).",
2143
2499
  },
2144
2500
  name: "FocusRingColor",
2145
2501
  attributes: {
@@ -2152,13 +2508,15 @@ module.exports = {
2152
2508
  offset: {
2153
2509
  $value: "2px",
2154
2510
  $type: "dimension",
2155
- $description: "Focus ring offset (gap between target and ring).",
2511
+ $description:
2512
+ "Focus ring offset (gap between target and ring); renders the ring on the page surface, not on a filled control.",
2156
2513
  filePath: "src/tokens/focus.tokens.json",
2157
2514
  isSource: true,
2158
2515
  original: {
2159
2516
  $value: "2px",
2160
2517
  $type: "dimension",
2161
- $description: "Focus ring offset (gap between target and ring).",
2518
+ $description:
2519
+ "Focus ring offset (gap between target and ring); renders the ring on the page surface, not on a filled control.",
2162
2520
  },
2163
2521
  name: "FocusRingOffset",
2164
2522
  attributes: {
@@ -2168,6 +2526,27 @@ module.exports = {
2168
2526
  },
2169
2527
  path: ["focus", "ring", "offset"],
2170
2528
  },
2529
+ casing: {
2530
+ $value: "#0b0f19",
2531
+ $type: "color",
2532
+ $description:
2533
+ "Two-tone focus ring contrast layer — the band's AAA text color, so the indicator has a ≥3:1 edge on every surface (light: dark ink ≈17:1; dark: light text ≈11:1+). Per WCAG 1.4.11.",
2534
+ filePath: "src/tokens/focus.tokens.json",
2535
+ isSource: true,
2536
+ original: {
2537
+ $value: "{color.text.primary}",
2538
+ $type: "color",
2539
+ $description:
2540
+ "Two-tone focus ring contrast layer — the band's AAA text color, so the indicator has a ≥3:1 edge on every surface (light: dark ink ≈17:1; dark: light text ≈11:1+). Per WCAG 1.4.11.",
2541
+ },
2542
+ name: "FocusRingCasing",
2543
+ attributes: {
2544
+ category: "focus",
2545
+ type: "ring",
2546
+ item: "casing",
2547
+ },
2548
+ path: ["focus", "ring", "casing"],
2549
+ },
2171
2550
  },
2172
2551
  },
2173
2552
  font: {
package/dist/tokens.json CHANGED
@@ -56,6 +56,18 @@
56
56
  "ColorTextDisabled": "#b0baca",
57
57
  "ColorTextInverse": "#fbfcfe",
58
58
  "ColorTextOnBrand": "#fbfcfe",
59
+ "ColorDarkSurfaceRaised": "#0f1320",
60
+ "ColorDarkSurfaceInput": "#161b2a",
61
+ "ColorDarkSurfaceBorder": "#1f2638",
62
+ "ColorDarkSurfaceBorderMuted": "#2a3142",
63
+ "ColorDarkTextSecondary": "#8a95a8",
64
+ "ColorDarkTextMuted": "#4a5567",
65
+ "ColorDarkTextDisabled": "#2a3142",
66
+ "ColorDarkTextInverse": "#0b0f19",
67
+ "ColorDuskSurfaceRaised": "#1f2638",
68
+ "ColorDuskSurfaceInput": "#1f2638",
69
+ "ColorDuskSurfaceBorder": "#4a5567",
70
+ "ColorDuskSurfaceBorderMuted": "#2a3142",
59
71
  "ColorScrimLight": "#0b0f1980",
60
72
  "ColorScrimDark": "#060912b3",
61
73
  "ColorActionPrimaryBg": "#7053e5",
@@ -73,18 +85,22 @@
73
85
  "ColorActionDestructiveFg": "#fbfcfe",
74
86
  "ColorActionDestructiveBorder": "#be3939",
75
87
  "ColorStatusVerifiedFg": "#007947",
88
+ "ColorStatusVerifiedOnSurface": "#007947",
76
89
  "ColorStatusVerifiedBg": "#e8ecf4",
77
90
  "ColorStatusVerifiedBorder": "#007947",
78
91
  "ColorStatusVerifiedAccent": "#00d17a",
79
92
  "ColorStatusSignalFg": "#346bad",
93
+ "ColorStatusSignalOnSurface": "#346bad",
80
94
  "ColorStatusSignalBg": "#e8ecf4",
81
95
  "ColorStatusSignalBorder": "#346bad",
82
96
  "ColorStatusSignalAccent": "#4d9dff",
83
97
  "ColorStatusCautionFg": "#8e6014",
98
+ "ColorStatusCautionOnSurface": "#8e6014",
84
99
  "ColorStatusCautionBg": "#e8ecf4",
85
100
  "ColorStatusCautionBorder": "#8e6014",
86
101
  "ColorStatusCautionAccent": "#f5a623",
87
102
  "ColorStatusCriticalFg": "#be3939",
103
+ "ColorStatusCriticalOnSurface": "#be3939",
88
104
  "ColorStatusCriticalBg": "#e8ecf4",
89
105
  "ColorStatusCriticalBorder": "#be3939",
90
106
  "ColorStatusCriticalAccent": "#ff4d4d",
@@ -103,6 +119,7 @@
103
119
  "FocusRingWidth": "2px",
104
120
  "FocusRingColor": "#4d9dff",
105
121
  "FocusRingOffset": "2px",
122
+ "FocusRingCasing": "#0b0f19",
106
123
  "FontFamilySans": "Inter, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
107
124
  "FontFamilyMono": "'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace",
108
125
  "FontWeightRegular": "400",
package/dist/tokens.mjs CHANGED
@@ -59,6 +59,18 @@ export const ColorTextMuted = "#8a95a8"; // Muted text — shared with obsidian.
59
59
  export const ColorTextDisabled = "#b0baca"; // Disabled text — low-contrast, deliberate. Aliases mist.400; downstream consumers may alternatively compose text.primary with state.opacity.disabled (0.38) for a different visual register.
60
60
  export const ColorTextInverse = "#fbfcfe"; // Text on dark surfaces (e.g. obsidian backdrop, dark scrim). Aliases mist.50 — the lightest neutral. Distinct from on-brand: inverse is for neutral-dark contexts; on-brand is reserved for brand backgrounds.
61
61
  export const ColorTextOnBrand = "#fbfcfe"; // Text on brand backgrounds (e.g. CTA buttons). Constant per brand discipline.
62
+ export const ColorDarkSurfaceRaised = "#0f1320"; // Raised surface · cards — dark family (dusk/night). Mirrors surface.raised in light.
63
+ export const ColorDarkSurfaceInput = "#161b2a"; // Input / well — dark family (dusk/night).
64
+ export const ColorDarkSurfaceBorder = "#1f2638"; // Border / divider — dark family (dusk/night).
65
+ export const ColorDarkSurfaceBorderMuted = "#2a3142"; // Muted border — dark family (dusk/night).
66
+ export const ColorDarkTextSecondary = "#8a95a8"; // Secondary text — dark family (dusk/night); 6.6:1 on night canvas.
67
+ export const ColorDarkTextMuted = "#4a5567"; // Muted text — dark family; de-emphasized, same sub-UI register as light muted (~2.3-2.6:1).
68
+ export const ColorDarkTextDisabled = "#2a3142"; // Disabled text — dark family; low-contrast, deliberate (contrast-exempt).
69
+ export const ColorDarkTextInverse = "#0b0f19"; // Text on light surfaces within a dark context — dark family. (0 current component uses.)
70
+ export const ColorDuskSurfaceRaised = "#1f2638"; // Raised surface · cards — DUSK band only. The dusk canvas (#1a1a26, L≈0.011) is lighter than the shared dark family's raised (obsidian.850, L≈0.0067), which inverted elevation. Obsidian.700 (L≈0.0196) sits ABOVE the dusk canvas so cards read raised, while secondary text still clears AA (≈5.0:1).
71
+ export const ColorDuskSurfaceInput = "#1f2638"; // Input / well — DUSK band only. Same tone as dusk raised (lifted above the dusk canvas); distinguished from cards by its border. Obsidian.700 keeps muted text at the ≈2.0:1 perceptible floor (obsidian.600 would drop it to ~1.7:1 and fail).
72
+ export const ColorDuskSurfaceBorder = "#4a5567"; // Border / divider — DUSK band only. Obsidian.500 (L≈0.089) gives inputs/cards a visible boundary on the dusk canvas (≈2.3:1) where the shared dark border (obsidian.700) would be ~invisible.
73
+ export const ColorDuskSurfaceBorderMuted = "#2a3142"; // Muted border — DUSK band only; the softer divider above the dusk canvas.
62
74
  export const ColorScrimLight = "#0b0f1980"; // Modal/sheet backdrop on light surfaces — obsidian-900 at 50% opacity (per BR-2 spec §4).
63
75
  export const ColorScrimDark = "#060912b3"; // Modal/sheet backdrop on dark surfaces — obsidian-950 at 70% opacity for stronger isolation.
64
76
  export const ColorActionPrimaryBg = "#7053e5"; // Primary action background — Sovereign Violet. The single high-emphasis CTA per surface. — AA-darkened (brand-strong, 5.04:1 with white).
@@ -76,18 +88,22 @@ export const ColorActionDestructiveBg = "#be3939"; // Destructive action backgro
76
88
  export const ColorActionDestructiveFg = "#fbfcfe"; // Text/icon on a destructive action.
77
89
  export const ColorActionDestructiveBorder = "#be3939"; // Destructive action border. — AA-darkened (critical-strong, 5.34:1 with white).
78
90
  export const ColorStatusVerifiedFg = "#007947"; // Verified status foreground — Verified Green darkened to WCAG AA (#007947, ≥4.5:1 on the chip bg). The in-product success state; never the brand.
91
+ export const ColorStatusVerifiedOnSurface = "#007947"; // Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip.
79
92
  export const ColorStatusVerifiedBg = "#e8ecf4"; // Verified status chip background — neutral; color carried by fg/border (restraint over volume).
80
93
  export const ColorStatusVerifiedBorder = "#007947"; // Verified status border — AA-dark shade (≥3:1 non-text).
81
94
  export const ColorStatusVerifiedAccent = "#00d17a"; // Verified bright decorative accent (#00D17A) — for icons/fills where contrast is not a text/border requirement.
82
95
  export const ColorStatusSignalFg = "#346bad"; // Informational status foreground — Signal darkened to WCAG AA (#346BAD, ≥4.5:1 on the chip bg).
96
+ export const ColorStatusSignalOnSurface = "#346bad"; // Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip.
83
97
  export const ColorStatusSignalBg = "#e8ecf4"; // Informational status chip background — neutral.
84
98
  export const ColorStatusSignalBorder = "#346bad"; // Informational status border — AA-dark shade (≥3:1 non-text).
85
99
  export const ColorStatusSignalAccent = "#4d9dff"; // Signal bright decorative accent (#4D9DFF) — for icons/fills.
86
100
  export const ColorStatusCautionFg = "#8e6014"; // Caution status foreground — Caution darkened to WCAG AA (#8E6014, ≥4.5:1 on the chip bg); pending / in-progress.
101
+ export const ColorStatusCautionOnSurface = "#8e6014"; // Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip.
87
102
  export const ColorStatusCautionBg = "#e8ecf4"; // Caution status chip background — neutral.
88
103
  export const ColorStatusCautionBorder = "#8e6014"; // Caution status border — AA-dark shade (≥3:1 non-text).
89
104
  export const ColorStatusCautionAccent = "#f5a623"; // Caution bright decorative accent (#F5A623) — for icons/fills.
90
105
  export const ColorStatusCriticalFg = "#be3939"; // Critical status foreground — Critical darkened to WCAG AA (#BE3939, ≥4.5:1 on the chip bg); error / failure.
106
+ export const ColorStatusCriticalOnSurface = "#be3939"; // Status foreground for INLINE status text/icons on a theme surface — band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip.
91
107
  export const ColorStatusCriticalBg = "#e8ecf4"; // Critical status chip background — neutral.
92
108
  export const ColorStatusCriticalBorder = "#be3939"; // Critical status border — AA-dark shade (≥3:1 non-text).
93
109
  export const ColorStatusCriticalAccent = "#ff4d4d"; // Critical bright decorative accent (#FF4D4D) — for icons/fills.
@@ -104,8 +120,9 @@ export const ContainerLg = "64rem"; // Container max-width at lg breakpoint
104
120
  export const ContainerXl = "80rem"; // Container max-width at xl breakpoint
105
121
  export const Container2xl = "96rem"; // Container max-width at 2xl breakpoint
106
122
  export const FocusRingWidth = "2px"; // Focus ring width. Per WCAG 2.4.7.
107
- export const FocusRingColor = "#4d9dff"; // Focus ring color — semantic.signal (#4D9DFF). Contrast ≥3:1 verified in Task 7 (contrast-validation).
108
- export const FocusRingOffset = "2px"; // Focus ring offset (gap between target and ring).
123
+ export const FocusRingColor = "#4d9dff"; // Focus ring identity layer — semantic.signal (#4D9DFF). NOT ≥3:1 on light surfaces alone (2.56:1 on canvas); the casing layer carries WCAG 1.4.11 contrast (see ring.casing).
124
+ export const FocusRingOffset = "2px"; // Focus ring offset (gap between target and ring); renders the ring on the page surface, not on a filled control.
125
+ export const FocusRingCasing = "#0b0f19"; // Two-tone focus ring contrast layer — the band's AAA text color, so the indicator has a ≥3:1 edge on every surface (light: dark ink ≈17:1; dark: light text ≈11:1+). Per WCAG 1.4.11.
109
126
  export const FontFamilySans =
110
127
  "Inter, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif"; // Primary UI and reading family — Inter Variable per BR-1 §5.1. System fallbacks listed in priority order.
111
128
  export const FontFamilyMono =
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdify/tokens",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Verdify design tokens — W3C DTCG sources with Tailwind v4 preset, CSS vars, JS/TS, and raw JSON outputs",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {
@@ -13,29 +13,36 @@
13
13
  "directory": "packages/tokens"
14
14
  },
15
15
  "exports": {
16
- ".": { "import": "./dist/tokens.mjs", "require": "./dist/tokens.js", "types": "./dist/tokens.d.ts" },
17
- "./css": "./dist/tokens.css",
18
- "./preset": "./dist/preset.css",
19
- "./preset-adaptive": "./dist/preset-adaptive.css",
20
- "./json": "./dist/tokens.json",
21
- "./tokens/*": "./src/tokens/*"
22
- },
23
- "files": ["dist/", "src/tokens/", "README.md"],
24
- "scripts": {
25
- "sync": "tsx scripts/sync-color.ts",
26
- "sync:print": "tsx scripts/sync-print.ts",
27
- "build:ase": "tsx scripts/build-ase.ts",
28
- "validate": "tsx scripts/validate.ts",
29
- "build": "pnpm run sync && pnpm run sync:print && pnpm run build:ase && pnpm run validate && tsx scripts/build.ts",
30
- "verify": "pnpm run build && git diff --exit-code src/ ../ui_flutter/lib/src/theme/",
31
- "test": "tsx scripts/test.ts",
32
- "prepublishOnly": "pnpm run build"
16
+ ".": {
17
+ "import": "./dist/tokens.mjs",
18
+ "require": "./dist/tokens.js",
19
+ "types": "./dist/tokens.d.ts"
20
+ },
21
+ "./css": "./dist/tokens.css",
22
+ "./preset": "./dist/preset.css",
23
+ "./preset-adaptive": "./dist/preset-adaptive.css",
24
+ "./json": "./dist/tokens.json",
25
+ "./tokens/*": "./src/tokens/*"
33
26
  },
27
+ "files": [
28
+ "dist/",
29
+ "src/tokens/",
30
+ "README.md"
31
+ ],
34
32
  "devDependencies": {
35
33
  "style-dictionary": "^4.0.0",
36
- "tsx": "^4.7.0",
37
- "typescript": "^5.4.0",
38
- "ajv": "^8.12.0",
39
- "@types/node": "^20.0.0"
34
+ "tsx": "^4.7.0",
35
+ "typescript": "^5.4.0",
36
+ "ajv": "^8.12.0",
37
+ "@types/node": "^20.0.0"
38
+ },
39
+ "scripts": {
40
+ "sync": "tsx scripts/sync-color.ts",
41
+ "sync:print": "tsx scripts/sync-print.ts",
42
+ "build:ase": "tsx scripts/build-ase.ts",
43
+ "validate": "tsx scripts/validate.ts",
44
+ "build": "pnpm run sync && pnpm run sync:print && pnpm run build:ase && pnpm run validate && tsx scripts/build.ts",
45
+ "verify": "pnpm run build && git diff --exit-code src/ ../ui_flutter/lib/src/theme/",
46
+ "test": "tsx scripts/test.ts"
40
47
  }
41
- }
48
+ }
@@ -264,6 +264,76 @@
264
264
  "$description": "Text on brand backgrounds (e.g. CTA buttons). Constant per brand discipline."
265
265
  }
266
266
  },
267
+ "dark": {
268
+ "surface": {
269
+ "raised": {
270
+ "$value": "{color.neutral.obsidian.850}",
271
+ "$type": "color",
272
+ "$description": "Raised surface · cards — dark family (dusk/night). Mirrors surface.raised in light."
273
+ },
274
+ "input": {
275
+ "$value": "{color.neutral.obsidian.800}",
276
+ "$type": "color",
277
+ "$description": "Input / well — dark family (dusk/night)."
278
+ },
279
+ "border": {
280
+ "$value": "{color.neutral.obsidian.700}",
281
+ "$type": "color",
282
+ "$description": "Border / divider — dark family (dusk/night)."
283
+ },
284
+ "border-muted": {
285
+ "$value": "{color.neutral.obsidian.600}",
286
+ "$type": "color",
287
+ "$description": "Muted border — dark family (dusk/night)."
288
+ }
289
+ },
290
+ "text": {
291
+ "secondary": {
292
+ "$value": "{color.neutral.obsidian.400}",
293
+ "$type": "color",
294
+ "$description": "Secondary text — dark family (dusk/night); 6.6:1 on night canvas."
295
+ },
296
+ "muted": {
297
+ "$value": "{color.neutral.obsidian.500}",
298
+ "$type": "color",
299
+ "$description": "Muted text — dark family; de-emphasized, same sub-UI register as light muted (~2.3-2.6:1)."
300
+ },
301
+ "disabled": {
302
+ "$value": "{color.neutral.obsidian.600}",
303
+ "$type": "color",
304
+ "$description": "Disabled text — dark family; low-contrast, deliberate (contrast-exempt)."
305
+ },
306
+ "inverse": {
307
+ "$value": "{color.neutral.mist.950}",
308
+ "$type": "color",
309
+ "$description": "Text on light surfaces within a dark context — dark family. (0 current component uses.)"
310
+ }
311
+ }
312
+ },
313
+ "dusk": {
314
+ "surface": {
315
+ "raised": {
316
+ "$value": "{color.neutral.obsidian.700}",
317
+ "$type": "color",
318
+ "$description": "Raised surface · cards — DUSK band only. The dusk canvas (#1a1a26, L≈0.011) is lighter than the shared dark family's raised (obsidian.850, L≈0.0067), which inverted elevation. Obsidian.700 (L≈0.0196) sits ABOVE the dusk canvas so cards read raised, while secondary text still clears AA (≈5.0:1)."
319
+ },
320
+ "input": {
321
+ "$value": "{color.neutral.obsidian.700}",
322
+ "$type": "color",
323
+ "$description": "Input / well — DUSK band only. Same tone as dusk raised (lifted above the dusk canvas); distinguished from cards by its border. Obsidian.700 keeps muted text at the ≈2.0:1 perceptible floor (obsidian.600 would drop it to ~1.7:1 and fail)."
324
+ },
325
+ "border": {
326
+ "$value": "{color.neutral.obsidian.500}",
327
+ "$type": "color",
328
+ "$description": "Border / divider — DUSK band only. Obsidian.500 (L≈0.089) gives inputs/cards a visible boundary on the dusk canvas (≈2.3:1) where the shared dark border (obsidian.700) would be ~invisible."
329
+ },
330
+ "border-muted": {
331
+ "$value": "{color.neutral.obsidian.600}",
332
+ "$type": "color",
333
+ "$description": "Muted border — DUSK band only; the softer divider above the dusk canvas."
334
+ }
335
+ }
336
+ },
267
337
  "scrim": {
268
338
  "light": {
269
339
  "$value": "rgba(11, 15, 25, 0.5)",
@@ -26,28 +26,32 @@
26
26
  },
27
27
  "status": {
28
28
  "verified": {
29
- "fg": { "$value": "{color.semantic.verified-strong}", "$type": "color", "$description": "Verified status foreground — Verified Green darkened to WCAG AA (#007947, ≥4.5:1 on the chip bg). The in-product success state; never the brand." },
30
- "bg": { "$value": "{color.surface.raised}", "$type": "color", "$description": "Verified status chip backgroundneutral; color carried by fg/border (restraint over volume)." },
31
- "border": { "$value": "{color.semantic.verified-strong}", "$type": "color", "$description": "Verified status borderAA-dark shade (≥3:1 non-text)." },
32
- "accent": { "$value": "{color.semantic.verified}", "$type": "color", "$description": "Verified bright decorative accent (#00D17A) for icons/fills where contrast is not a text/border requirement." }
29
+ "fg": { "$value": "{color.semantic.verified-strong}", "$type": "color", "$description": "Verified status foreground — Verified Green darkened to WCAG AA (#007947, ≥4.5:1 on the chip bg). The in-product success state; never the brand." },
30
+ "on-surface": { "$value": "{color.semantic.verified-strong}", "$type": "color", "$description": "Status foreground for INLINE status text/icons on a theme surface band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip." },
31
+ "bg": { "$value": "{color.surface.raised}", "$type": "color", "$description": "Verified status chip background neutral; color carried by fg/border (restraint over volume)." },
32
+ "border": { "$value": "{color.semantic.verified-strong}", "$type": "color", "$description": "Verified status borderAA-dark shade (≥3:1 non-text)." },
33
+ "accent": { "$value": "{color.semantic.verified}", "$type": "color", "$description": "Verified bright decorative accent (#00D17A) — for icons/fills where contrast is not a text/border requirement." }
33
34
  },
34
35
  "signal": {
35
- "fg": { "$value": "{color.semantic.signal-strong}", "$type": "color", "$description": "Informational status foreground — Signal darkened to WCAG AA (#346BAD, ≥4.5:1 on the chip bg)." },
36
- "bg": { "$value": "{color.surface.raised}", "$type": "color", "$description": "Informational status chip backgroundneutral." },
37
- "border": { "$value": "{color.semantic.signal-strong}", "$type": "color", "$description": "Informational status borderAA-dark shade (≥3:1 non-text)." },
38
- "accent": { "$value": "{color.semantic.signal}", "$type": "color", "$description": "Signal bright decorative accent (#4D9DFF) for icons/fills." }
36
+ "fg": { "$value": "{color.semantic.signal-strong}", "$type": "color", "$description": "Informational status foreground — Signal darkened to WCAG AA (#346BAD, ≥4.5:1 on the chip bg)." },
37
+ "on-surface": { "$value": "{color.semantic.signal-strong}", "$type": "color", "$description": "Status foreground for INLINE status text/icons on a theme surface band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip." },
38
+ "bg": { "$value": "{color.surface.raised}", "$type": "color", "$description": "Informational status chip background neutral." },
39
+ "border": { "$value": "{color.semantic.signal-strong}", "$type": "color", "$description": "Informational status border AA-dark shade (≥3:1 non-text)." },
40
+ "accent": { "$value": "{color.semantic.signal}", "$type": "color", "$description": "Signal bright decorative accent (#4D9DFF) — for icons/fills." }
39
41
  },
40
42
  "caution": {
41
- "fg": { "$value": "{color.semantic.caution-strong}", "$type": "color", "$description": "Caution status foreground — Caution darkened to WCAG AA (#8E6014, ≥4.5:1 on the chip bg); pending / in-progress." },
42
- "bg": { "$value": "{color.surface.raised}", "$type": "color", "$description": "Caution status chip backgroundneutral." },
43
- "border": { "$value": "{color.semantic.caution-strong}", "$type": "color", "$description": "Caution status borderAA-dark shade (≥3:1 non-text)." },
44
- "accent": { "$value": "{color.semantic.caution}", "$type": "color", "$description": "Caution bright decorative accent (#F5A623) for icons/fills." }
43
+ "fg": { "$value": "{color.semantic.caution-strong}", "$type": "color", "$description": "Caution status foreground — Caution darkened to WCAG AA (#8E6014, ≥4.5:1 on the chip bg); pending / in-progress." },
44
+ "on-surface": { "$value": "{color.semantic.caution-strong}", "$type": "color", "$description": "Status foreground for INLINE status text/icons on a theme surface band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip." },
45
+ "bg": { "$value": "{color.surface.raised}", "$type": "color", "$description": "Caution status chip background neutral." },
46
+ "border": { "$value": "{color.semantic.caution-strong}", "$type": "color", "$description": "Caution status border AA-dark shade (≥3:1 non-text)." },
47
+ "accent": { "$value": "{color.semantic.caution}", "$type": "color", "$description": "Caution bright decorative accent (#F5A623) — for icons/fills." }
45
48
  },
46
49
  "critical": {
47
- "fg": { "$value": "{color.semantic.critical-strong}", "$type": "color", "$description": "Critical status foreground — Critical darkened to WCAG AA (#BE3939, ≥4.5:1 on the chip bg); error / failure." },
48
- "bg": { "$value": "{color.surface.raised}", "$type": "color", "$description": "Critical status chip backgroundneutral." },
49
- "border": { "$value": "{color.semantic.critical-strong}", "$type": "color", "$description": "Critical status borderAA-dark shade (≥3:1 non-text)." },
50
- "accent": { "$value": "{color.semantic.critical}", "$type": "color", "$description": "Critical bright decorative accent (#FF4D4D) for icons/fills." }
50
+ "fg": { "$value": "{color.semantic.critical-strong}", "$type": "color", "$description": "Critical status foreground — Critical darkened to WCAG AA (#BE3939, ≥4.5:1 on the chip bg); error / failure." },
51
+ "on-surface": { "$value": "{color.semantic.critical-strong}", "$type": "color", "$description": "Status foreground for INLINE status text/icons on a theme surface band-aware: -strong on light bands, bright base on dusk/night (AA on dark). Distinct from .fg, which is for the always-light status chip." },
52
+ "bg": { "$value": "{color.surface.raised}", "$type": "color", "$description": "Critical status chip background neutral." },
53
+ "border": { "$value": "{color.semantic.critical-strong}", "$type": "color", "$description": "Critical status border AA-dark shade (≥3:1 non-text)." },
54
+ "accent": { "$value": "{color.semantic.critical}", "$type": "color", "$description": "Critical bright decorative accent (#FF4D4D) — for icons/fills." }
51
55
  }
52
56
  },
53
57
  "border": {
@@ -2,8 +2,9 @@
2
2
  "focus": {
3
3
  "ring": {
4
4
  "width": { "$value": "2px", "$type": "dimension", "$description": "Focus ring width. Per WCAG 2.4.7." },
5
- "color": { "$value": "{color.semantic.signal}", "$type": "color", "$description": "Focus ring color — semantic.signal (#4D9DFF). Contrast ≥3:1 verified in Task 7 (contrast-validation)." },
6
- "offset": { "$value": "2px", "$type": "dimension", "$description": "Focus ring offset (gap between target and ring)." }
5
+ "color": { "$value": "{color.semantic.signal}", "$type": "color", "$description": "Focus ring identity layer — semantic.signal (#4D9DFF). NOT ≥3:1 on light surfaces alone (2.56:1 on canvas); the casing layer carries WCAG 1.4.11 contrast (see ring.casing)." },
6
+ "offset": { "$value": "2px", "$type": "dimension", "$description": "Focus ring offset (gap between target and ring); renders the ring on the page surface, not on a filled control." },
7
+ "casing": { "$value": "{color.text.primary}", "$type": "color", "$description": "Two-tone focus ring contrast layer — the band's AAA text color, so the indicator has a ≥3:1 edge on every surface (light: dark ink ≈17:1; dark: light text ≈11:1+). Per WCAG 1.4.11." }
7
8
  }
8
9
  }
9
10
  }