@dataimago/tokens-neutral 0.1.0-alpha.16 → 0.1.0-alpha.18

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/dist/colors.json CHANGED
@@ -96,7 +96,7 @@
96
96
  },
97
97
  "200": {
98
98
  "value": "#faf2e3",
99
- "description": "Paper scale — code-block and pull-quote background"
99
+ "description": "Paper scale — pull-quote background"
100
100
  },
101
101
  "300": {
102
102
  "value": "#f5e8cf",
@@ -114,20 +114,20 @@
114
114
  },
115
115
  "functional": {
116
116
  "success": {
117
- "value": "#27AE60",
118
- "description": "Success states and positive actions"
117
+ "value": "#009E73",
118
+ "description": "Success hue (Okabe-Ito bluish-green, 2026-11-02; was Flat-UI #27AE60). For text use the mode-aware color.state.success"
119
119
  },
120
120
  "warning": {
121
- "value": "#F39C12",
122
- "description": "Warning states and caution"
121
+ "value": "#E69F00",
122
+ "description": "Warning hue (Okabe-Ito orange, 2026-11-02; was Flat-UI #F39C12). For text use the mode-aware color.state.warning"
123
123
  },
124
124
  "error": {
125
- "value": "#E74C3C",
126
- "description": "Error states and critical issues"
125
+ "value": "#ef5350",
126
+ "description": "Error hue (red, 2026-11-02; was Flat-UI #E74C3C). For text use the mode-aware color.state.error"
127
127
  },
128
128
  "info": {
129
- "value": "#3498DB",
130
- "description": "Informational content"
129
+ "value": "#d6d3d1",
130
+ "description": "Info hue (the neutral accent, ink-200, 2026-11-02; was the house #3498DB, which css-neutral does not carry). For text use the mode-aware color.state.info"
131
131
  }
132
132
  }
133
133
  }
package/dist/effects.json CHANGED
@@ -14,6 +14,18 @@
14
14
  "light": "0 10px 15px -3px rgb(20 20 16 / 0.1)",
15
15
  "dark": "0 10px 15px -3px rgb(237 237 235 / 0.4)",
16
16
  "description": "Strong elevation - modals, floating elements"
17
+ },
18
+ "figure-plate": {
19
+ "hover": {
20
+ "light": "0 10px 15px -3px rgb(20 20 16 / 0.1)",
21
+ "dark": "0 4px 12px rgb(0 0 0 / 0.5)",
22
+ "description": "Figure plate on hover. Light mode is the prominent shadow. Dark mode needs its own value: the plate stays light in dark mode, and prominent's light-ink glow (rgb(237 237 235 / 0.4)) would haze the dark page round a light plate, so a plain black shadow is used. Not mode-invariant."
23
+ },
24
+ "active": {
25
+ "light": "0 4px 6px -1px rgb(20 20 16 / 0.1)",
26
+ "dark": "0 2px 8px rgb(0 0 0 / 0.35)",
27
+ "description": "Figure plate while pressed. Light mode is the moderate shadow; dark mode is a plain black shadow for the same reason as figure-plate.hover. Not mode-invariant."
28
+ }
17
29
  }
18
30
  },
19
31
  "border": {
package/dist/index.cjs CHANGED
@@ -18,9 +18,9 @@ const tokens = {
18
18
  "description": "Cards, modals, dropdowns — one step above page (stone-50 / ink-800)"
19
19
  },
20
20
  "sunken": {
21
- "light": "#faf2e3",
21
+ "light": "#f7f7f6",
22
22
  "dark": "#0c0a09",
23
- "description": "Input fields, code blocks — below page level (paper-200 light / ink-900 dark)"
23
+ "description": "Input fields and insets. Light: the card colour, stone-50 (since 2026-11-02; it was the warm paper-200 #faf2e3). Dark: ink-900, below the page. Code blocks use surface.code."
24
24
  },
25
25
  "navbar": {
26
26
  "light": "#ededeb",
@@ -33,9 +33,19 @@ const tokens = {
33
33
  "description": "Navbar when scrolled/shrunk — matches page-scrolled"
34
34
  },
35
35
  "code": {
36
- "light": "#faf2e3",
36
+ "light": "#f7f7f6",
37
37
  "dark": "#1c1917",
38
- "description": "Code block and inline code background"
38
+ "description": "Code block and inline code background: the card colour in both modes (2026-11-02; light mode was paper-200 #faf2e3)"
39
+ },
40
+ "scrim": {
41
+ "light": "rgba(20, 20, 16, 0.85)",
42
+ "dark": "rgba(20, 20, 16, 0.85)",
43
+ "description": "Figure viewer backdrop. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Ink-900-ish at 0.85, drawn under a 3px blur; measured composited over the page, on-scrim text is 11.5:1 on the light page and 17.2:1 on the dark (gated by tools/contrast-check.mjs, 2026-11-03)."
44
+ },
45
+ "scrim-solid": {
46
+ "light": "rgba(20, 20, 16, 0.92)",
47
+ "dark": "rgba(20, 20, 16, 0.92)",
48
+ "description": "Figure viewer backdrop where backdrop blur is unavailable (prefers-reduced-transparency, prefers-contrast: more and browsers without backdrop blur): the same ink at 0.92. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Gated by tools/contrast-check.mjs."
39
49
  }
40
50
  },
41
51
  "border": {
@@ -63,6 +73,11 @@ const tokens = {
63
73
  "light": "#d6d3d1",
64
74
  "dark": "#292524",
65
75
  "description": "Code block border"
76
+ },
77
+ "on-scrim-focus": {
78
+ "light": "#f7f7f6",
79
+ "dark": "#f7f7f6",
80
+ "description": "Focus ring on the figure viewer scrim. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). The neutral identity uses ink, not slate, for accents (the state-colours ADR), so the ring is on-scrim stone-50. Held to 3:1 (WCAG 1.4.11) over both scrims and both page modes by tools/contrast-check.mjs."
66
81
  }
67
82
  },
68
83
  "content": {
@@ -85,6 +100,11 @@ const tokens = {
85
100
  "light": "#fdf9f2",
86
101
  "dark": "#0c0a09",
87
102
  "description": "Inverse text — for contrasting backgrounds"
103
+ },
104
+ "on-scrim": {
105
+ "light": "#f7f7f6",
106
+ "dark": "#f7f7f6",
107
+ "description": "Text and controls on the figure viewer scrim (stone-50). Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Held to 7:1 over both scrims and both page modes by tools/contrast-check.mjs."
88
108
  }
89
109
  },
90
110
  "interactive": {
@@ -109,6 +129,28 @@ const tokens = {
109
129
  "description": "Focus indicators — mirrors interactive.primary"
110
130
  }
111
131
  },
132
+ "state": {
133
+ "success": {
134
+ "light": "#007a58",
135
+ "dark": "#009E73",
136
+ "description": "State: success. Okabe-Ito bluish-green, darkened in light mode for text: 4.56:1 on page and 4.99:1 on card (dark 5.40 / 5.11). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
137
+ },
138
+ "warning": {
139
+ "light": "#906306",
140
+ "dark": "#E69F00",
141
+ "description": "State: warning. Okabe-Ito orange, darkened in light mode to an amber that holds text contrast: 4.51:1 on page and 4.93:1 on card (dark 8.20 / 7.76). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
142
+ },
143
+ "error": {
144
+ "light": "#a4262c",
145
+ "dark": "#ef5350",
146
+ "description": "State: error. Red rather than Okabe-Ito vermillion: darkened vermillion collapses into the amber warning under deuteranopia (ΔE 2.0). 6.2:1 on page in light mode (dark 5.30 / 5.02). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
147
+ },
148
+ "info": {
149
+ "light": "#292524",
150
+ "dark": "#d6d3d1",
151
+ "description": "State: info. The neutral accent (ink-700 / ink-200), since css-neutral ships no brand accent. 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
152
+ }
153
+ },
112
154
  "dataviz": {
113
155
  "okabe-ito": {
114
156
  "orange": {
package/dist/index.mjs CHANGED
@@ -18,9 +18,9 @@ const tokens = {
18
18
  "description": "Cards, modals, dropdowns — one step above page (stone-50 / ink-800)"
19
19
  },
20
20
  "sunken": {
21
- "light": "#faf2e3",
21
+ "light": "#f7f7f6",
22
22
  "dark": "#0c0a09",
23
- "description": "Input fields, code blocks — below page level (paper-200 light / ink-900 dark)"
23
+ "description": "Input fields and insets. Light: the card colour, stone-50 (since 2026-11-02; it was the warm paper-200 #faf2e3). Dark: ink-900, below the page. Code blocks use surface.code."
24
24
  },
25
25
  "navbar": {
26
26
  "light": "#ededeb",
@@ -33,9 +33,19 @@ const tokens = {
33
33
  "description": "Navbar when scrolled/shrunk — matches page-scrolled"
34
34
  },
35
35
  "code": {
36
- "light": "#faf2e3",
36
+ "light": "#f7f7f6",
37
37
  "dark": "#1c1917",
38
- "description": "Code block and inline code background"
38
+ "description": "Code block and inline code background: the card colour in both modes (2026-11-02; light mode was paper-200 #faf2e3)"
39
+ },
40
+ "scrim": {
41
+ "light": "rgba(20, 20, 16, 0.85)",
42
+ "dark": "rgba(20, 20, 16, 0.85)",
43
+ "description": "Figure viewer backdrop. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Ink-900-ish at 0.85, drawn under a 3px blur; measured composited over the page, on-scrim text is 11.5:1 on the light page and 17.2:1 on the dark (gated by tools/contrast-check.mjs, 2026-11-03)."
44
+ },
45
+ "scrim-solid": {
46
+ "light": "rgba(20, 20, 16, 0.92)",
47
+ "dark": "rgba(20, 20, 16, 0.92)",
48
+ "description": "Figure viewer backdrop where backdrop blur is unavailable (prefers-reduced-transparency, prefers-contrast: more and browsers without backdrop blur): the same ink at 0.92. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Gated by tools/contrast-check.mjs."
39
49
  }
40
50
  },
41
51
  "border": {
@@ -63,6 +73,11 @@ const tokens = {
63
73
  "light": "#d6d3d1",
64
74
  "dark": "#292524",
65
75
  "description": "Code block border"
76
+ },
77
+ "on-scrim-focus": {
78
+ "light": "#f7f7f6",
79
+ "dark": "#f7f7f6",
80
+ "description": "Focus ring on the figure viewer scrim. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). The neutral identity uses ink, not slate, for accents (the state-colours ADR), so the ring is on-scrim stone-50. Held to 3:1 (WCAG 1.4.11) over both scrims and both page modes by tools/contrast-check.mjs."
66
81
  }
67
82
  },
68
83
  "content": {
@@ -85,6 +100,11 @@ const tokens = {
85
100
  "light": "#fdf9f2",
86
101
  "dark": "#0c0a09",
87
102
  "description": "Inverse text — for contrasting backgrounds"
103
+ },
104
+ "on-scrim": {
105
+ "light": "#f7f7f6",
106
+ "dark": "#f7f7f6",
107
+ "description": "Text and controls on the figure viewer scrim (stone-50). Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Held to 7:1 over both scrims and both page modes by tools/contrast-check.mjs."
88
108
  }
89
109
  },
90
110
  "interactive": {
@@ -109,6 +129,28 @@ const tokens = {
109
129
  "description": "Focus indicators — mirrors interactive.primary"
110
130
  }
111
131
  },
132
+ "state": {
133
+ "success": {
134
+ "light": "#007a58",
135
+ "dark": "#009E73",
136
+ "description": "State: success. Okabe-Ito bluish-green, darkened in light mode for text: 4.56:1 on page and 4.99:1 on card (dark 5.40 / 5.11). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
137
+ },
138
+ "warning": {
139
+ "light": "#906306",
140
+ "dark": "#E69F00",
141
+ "description": "State: warning. Okabe-Ito orange, darkened in light mode to an amber that holds text contrast: 4.51:1 on page and 4.93:1 on card (dark 8.20 / 7.76). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
142
+ },
143
+ "error": {
144
+ "light": "#a4262c",
145
+ "dark": "#ef5350",
146
+ "description": "State: error. Red rather than Okabe-Ito vermillion: darkened vermillion collapses into the amber warning under deuteranopia (ΔE 2.0). 6.2:1 on page in light mode (dark 5.30 / 5.02). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
147
+ },
148
+ "info": {
149
+ "light": "#292524",
150
+ "dark": "#d6d3d1",
151
+ "description": "State: info. The neutral accent (ink-700 / ink-200), since css-neutral ships no brand accent. 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
152
+ }
153
+ },
112
154
  "dataviz": {
113
155
  "okabe-ito": {
114
156
  "orange": {
@@ -17,9 +17,9 @@
17
17
  "description": "Cards, modals, dropdowns — one step above page (stone-50 / ink-800)"
18
18
  },
19
19
  "sunken": {
20
- "light": "#faf2e3",
20
+ "light": "#f7f7f6",
21
21
  "dark": "#0c0a09",
22
- "description": "Input fields, code blocks — below page level (paper-200 light / ink-900 dark)"
22
+ "description": "Input fields and insets. Light: the card colour, stone-50 (since 2026-11-02; it was the warm paper-200 #faf2e3). Dark: ink-900, below the page. Code blocks use surface.code."
23
23
  },
24
24
  "navbar": {
25
25
  "light": "#ededeb",
@@ -32,9 +32,19 @@
32
32
  "description": "Navbar when scrolled/shrunk — matches page-scrolled"
33
33
  },
34
34
  "code": {
35
- "light": "#faf2e3",
35
+ "light": "#f7f7f6",
36
36
  "dark": "#1c1917",
37
- "description": "Code block and inline code background"
37
+ "description": "Code block and inline code background: the card colour in both modes (2026-11-02; light mode was paper-200 #faf2e3)"
38
+ },
39
+ "scrim": {
40
+ "light": "rgba(20, 20, 16, 0.85)",
41
+ "dark": "rgba(20, 20, 16, 0.85)",
42
+ "description": "Figure viewer backdrop. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Ink-900-ish at 0.85, drawn under a 3px blur; measured composited over the page, on-scrim text is 11.5:1 on the light page and 17.2:1 on the dark (gated by tools/contrast-check.mjs, 2026-11-03)."
43
+ },
44
+ "scrim-solid": {
45
+ "light": "rgba(20, 20, 16, 0.92)",
46
+ "dark": "rgba(20, 20, 16, 0.92)",
47
+ "description": "Figure viewer backdrop where backdrop blur is unavailable (prefers-reduced-transparency, prefers-contrast: more and browsers without backdrop blur): the same ink at 0.92. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Gated by tools/contrast-check.mjs."
38
48
  }
39
49
  },
40
50
  "border": {
@@ -62,6 +72,11 @@
62
72
  "light": "#d6d3d1",
63
73
  "dark": "#292524",
64
74
  "description": "Code block border"
75
+ },
76
+ "on-scrim-focus": {
77
+ "light": "#f7f7f6",
78
+ "dark": "#f7f7f6",
79
+ "description": "Focus ring on the figure viewer scrim. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). The neutral identity uses ink, not slate, for accents (the state-colours ADR), so the ring is on-scrim stone-50. Held to 3:1 (WCAG 1.4.11) over both scrims and both page modes by tools/contrast-check.mjs."
65
80
  }
66
81
  },
67
82
  "content": {
@@ -84,6 +99,11 @@
84
99
  "light": "#fdf9f2",
85
100
  "dark": "#0c0a09",
86
101
  "description": "Inverse text — for contrasting backgrounds"
102
+ },
103
+ "on-scrim": {
104
+ "light": "#f7f7f6",
105
+ "dark": "#f7f7f6",
106
+ "description": "Text and controls on the figure viewer scrim (stone-50). Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Held to 7:1 over both scrims and both page modes by tools/contrast-check.mjs."
87
107
  }
88
108
  },
89
109
  "interactive": {
@@ -107,6 +127,28 @@
107
127
  "dark": "#d6d3d1",
108
128
  "description": "Focus indicators — mirrors interactive.primary"
109
129
  }
130
+ },
131
+ "state": {
132
+ "success": {
133
+ "light": "#007a58",
134
+ "dark": "#009E73",
135
+ "description": "State: success. Okabe-Ito bluish-green, darkened in light mode for text: 4.56:1 on page and 4.99:1 on card (dark 5.40 / 5.11). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
136
+ },
137
+ "warning": {
138
+ "light": "#906306",
139
+ "dark": "#E69F00",
140
+ "description": "State: warning. Okabe-Ito orange, darkened in light mode to an amber that holds text contrast: 4.51:1 on page and 4.93:1 on card (dark 8.20 / 7.76). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
141
+ },
142
+ "error": {
143
+ "light": "#a4262c",
144
+ "dark": "#ef5350",
145
+ "description": "State: error. Red rather than Okabe-Ito vermillion: darkened vermillion collapses into the amber warning under deuteranopia (ΔE 2.0). 6.2:1 on page in light mode (dark 5.30 / 5.02). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
146
+ },
147
+ "info": {
148
+ "light": "#292524",
149
+ "dark": "#d6d3d1",
150
+ "description": "State: info. The neutral accent (ink-700 / ink-200), since css-neutral ships no brand accent. 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
151
+ }
110
152
  }
111
153
  }
112
154
  }
package/dist/tokens.css CHANGED
@@ -25,10 +25,10 @@
25
25
  --color-palette-paper-300: #f5e8cf;
26
26
  --color-palette-paper-400: #edd9b3;
27
27
  --color-palette-paper-500: #e0c088;
28
- --color-functional-success: #27AE60;
29
- --color-functional-warning: #F39C12;
30
- --color-functional-error: #E74C3C;
31
- --color-functional-info: #3498DB;
28
+ --color-functional-success: #009E73;
29
+ --color-functional-warning: #E69F00;
30
+ --color-functional-error: #ef5350;
31
+ --color-functional-info: #d6d3d1;
32
32
  --transition-quick: 0.15s ease;
33
33
  --transition-standard: 0.25s ease-in-out;
34
34
  --transition-smooth: 0.35s ease;
@@ -111,23 +111,31 @@
111
111
  --color-surface-page: #ededeb;
112
112
  --color-surface-page-scrolled: #ededeb;
113
113
  --color-surface-elevated: #f7f7f6;
114
- --color-surface-sunken: #faf2e3;
114
+ --color-surface-sunken: #f7f7f6;
115
115
  --color-surface-navbar: #ededeb;
116
116
  --color-surface-navbar-scrolled: #ededeb;
117
- --color-surface-code: #faf2e3;
117
+ --color-surface-code: #f7f7f6;
118
+ --color-surface-scrim: rgba(20, 20, 16, 0.85);
119
+ --color-surface-scrim-solid: rgba(20, 20, 16, 0.92);
118
120
  --color-border-subtle: rgba(12, 10, 9, 0.45);
119
121
  --color-border-moderate: rgba(12, 10, 9, 0.60);
120
122
  --color-border-strong: rgba(12, 10, 9, 0.75);
121
123
  --color-border-card: rgba(12, 10, 9, 0.60);
122
124
  --color-border-code: #d6d3d1;
125
+ --color-border-on-scrim-focus: #f7f7f6;
123
126
  --color-content-primary: #14140f;
124
127
  --color-content-secondary: #424240;
125
128
  --color-content-muted: #5e5e5c;
126
129
  --color-content-inverse: #fdf9f2;
130
+ --color-content-on-scrim: #f7f7f6;
127
131
  --color-interactive-primary: #292524;
128
132
  --color-interactive-hover: #1c1917;
129
133
  --color-interactive-accent: #292524;
130
134
  --color-interactive-focus: #292524;
135
+ --color-state-success: #007a58;
136
+ --color-state-warning: #906306;
137
+ --color-state-error: #a4262c;
138
+ --color-state-info: #292524;
131
139
  --contrast-high: rgb(20, 20, 16);
132
140
  --contrast-readable: rgb(20, 20, 16);
133
141
  --contrast-medium: #7c7c7c;
@@ -135,6 +143,8 @@
135
143
  --shadow-subtle: 0 1px 2px 0 rgb(20 20 16 / 0.05);
136
144
  --shadow-moderate: 0 4px 6px -1px rgb(20 20 16 / 0.1);
137
145
  --shadow-prominent: 0 10px 15px -3px rgb(20 20 16 / 0.1);
146
+ --shadow-figure-plate-hover: 0 10px 15px -3px rgb(20 20 16 / 0.1);
147
+ --shadow-figure-plate-active: 0 4px 6px -1px rgb(20 20 16 / 0.1);
138
148
  --border-subtle: rgba(20, 20, 16, 0.47);
139
149
  --border-moderate: rgba(20, 20, 16, 0.63);
140
150
  --border-focus: #3498DB;
@@ -155,19 +165,27 @@
155
165
  --color-surface-navbar: #141410;
156
166
  --color-surface-navbar-scrolled: #141410;
157
167
  --color-surface-code: #1c1917;
168
+ --color-surface-scrim: rgba(20, 20, 16, 0.85);
169
+ --color-surface-scrim-solid: rgba(20, 20, 16, 0.92);
158
170
  --color-border-subtle: rgba(253, 249, 242, 0.45);
159
171
  --color-border-moderate: rgba(253, 249, 242, 0.60);
160
172
  --color-border-strong: rgba(253, 249, 242, 0.75);
161
173
  --color-border-card: rgba(253, 249, 242, 0.60);
162
174
  --color-border-code: #292524;
175
+ --color-border-on-scrim-focus: #f7f7f6;
163
176
  --color-content-primary: #fdf9f2;
164
177
  --color-content-secondary: #a8a29e;
165
178
  --color-content-muted: #89827d;
166
179
  --color-content-inverse: #0c0a09;
180
+ --color-content-on-scrim: #f7f7f6;
167
181
  --color-interactive-primary: #d6d3d1;
168
182
  --color-interactive-hover: #a8a29e;
169
183
  --color-interactive-accent: #d6d3d1;
170
184
  --color-interactive-focus: #d6d3d1;
185
+ --color-state-success: #009E73;
186
+ --color-state-warning: #E69F00;
187
+ --color-state-error: #ef5350;
188
+ --color-state-info: #d6d3d1;
171
189
  --contrast-high: rgb(237, 237, 235);
172
190
  --contrast-readable: rgb(237, 237, 235);
173
191
  --contrast-medium: #83838f;
@@ -175,6 +193,8 @@
175
193
  --shadow-subtle: 0 1px 2px 0 rgb(237 237 235 / 0.03);
176
194
  --shadow-moderate: 0 4px 6px -1px rgb(237 237 235 / 0.05);
177
195
  --shadow-prominent: 0 10px 15px -3px rgb(237 237 235 / 0.4);
196
+ --shadow-figure-plate-hover: 0 4px 12px rgb(0 0 0 / 0.5);
197
+ --shadow-figure-plate-active: 0 2px 8px rgb(0 0 0 / 0.35);
178
198
  --border-subtle: rgba(237, 237, 235, 0.47);
179
199
  --border-moderate: rgba(237, 237, 235, 0.63);
180
200
  --border-focus: #4FC3F7;
@@ -196,19 +216,27 @@
196
216
  --color-surface-navbar: #141410;
197
217
  --color-surface-navbar-scrolled: #141410;
198
218
  --color-surface-code: #1c1917;
219
+ --color-surface-scrim: rgba(20, 20, 16, 0.85);
220
+ --color-surface-scrim-solid: rgba(20, 20, 16, 0.92);
199
221
  --color-border-subtle: rgba(253, 249, 242, 0.45);
200
222
  --color-border-moderate: rgba(253, 249, 242, 0.60);
201
223
  --color-border-strong: rgba(253, 249, 242, 0.75);
202
224
  --color-border-card: rgba(253, 249, 242, 0.60);
203
225
  --color-border-code: #292524;
226
+ --color-border-on-scrim-focus: #f7f7f6;
204
227
  --color-content-primary: #fdf9f2;
205
228
  --color-content-secondary: #a8a29e;
206
229
  --color-content-muted: #89827d;
207
230
  --color-content-inverse: #0c0a09;
231
+ --color-content-on-scrim: #f7f7f6;
208
232
  --color-interactive-primary: #d6d3d1;
209
233
  --color-interactive-hover: #a8a29e;
210
234
  --color-interactive-accent: #d6d3d1;
211
235
  --color-interactive-focus: #d6d3d1;
236
+ --color-state-success: #009E73;
237
+ --color-state-warning: #E69F00;
238
+ --color-state-error: #ef5350;
239
+ --color-state-info: #d6d3d1;
212
240
  --contrast-high: rgb(237, 237, 235);
213
241
  --contrast-readable: rgb(237, 237, 235);
214
242
  --contrast-medium: #83838f;
@@ -216,6 +244,8 @@
216
244
  --shadow-subtle: 0 1px 2px 0 rgb(237 237 235 / 0.03);
217
245
  --shadow-moderate: 0 4px 6px -1px rgb(237 237 235 / 0.05);
218
246
  --shadow-prominent: 0 10px 15px -3px rgb(237 237 235 / 0.4);
247
+ --shadow-figure-plate-hover: 0 4px 12px rgb(0 0 0 / 0.5);
248
+ --shadow-figure-plate-active: 0 2px 8px rgb(0 0 0 / 0.35);
219
249
  --border-subtle: rgba(237, 237, 235, 0.47);
220
250
  --border-moderate: rgba(237, 237, 235, 0.63);
221
251
  --border-focus: #4FC3F7;
@@ -27,11 +27,11 @@
27
27
  },
28
28
  "sunken": {
29
29
  "$value": {
30
- "light": "#faf2e3",
30
+ "light": "#f7f7f6",
31
31
  "dark": "#0c0a09"
32
32
  },
33
33
  "$type": "color",
34
- "$description": "Input fields, code blocks — below page level (paper-200 light / ink-900 dark)"
34
+ "$description": "Input fields and insets. Light: the card colour, stone-50 (since 2026-11-02; it was the warm paper-200 #faf2e3). Dark: ink-900, below the page. Code blocks use surface.code."
35
35
  },
36
36
  "navbar": {
37
37
  "$value": {
@@ -51,11 +51,27 @@
51
51
  },
52
52
  "code": {
53
53
  "$value": {
54
- "light": "#faf2e3",
54
+ "light": "#f7f7f6",
55
55
  "dark": "#1c1917"
56
56
  },
57
57
  "$type": "color",
58
- "$description": "Code block and inline code background"
58
+ "$description": "Code block and inline code background: the card colour in both modes (2026-11-02; light mode was paper-200 #faf2e3)"
59
+ },
60
+ "scrim": {
61
+ "$value": {
62
+ "light": "rgba(20, 20, 16, 0.85)",
63
+ "dark": "rgba(20, 20, 16, 0.85)"
64
+ },
65
+ "$type": "color",
66
+ "$description": "Figure viewer backdrop. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Ink-900-ish at 0.85, drawn under a 3px blur; measured composited over the page, on-scrim text is 11.5:1 on the light page and 17.2:1 on the dark (gated by tools/contrast-check.mjs, 2026-11-03)."
67
+ },
68
+ "scrim-solid": {
69
+ "$value": {
70
+ "light": "rgba(20, 20, 16, 0.92)",
71
+ "dark": "rgba(20, 20, 16, 0.92)"
72
+ },
73
+ "$type": "color",
74
+ "$description": "Figure viewer backdrop where backdrop blur is unavailable (prefers-reduced-transparency, prefers-contrast: more and browsers without backdrop blur): the same ink at 0.92. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Gated by tools/contrast-check.mjs."
59
75
  }
60
76
  },
61
77
  "border": {
@@ -98,6 +114,14 @@
98
114
  },
99
115
  "$type": "color",
100
116
  "$description": "Code block border"
117
+ },
118
+ "on-scrim-focus": {
119
+ "$value": {
120
+ "light": "#f7f7f6",
121
+ "dark": "#f7f7f6"
122
+ },
123
+ "$type": "color",
124
+ "$description": "Focus ring on the figure viewer scrim. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). The neutral identity uses ink, not slate, for accents (the state-colours ADR), so the ring is on-scrim stone-50. Held to 3:1 (WCAG 1.4.11) over both scrims and both page modes by tools/contrast-check.mjs."
101
125
  }
102
126
  },
103
127
  "content": {
@@ -132,6 +156,14 @@
132
156
  },
133
157
  "$type": "color",
134
158
  "$description": "Inverse text — for contrasting backgrounds"
159
+ },
160
+ "on-scrim": {
161
+ "$value": {
162
+ "light": "#f7f7f6",
163
+ "dark": "#f7f7f6"
164
+ },
165
+ "$type": "color",
166
+ "$description": "Text and controls on the figure viewer scrim (stone-50). Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Held to 7:1 over both scrims and both page modes by tools/contrast-check.mjs."
135
167
  }
136
168
  },
137
169
  "interactive": {
@@ -167,6 +199,40 @@
167
199
  "$type": "color",
168
200
  "$description": "Focus indicators — mirrors interactive.primary"
169
201
  }
202
+ },
203
+ "state": {
204
+ "success": {
205
+ "$value": {
206
+ "light": "#007a58",
207
+ "dark": "#009E73"
208
+ },
209
+ "$type": "color",
210
+ "$description": "State: success. Okabe-Ito bluish-green, darkened in light mode for text: 4.56:1 on page and 4.99:1 on card (dark 5.40 / 5.11). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
211
+ },
212
+ "warning": {
213
+ "$value": {
214
+ "light": "#906306",
215
+ "dark": "#E69F00"
216
+ },
217
+ "$type": "color",
218
+ "$description": "State: warning. Okabe-Ito orange, darkened in light mode to an amber that holds text contrast: 4.51:1 on page and 4.93:1 on card (dark 8.20 / 7.76). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
219
+ },
220
+ "error": {
221
+ "$value": {
222
+ "light": "#a4262c",
223
+ "dark": "#ef5350"
224
+ },
225
+ "$type": "color",
226
+ "$description": "State: error. Red rather than Okabe-Ito vermillion: darkened vermillion collapses into the amber warning under deuteranopia (ΔE 2.0). 6.2:1 on page in light mode (dark 5.30 / 5.02). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
227
+ },
228
+ "info": {
229
+ "$value": {
230
+ "light": "#292524",
231
+ "dark": "#d6d3d1"
232
+ },
233
+ "$type": "color",
234
+ "$description": "State: info. The neutral accent (ink-700 / ink-200), since css-neutral ships no brand accent. 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
235
+ }
170
236
  }
171
237
  },
172
238
  "spacing": {
package/dist/tokens.scss CHANGED
@@ -25,10 +25,10 @@
25
25
  --color-palette-paper-300: #f5e8cf;
26
26
  --color-palette-paper-400: #edd9b3;
27
27
  --color-palette-paper-500: #e0c088;
28
- --color-functional-success: #27AE60;
29
- --color-functional-warning: #F39C12;
30
- --color-functional-error: #E74C3C;
31
- --color-functional-info: #3498DB;
28
+ --color-functional-success: #009E73;
29
+ --color-functional-warning: #E69F00;
30
+ --color-functional-error: #ef5350;
31
+ --color-functional-info: #d6d3d1;
32
32
  --transition-quick: 0.15s ease;
33
33
  --transition-standard: 0.25s ease-in-out;
34
34
  --transition-smooth: 0.35s ease;
@@ -111,23 +111,31 @@
111
111
  --color-surface-page: #ededeb;
112
112
  --color-surface-page-scrolled: #ededeb;
113
113
  --color-surface-elevated: #f7f7f6;
114
- --color-surface-sunken: #faf2e3;
114
+ --color-surface-sunken: #f7f7f6;
115
115
  --color-surface-navbar: #ededeb;
116
116
  --color-surface-navbar-scrolled: #ededeb;
117
- --color-surface-code: #faf2e3;
117
+ --color-surface-code: #f7f7f6;
118
+ --color-surface-scrim: rgba(20, 20, 16, 0.85);
119
+ --color-surface-scrim-solid: rgba(20, 20, 16, 0.92);
118
120
  --color-border-subtle: rgba(12, 10, 9, 0.45);
119
121
  --color-border-moderate: rgba(12, 10, 9, 0.60);
120
122
  --color-border-strong: rgba(12, 10, 9, 0.75);
121
123
  --color-border-card: rgba(12, 10, 9, 0.60);
122
124
  --color-border-code: #d6d3d1;
125
+ --color-border-on-scrim-focus: #f7f7f6;
123
126
  --color-content-primary: #14140f;
124
127
  --color-content-secondary: #424240;
125
128
  --color-content-muted: #5e5e5c;
126
129
  --color-content-inverse: #fdf9f2;
130
+ --color-content-on-scrim: #f7f7f6;
127
131
  --color-interactive-primary: #292524;
128
132
  --color-interactive-hover: #1c1917;
129
133
  --color-interactive-accent: #292524;
130
134
  --color-interactive-focus: #292524;
135
+ --color-state-success: #007a58;
136
+ --color-state-warning: #906306;
137
+ --color-state-error: #a4262c;
138
+ --color-state-info: #292524;
131
139
  --contrast-high: rgb(20, 20, 16);
132
140
  --contrast-readable: rgb(20, 20, 16);
133
141
  --contrast-medium: #7c7c7c;
@@ -135,6 +143,8 @@
135
143
  --shadow-subtle: 0 1px 2px 0 rgb(20 20 16 / 0.05);
136
144
  --shadow-moderate: 0 4px 6px -1px rgb(20 20 16 / 0.1);
137
145
  --shadow-prominent: 0 10px 15px -3px rgb(20 20 16 / 0.1);
146
+ --shadow-figure-plate-hover: 0 10px 15px -3px rgb(20 20 16 / 0.1);
147
+ --shadow-figure-plate-active: 0 4px 6px -1px rgb(20 20 16 / 0.1);
138
148
  --border-subtle: rgba(20, 20, 16, 0.47);
139
149
  --border-moderate: rgba(20, 20, 16, 0.63);
140
150
  --border-focus: #3498DB;
@@ -155,19 +165,27 @@
155
165
  --color-surface-navbar: #141410;
156
166
  --color-surface-navbar-scrolled: #141410;
157
167
  --color-surface-code: #1c1917;
168
+ --color-surface-scrim: rgba(20, 20, 16, 0.85);
169
+ --color-surface-scrim-solid: rgba(20, 20, 16, 0.92);
158
170
  --color-border-subtle: rgba(253, 249, 242, 0.45);
159
171
  --color-border-moderate: rgba(253, 249, 242, 0.60);
160
172
  --color-border-strong: rgba(253, 249, 242, 0.75);
161
173
  --color-border-card: rgba(253, 249, 242, 0.60);
162
174
  --color-border-code: #292524;
175
+ --color-border-on-scrim-focus: #f7f7f6;
163
176
  --color-content-primary: #fdf9f2;
164
177
  --color-content-secondary: #a8a29e;
165
178
  --color-content-muted: #89827d;
166
179
  --color-content-inverse: #0c0a09;
180
+ --color-content-on-scrim: #f7f7f6;
167
181
  --color-interactive-primary: #d6d3d1;
168
182
  --color-interactive-hover: #a8a29e;
169
183
  --color-interactive-accent: #d6d3d1;
170
184
  --color-interactive-focus: #d6d3d1;
185
+ --color-state-success: #009E73;
186
+ --color-state-warning: #E69F00;
187
+ --color-state-error: #ef5350;
188
+ --color-state-info: #d6d3d1;
171
189
  --contrast-high: rgb(237, 237, 235);
172
190
  --contrast-readable: rgb(237, 237, 235);
173
191
  --contrast-medium: #83838f;
@@ -175,6 +193,8 @@
175
193
  --shadow-subtle: 0 1px 2px 0 rgb(237 237 235 / 0.03);
176
194
  --shadow-moderate: 0 4px 6px -1px rgb(237 237 235 / 0.05);
177
195
  --shadow-prominent: 0 10px 15px -3px rgb(237 237 235 / 0.4);
196
+ --shadow-figure-plate-hover: 0 4px 12px rgb(0 0 0 / 0.5);
197
+ --shadow-figure-plate-active: 0 2px 8px rgb(0 0 0 / 0.35);
178
198
  --border-subtle: rgba(237, 237, 235, 0.47);
179
199
  --border-moderate: rgba(237, 237, 235, 0.63);
180
200
  --border-focus: #4FC3F7;
@@ -196,19 +216,27 @@
196
216
  --color-surface-navbar: #141410;
197
217
  --color-surface-navbar-scrolled: #141410;
198
218
  --color-surface-code: #1c1917;
219
+ --color-surface-scrim: rgba(20, 20, 16, 0.85);
220
+ --color-surface-scrim-solid: rgba(20, 20, 16, 0.92);
199
221
  --color-border-subtle: rgba(253, 249, 242, 0.45);
200
222
  --color-border-moderate: rgba(253, 249, 242, 0.60);
201
223
  --color-border-strong: rgba(253, 249, 242, 0.75);
202
224
  --color-border-card: rgba(253, 249, 242, 0.60);
203
225
  --color-border-code: #292524;
226
+ --color-border-on-scrim-focus: #f7f7f6;
204
227
  --color-content-primary: #fdf9f2;
205
228
  --color-content-secondary: #a8a29e;
206
229
  --color-content-muted: #89827d;
207
230
  --color-content-inverse: #0c0a09;
231
+ --color-content-on-scrim: #f7f7f6;
208
232
  --color-interactive-primary: #d6d3d1;
209
233
  --color-interactive-hover: #a8a29e;
210
234
  --color-interactive-accent: #d6d3d1;
211
235
  --color-interactive-focus: #d6d3d1;
236
+ --color-state-success: #009E73;
237
+ --color-state-warning: #E69F00;
238
+ --color-state-error: #ef5350;
239
+ --color-state-info: #d6d3d1;
212
240
  --contrast-high: rgb(237, 237, 235);
213
241
  --contrast-readable: rgb(237, 237, 235);
214
242
  --contrast-medium: #83838f;
@@ -216,6 +244,8 @@
216
244
  --shadow-subtle: 0 1px 2px 0 rgb(237 237 235 / 0.03);
217
245
  --shadow-moderate: 0 4px 6px -1px rgb(237 237 235 / 0.05);
218
246
  --shadow-prominent: 0 10px 15px -3px rgb(237 237 235 / 0.4);
247
+ --shadow-figure-plate-hover: 0 4px 12px rgb(0 0 0 / 0.5);
248
+ --shadow-figure-plate-active: 0 2px 8px rgb(0 0 0 / 0.35);
219
249
  --border-subtle: rgba(237, 237, 235, 0.47);
220
250
  --border-moderate: rgba(237, 237, 235, 0.63);
221
251
  --border-focus: #4FC3F7;
@@ -15,7 +15,7 @@
15
15
  "type": "color"
16
16
  },
17
17
  "sunken": {
18
- "value": "#faf2e3",
18
+ "value": "#f7f7f6",
19
19
  "type": "color"
20
20
  },
21
21
  "navbar": {
@@ -27,7 +27,15 @@
27
27
  "type": "color"
28
28
  },
29
29
  "code": {
30
- "value": "#faf2e3",
30
+ "value": "#f7f7f6",
31
+ "type": "color"
32
+ },
33
+ "scrim": {
34
+ "value": "rgba(20, 20, 16, 0.85)",
35
+ "type": "color"
36
+ },
37
+ "scrim-solid": {
38
+ "value": "rgba(20, 20, 16, 0.92)",
31
39
  "type": "color"
32
40
  }
33
41
  },
@@ -51,6 +59,10 @@
51
59
  "code": {
52
60
  "value": "#d6d3d1",
53
61
  "type": "color"
62
+ },
63
+ "on-scrim-focus": {
64
+ "value": "#f7f7f6",
65
+ "type": "color"
54
66
  }
55
67
  },
56
68
  "content": {
@@ -69,6 +81,10 @@
69
81
  "inverse": {
70
82
  "value": "#fdf9f2",
71
83
  "type": "color"
84
+ },
85
+ "on-scrim": {
86
+ "value": "#f7f7f6",
87
+ "type": "color"
72
88
  }
73
89
  },
74
90
  "interactive": {
@@ -89,6 +105,24 @@
89
105
  "type": "color"
90
106
  }
91
107
  },
108
+ "state": {
109
+ "success": {
110
+ "value": "#007a58",
111
+ "type": "color"
112
+ },
113
+ "warning": {
114
+ "value": "#906306",
115
+ "type": "color"
116
+ },
117
+ "error": {
118
+ "value": "#a4262c",
119
+ "type": "color"
120
+ },
121
+ "info": {
122
+ "value": "#292524",
123
+ "type": "color"
124
+ }
125
+ },
92
126
  "dataviz": {
93
127
  "okabe-ito": {
94
128
  "orange": {
@@ -501,6 +535,14 @@
501
535
  "code": {
502
536
  "value": "#1c1917",
503
537
  "type": "color"
538
+ },
539
+ "scrim": {
540
+ "value": "rgba(20, 20, 16, 0.85)",
541
+ "type": "color"
542
+ },
543
+ "scrim-solid": {
544
+ "value": "rgba(20, 20, 16, 0.92)",
545
+ "type": "color"
504
546
  }
505
547
  },
506
548
  "border": {
@@ -523,6 +565,10 @@
523
565
  "code": {
524
566
  "value": "#292524",
525
567
  "type": "color"
568
+ },
569
+ "on-scrim-focus": {
570
+ "value": "#f7f7f6",
571
+ "type": "color"
526
572
  }
527
573
  },
528
574
  "content": {
@@ -541,6 +587,10 @@
541
587
  "inverse": {
542
588
  "value": "#0c0a09",
543
589
  "type": "color"
590
+ },
591
+ "on-scrim": {
592
+ "value": "#f7f7f6",
593
+ "type": "color"
544
594
  }
545
595
  },
546
596
  "interactive": {
@@ -561,6 +611,24 @@
561
611
  "type": "color"
562
612
  }
563
613
  },
614
+ "state": {
615
+ "success": {
616
+ "value": "#009E73",
617
+ "type": "color"
618
+ },
619
+ "warning": {
620
+ "value": "#E69F00",
621
+ "type": "color"
622
+ },
623
+ "error": {
624
+ "value": "#ef5350",
625
+ "type": "color"
626
+ },
627
+ "info": {
628
+ "value": "#d6d3d1",
629
+ "type": "color"
630
+ }
631
+ },
564
632
  "dataviz": {
565
633
  "okabe-ito": {
566
634
  "black": {
@@ -32,14 +32,14 @@
32
32
  "$description": "Cards, modals, dropdowns — one step above page (stone-50 / ink-800)"
33
33
  },
34
34
  "sunken": {
35
- "$value": "#faf2e3",
35
+ "$value": "#f7f7f6",
36
36
  "$type": "color",
37
37
  "$extensions": {
38
38
  "com.dataimago.theme": {
39
39
  "dark": "#0c0a09"
40
40
  }
41
41
  },
42
- "$description": "Input fields, code blocks — below page level (paper-200 light / ink-900 dark)"
42
+ "$description": "Input fields and insets. Light: the card colour, stone-50 (since 2026-11-02; it was the warm paper-200 #faf2e3). Dark: ink-900, below the page. Code blocks use surface.code."
43
43
  },
44
44
  "navbar": {
45
45
  "$value": "#ededeb",
@@ -62,14 +62,34 @@
62
62
  "$description": "Navbar when scrolled/shrunk — matches page-scrolled"
63
63
  },
64
64
  "code": {
65
- "$value": "#faf2e3",
65
+ "$value": "#f7f7f6",
66
66
  "$type": "color",
67
67
  "$extensions": {
68
68
  "com.dataimago.theme": {
69
69
  "dark": "#1c1917"
70
70
  }
71
71
  },
72
- "$description": "Code block and inline code background"
72
+ "$description": "Code block and inline code background: the card colour in both modes (2026-11-02; light mode was paper-200 #faf2e3)"
73
+ },
74
+ "scrim": {
75
+ "$value": "rgba(20, 20, 16, 0.85)",
76
+ "$type": "color",
77
+ "$extensions": {
78
+ "com.dataimago.theme": {
79
+ "dark": "rgba(20, 20, 16, 0.85)"
80
+ }
81
+ },
82
+ "$description": "Figure viewer backdrop. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Ink-900-ish at 0.85, drawn under a 3px blur; measured composited over the page, on-scrim text is 11.5:1 on the light page and 17.2:1 on the dark (gated by tools/contrast-check.mjs, 2026-11-03)."
83
+ },
84
+ "scrim-solid": {
85
+ "$value": "rgba(20, 20, 16, 0.92)",
86
+ "$type": "color",
87
+ "$extensions": {
88
+ "com.dataimago.theme": {
89
+ "dark": "rgba(20, 20, 16, 0.92)"
90
+ }
91
+ },
92
+ "$description": "Figure viewer backdrop where backdrop blur is unavailable (prefers-reduced-transparency, prefers-contrast: more and browsers without backdrop blur): the same ink at 0.92. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Gated by tools/contrast-check.mjs."
73
93
  }
74
94
  },
75
95
  "border": {
@@ -122,6 +142,16 @@
122
142
  }
123
143
  },
124
144
  "$description": "Code block border"
145
+ },
146
+ "on-scrim-focus": {
147
+ "$value": "#f7f7f6",
148
+ "$type": "color",
149
+ "$extensions": {
150
+ "com.dataimago.theme": {
151
+ "dark": "#f7f7f6"
152
+ }
153
+ },
154
+ "$description": "Focus ring on the figure viewer scrim. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). The neutral identity uses ink, not slate, for accents (the state-colours ADR), so the ring is on-scrim stone-50. Held to 3:1 (WCAG 1.4.11) over both scrims and both page modes by tools/contrast-check.mjs."
125
155
  }
126
156
  },
127
157
  "content": {
@@ -164,6 +194,16 @@
164
194
  }
165
195
  },
166
196
  "$description": "Inverse text — for contrasting backgrounds"
197
+ },
198
+ "on-scrim": {
199
+ "$value": "#f7f7f6",
200
+ "$type": "color",
201
+ "$extensions": {
202
+ "com.dataimago.theme": {
203
+ "dark": "#f7f7f6"
204
+ }
205
+ },
206
+ "$description": "Text and controls on the figure viewer scrim (stone-50). Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Held to 7:1 over both scrims and both page modes by tools/contrast-check.mjs."
167
207
  }
168
208
  },
169
209
  "interactive": {
@@ -208,6 +248,48 @@
208
248
  "$description": "Focus indicators — mirrors interactive.primary"
209
249
  }
210
250
  },
251
+ "state": {
252
+ "success": {
253
+ "$value": "#007a58",
254
+ "$type": "color",
255
+ "$extensions": {
256
+ "com.dataimago.theme": {
257
+ "dark": "#009E73"
258
+ }
259
+ },
260
+ "$description": "State: success. Okabe-Ito bluish-green, darkened in light mode for text: 4.56:1 on page and 4.99:1 on card (dark 5.40 / 5.11). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
261
+ },
262
+ "warning": {
263
+ "$value": "#906306",
264
+ "$type": "color",
265
+ "$extensions": {
266
+ "com.dataimago.theme": {
267
+ "dark": "#E69F00"
268
+ }
269
+ },
270
+ "$description": "State: warning. Okabe-Ito orange, darkened in light mode to an amber that holds text contrast: 4.51:1 on page and 4.93:1 on card (dark 8.20 / 7.76). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
271
+ },
272
+ "error": {
273
+ "$value": "#a4262c",
274
+ "$type": "color",
275
+ "$extensions": {
276
+ "com.dataimago.theme": {
277
+ "dark": "#ef5350"
278
+ }
279
+ },
280
+ "$description": "State: error. Red rather than Okabe-Ito vermillion: darkened vermillion collapses into the amber warning under deuteranopia (ΔE 2.0). 6.2:1 on page in light mode (dark 5.30 / 5.02). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
281
+ },
282
+ "info": {
283
+ "$value": "#292524",
284
+ "$type": "color",
285
+ "$extensions": {
286
+ "com.dataimago.theme": {
287
+ "dark": "#d6d3d1"
288
+ }
289
+ },
290
+ "$description": "State: info. The neutral accent (ink-700 / ink-200), since css-neutral ships no brand accent. 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
291
+ }
292
+ },
211
293
  "dataviz": {
212
294
  "okabe-ito": {
213
295
  "orange": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dataimago/tokens-neutral",
3
- "version": "0.1.0-alpha.16",
3
+ "version": "0.1.0-alpha.18",
4
4
  "description": "dataimago neutral-identity design tokens — Noto Sans throughout, neutral palette; sensible defaults for externally-owned consumers (Level-3 user apps, third-party Level-2 verticals). Non-identity tokens (spacing, radius, motion, effects, components) are read from @dataimago/tokens at build time so the two packages stay in lockstep.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/colors.json CHANGED
@@ -28,17 +28,17 @@
28
28
  "paper": {
29
29
  "50": { "value": "#fefdfb", "description": "Paper scale — lightest warm surface; elevated cards/modals when warm tint is desired" },
30
30
  "100": { "value": "#fdf9f2", "description": "Paper scale — warm page-background option" },
31
- "200": { "value": "#faf2e3", "description": "Paper scale — code-block and pull-quote background" },
31
+ "200": { "value": "#faf2e3", "description": "Paper scale — pull-quote background" },
32
32
  "300": { "value": "#f5e8cf", "description": "Paper scale — call-out / emphasised panel background" },
33
33
  "400": { "value": "#edd9b3", "description": "Paper scale — muted warm accent" },
34
34
  "500": { "value": "#e0c088", "description": "Paper scale — strong warm accent; wheat" }
35
35
  }
36
36
  },
37
37
  "functional": {
38
- "success": { "value": "#27AE60", "description": "Success states and positive actions" },
39
- "warning": { "value": "#F39C12", "description": "Warning states and caution" },
40
- "error": { "value": "#E74C3C", "description": "Error states and critical issues" },
41
- "info": { "value": "#3498DB", "description": "Informational content" }
38
+ "success": { "value": "#009E73", "description": "Success hue (Okabe-Ito bluish-green, 2026-11-02; was Flat-UI #27AE60). For text use the mode-aware color.state.success" },
39
+ "warning": { "value": "#E69F00", "description": "Warning hue (Okabe-Ito orange, 2026-11-02; was Flat-UI #F39C12). For text use the mode-aware color.state.warning" },
40
+ "error": { "value": "#ef5350", "description": "Error hue (red, 2026-11-02; was Flat-UI #E74C3C). For text use the mode-aware color.state.error" },
41
+ "info": { "value": "#d6d3d1", "description": "Info hue (the neutral accent, ink-200, 2026-11-02; was the house #3498DB, which css-neutral does not carry). For text use the mode-aware color.state.info" }
42
42
  }
43
43
  }
44
44
  }
@@ -17,9 +17,9 @@
17
17
  "description": "Cards, modals, dropdowns — one step above page (stone-50 / ink-800)"
18
18
  },
19
19
  "sunken": {
20
- "light": "#faf2e3",
20
+ "light": "#f7f7f6",
21
21
  "dark": "#0c0a09",
22
- "description": "Input fields, code blocks — below page level (paper-200 light / ink-900 dark)"
22
+ "description": "Input fields and insets. Light: the card colour, stone-50 (since 2026-11-02; it was the warm paper-200 #faf2e3). Dark: ink-900, below the page. Code blocks use surface.code."
23
23
  },
24
24
  "navbar": {
25
25
  "light": "#ededeb",
@@ -32,9 +32,19 @@
32
32
  "description": "Navbar when scrolled/shrunk — matches page-scrolled"
33
33
  },
34
34
  "code": {
35
- "light": "#faf2e3",
35
+ "light": "#f7f7f6",
36
36
  "dark": "#1c1917",
37
- "description": "Code block and inline code background"
37
+ "description": "Code block and inline code background: the card colour in both modes (2026-11-02; light mode was paper-200 #faf2e3)"
38
+ },
39
+ "scrim": {
40
+ "light": "rgba(20, 20, 16, 0.85)",
41
+ "dark": "rgba(20, 20, 16, 0.85)",
42
+ "description": "Figure viewer backdrop. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Ink-900-ish at 0.85, drawn under a 3px blur; measured composited over the page, on-scrim text is 11.5:1 on the light page and 17.2:1 on the dark (gated by tools/contrast-check.mjs, 2026-11-03)."
43
+ },
44
+ "scrim-solid": {
45
+ "light": "rgba(20, 20, 16, 0.92)",
46
+ "dark": "rgba(20, 20, 16, 0.92)",
47
+ "description": "Figure viewer backdrop where backdrop blur is unavailable (prefers-reduced-transparency, prefers-contrast: more and browsers without backdrop blur): the same ink at 0.92. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Gated by tools/contrast-check.mjs."
38
48
  }
39
49
  },
40
50
  "border": {
@@ -42,13 +52,23 @@
42
52
  "moderate": { "light": "rgba(12, 10, 9, 0.60)", "dark": "rgba(253, 249, 242, 0.60)", "description": "Moderate borders — defined boundaries" },
43
53
  "strong": { "light": "rgba(12, 10, 9, 0.75)", "dark": "rgba(253, 249, 242, 0.75)", "description": "Strong borders — prominent separation" },
44
54
  "card": { "light": "rgba(12, 10, 9, 0.60)", "dark": "rgba(253, 249, 242, 0.60)", "description": "Card border color with transparency for subtle definition" },
45
- "code": { "light": "#d6d3d1", "dark": "#292524", "description": "Code block border" }
55
+ "code": { "light": "#d6d3d1", "dark": "#292524", "description": "Code block border" },
56
+ "on-scrim-focus": {
57
+ "light": "#f7f7f6",
58
+ "dark": "#f7f7f6",
59
+ "description": "Focus ring on the figure viewer scrim. Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). The neutral identity uses ink, not slate, for accents (the state-colours ADR), so the ring is on-scrim stone-50. Held to 3:1 (WCAG 1.4.11) over both scrims and both page modes by tools/contrast-check.mjs."
60
+ }
46
61
  },
47
62
  "content": {
48
63
  "primary": { "light": "#14140f", "dark": "#fdf9f2", "description": "Primary text — stone-900 on stone-100 (light) / paper-100 on dark surface" },
49
64
  "secondary": { "light": "#424240", "dark": "#a8a29e", "description": "Secondary text — stone-700 (light; 8.6:1 on stone-100, 10.1:1 on white, AAA) / ink-300 (dark; 7.3:1 on the dark page)" },
50
65
  "muted": { "light": "#5e5e5c", "dark": "#89827d", "description": "Muted text — captions, meta info; stone-600 (light; 5.5:1 on stone-100) / #89827d (dark; 4.9:1 on the dark page), AA" },
51
- "inverse": { "light": "#fdf9f2", "dark": "#0c0a09", "description": "Inverse text — for contrasting backgrounds" }
66
+ "inverse": { "light": "#fdf9f2", "dark": "#0c0a09", "description": "Inverse text — for contrasting backgrounds" },
67
+ "on-scrim": {
68
+ "light": "#f7f7f6",
69
+ "dark": "#f7f7f6",
70
+ "description": "Text and controls on the figure viewer scrim (stone-50). Mode-invariant: the scrim is dark in both modes, so light and dark carry the same value (the color.border.figure-frame precedent). Held to 7:1 over both scrims and both page modes by tools/contrast-check.mjs."
71
+ }
52
72
  },
53
73
  "interactive": {
54
74
  "primary": {
@@ -71,6 +91,28 @@
71
91
  "dark": "#d6d3d1",
72
92
  "description": "Focus indicators — mirrors interactive.primary"
73
93
  }
94
+ },
95
+ "state": {
96
+ "success": {
97
+ "light": "#007a58",
98
+ "dark": "#009E73",
99
+ "description": "State: success. Okabe-Ito bluish-green, darkened in light mode for text: 4.56:1 on page and 4.99:1 on card (dark 5.40 / 5.11). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
100
+ },
101
+ "warning": {
102
+ "light": "#906306",
103
+ "dark": "#E69F00",
104
+ "description": "State: warning. Okabe-Ito orange, darkened in light mode to an amber that holds text contrast: 4.51:1 on page and 4.93:1 on card (dark 8.20 / 7.76). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
105
+ },
106
+ "error": {
107
+ "light": "#a4262c",
108
+ "dark": "#ef5350",
109
+ "description": "State: error. Red rather than Okabe-Ito vermillion: darkened vermillion collapses into the amber warning under deuteranopia (ΔE 2.0). 6.2:1 on page in light mode (dark 5.30 / 5.02). 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
110
+ },
111
+ "info": {
112
+ "light": "#292524",
113
+ "dark": "#d6d3d1",
114
+ "description": "State: info. The neutral accent (ink-700 / ink-200), since css-neutral ships no brand accent. 2026-11-02; replaces the Flat-UI functional colours as the semantic layer"
115
+ }
74
116
  }
75
117
  }
76
118
  }