@kontourai/survey 8.0.0 → 8.1.1

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.
@@ -1,7 +1,39 @@
1
+ /* Product themes. Each theme sets its brand (identity) and, beside it, the
2
+ action and focus roles. The roles hold their own values rather than aliasing
3
+ the brand, so a later brand override cannot break primary actions or focus.
4
+ Every scope that sets --k-action also sets --k-action-contrast: a theme
5
+ nested under another theme's scope would otherwise inherit that scope's text
6
+ color onto its own fill.
7
+
8
+ Every scope that sets --k-focus also redeclares --k-focus-ring, and every
9
+ scope that sets a status hue redeclares its soft fill: a var()-derived token
10
+ resolves where it is declared, so without this a scope below the root would
11
+ inherit the root's value (issue 78). check:tokens enforces both.
12
+
13
+ Each light block matches three placements of the theme class and
14
+ data-theme="light": on one element, the theme class below the light
15
+ attribute, and the light attribute below the theme class. The last is
16
+ wrapped in :where() so it weighs the same as the bare [data-theme="light"]
17
+ block in tokens.css (which it follows, so it wins there) and less than a
18
+ theme class sitting on the light element itself: a nested theme keeps its
19
+ own identity.
20
+
21
+ Scoping rule (ui#80, ui#84; DESIGN.md "Theme and mode scoping"): the
22
+ nearest data-theme picks the mode and the nearest theme class picks the
23
+ product. The :where(:not(...)) tails enforce "nearest" without changing a
24
+ selector's weight: the class-below-attribute form stops at a nearer
25
+ data-theme="dark", and the attribute-below-class form stops at a nearer
26
+ (or its own) other theme class. Weights are unchanged, so an override
27
+ declared later with these selectors still wins. */
28
+
1
29
  .theme-survey {
2
30
  --k-bg: #06080b;
3
31
  --k-brand: #5ce0c6;
4
- --k-text-faint: #6f8095;
32
+ --k-action: #5ce0c6;
33
+ --k-action-contrast: #06080b;
34
+ --k-focus: #5ce0c6;
35
+ --k-text-faint: #78889b;
36
+ --k-focus-ring: var(--k-focus);
5
37
  }
6
38
 
7
39
  .theme-console {
@@ -13,6 +45,9 @@
13
45
  --k-radius-overlay: 0;
14
46
  --k-brand: #c9ff4a;
15
47
  --k-brand-contrast: #11120f;
48
+ --k-action: #c9ff4a;
49
+ --k-action-contrast: #11120f;
50
+ --k-focus: #c9ff4a;
16
51
  --k-bg: #11120f;
17
52
  --k-panel: #191b16;
18
53
  --k-panel-raised: #20231e;
@@ -20,30 +55,81 @@
20
55
  --k-line-strong: #8ea36e;
21
56
  --k-text: #f2f0e8;
22
57
  --k-text-muted: #a6ab9c;
23
- --k-text-faint: #747a6c;
58
+ --k-text-faint: #858b7e;
24
59
  --k-positive: #a6d37b;
25
60
  --k-caution: #e8c15f;
26
61
  --k-negative: #ee776f;
27
62
  --k-active: #84d8c8;
63
+ --k-status-contrast: #11120f;
64
+ --k-focus-ring: var(--k-focus);
65
+ --k-positive-soft: color-mix(in oklab, var(--k-positive) 14%, transparent);
66
+ --k-caution-soft: color-mix(in oklab, var(--k-caution) 14%, transparent);
67
+ --k-negative-soft: color-mix(in oklab, var(--k-negative) 14%, transparent);
68
+ --k-active-soft: color-mix(in oklab, var(--k-active) 14%, transparent);
28
69
  }
29
70
 
71
+ /* Flow dark: the brand is the accent lightened (OKLCH hue within 0.3°, same chroma)
72
+ just enough to read as text at 4.5:1 on bg, panel and raised panel; the
73
+ action and focus keep the accent, which clears their 3:1 and dark-text
74
+ pairs. */
30
75
  .theme-flow {
31
- --k-brand: #2f88a6;
76
+ --k-brand: #3890ae;
77
+ --k-action: #2f88a6;
78
+ --k-action-contrast: #06080b;
79
+ --k-focus: #2f88a6;
80
+ --k-focus-ring: var(--k-focus);
32
81
  }
33
82
 
34
83
  .theme-surface {
35
84
  --k-brand: #14a37a;
85
+ --k-action: #14a37a;
86
+ --k-action-contrast: #06080b;
87
+ --k-focus: #14a37a;
88
+ --k-focus-ring: var(--k-focus);
36
89
  }
37
90
 
91
+ /* Station: the draft accent, adjusted per mode only where WCAG AA needs it.
92
+ Dark: the accent carries white text as a fill but is too dark to read as
93
+ text on the dark panel, so the focus ring is the accent lightened to clear
94
+ contrast, and the brand is lightened a little further (OKLCH hue within 0.1°) to
95
+ read as text at 4.5:1 on bg, panel and raised panel; the action keeps the
96
+ draft accent. */
97
+ .theme-station {
98
+ --k-brand: #966aff;
99
+ --k-action: #7c3aed;
100
+ --k-action-contrast: #ffffff;
101
+ --k-focus: #9364ff;
102
+ --k-focus-ring: var(--k-focus);
103
+ }
104
+
105
+ /* Survey light: the brand is the accent darkened (same OKLCH hue and chroma) just enough
106
+ to read as text at 4.5:1 on the light canvas; the action and focus keep the
107
+ accent. */
38
108
  [data-theme="light"].theme-survey,
39
- [data-theme="light"] .theme-survey {
40
- --k-brand: #16806f;
109
+ [data-theme="light"] .theme-survey:where(:not([data-theme="dark"], [data-theme="light"] [data-theme="dark"] *)),
110
+ :where(.theme-survey) [data-theme="light"]:where(:not(.theme-console, .theme-flow, .theme-surface, .theme-station, .theme-survey :is(.theme-console, .theme-flow, .theme-surface, .theme-station) *)) {
111
+ --k-bg: #f5f4ef;
112
+ --k-text-faint: #6a707b;
113
+ --k-brand: #107e6d;
114
+ --k-action: #16806f;
115
+ --k-action-contrast: #ffffff;
116
+ --k-focus: #16806f;
117
+ --k-focus-ring: var(--k-focus);
41
118
  }
42
119
 
120
+ /* Console light: the brand is the lime darkened (OKLCH hue within 0.1°) just enough
121
+ to read as text at 4.5:1 on bg, panel and raised panel, and it keeps white
122
+ brand-contrast text (5.1:1; dark text would be 3.7:1). The action and focus
123
+ keep the brighter lime with dark text. */
43
124
  [data-theme="light"].theme-console,
44
- [data-theme="light"] .theme-console {
45
- --k-brand: #6c9400;
125
+ [data-theme="light"] .theme-console:where(:not([data-theme="dark"], [data-theme="light"] [data-theme="dark"] *)),
126
+ :where(.theme-console) [data-theme="light"]:where(:not(.theme-survey, .theme-flow, .theme-surface, .theme-station, .theme-console :is(.theme-survey, .theme-flow, .theme-surface, .theme-station) *)) {
127
+ --k-brand: #577800;
46
128
  --k-brand-contrast: #ffffff;
129
+ --k-action: #6c9400;
130
+ --k-action-contrast: #11120f;
131
+ --k-focus: #6c9400;
132
+ --k-focus-ring: var(--k-focus);
47
133
  --k-bg: #f3f5eb;
48
134
  --k-panel: #fbfcf7;
49
135
  --k-panel-raised: #eef2e6;
@@ -51,19 +137,112 @@
51
137
  --k-line-strong: #8fa36f;
52
138
  --k-text: #1e2319;
53
139
  --k-text-muted: #596250;
54
- --k-text-faint: #77816d;
140
+ --k-text-faint: #68705f;
55
141
  --k-positive: #2f7d32;
56
142
  --k-caution: #8a6500;
57
143
  --k-negative: #b93a36;
58
144
  --k-active: #247f75;
145
+ --k-status-contrast: #ffffff;
146
+ --k-positive-soft: color-mix(in oklab, var(--k-positive) 14%, transparent);
147
+ --k-caution-soft: color-mix(in oklab, var(--k-caution) 14%, transparent);
148
+ --k-negative-soft: color-mix(in oklab, var(--k-negative) 14%, transparent);
149
+ --k-active-soft: color-mix(in oklab, var(--k-active) 14%, transparent);
59
150
  }
60
151
 
61
152
  [data-theme="light"].theme-flow,
62
- [data-theme="light"] .theme-flow {
153
+ [data-theme="light"] .theme-flow:where(:not([data-theme="dark"], [data-theme="light"] [data-theme="dark"] *)),
154
+ :where(.theme-flow) [data-theme="light"]:where(:not(.theme-survey, .theme-console, .theme-surface, .theme-station, .theme-flow :is(.theme-survey, .theme-console, .theme-surface, .theme-station) *)) {
63
155
  --k-brand: #1f6f88;
156
+ --k-action: #1f6f88;
157
+ --k-action-contrast: #ffffff;
158
+ --k-focus: #1f6f88;
159
+ --k-focus-ring: var(--k-focus);
64
160
  }
65
161
 
66
162
  [data-theme="light"].theme-surface,
67
- [data-theme="light"] .theme-surface {
163
+ [data-theme="light"] .theme-surface:where(:not([data-theme="dark"], [data-theme="light"] [data-theme="dark"] *)),
164
+ :where(.theme-surface) [data-theme="light"]:where(:not(.theme-survey, .theme-console, .theme-flow, .theme-station, .theme-surface :is(.theme-survey, .theme-console, .theme-flow, .theme-station) *)) {
68
165
  --k-brand: #0f6b52;
166
+ --k-action: #0f6b52;
167
+ --k-action-contrast: #ffffff;
168
+ --k-focus: #0f6b52;
169
+ --k-focus-ring: var(--k-focus);
170
+ }
171
+
172
+ [data-theme="light"].theme-station,
173
+ [data-theme="light"] .theme-station:where(:not([data-theme="dark"], [data-theme="light"] [data-theme="dark"] *)),
174
+ :where(.theme-station) [data-theme="light"]:where(:not(.theme-survey, .theme-console, .theme-flow, .theme-surface, .theme-station :is(.theme-survey, .theme-console, .theme-flow, .theme-surface) *)) {
175
+ --k-brand: #7c3aed;
176
+ --k-action: #7c3aed;
177
+ --k-action-contrast: #ffffff;
178
+ --k-focus: #7c3aed;
179
+ --k-focus-ring: var(--k-focus);
180
+ }
181
+
182
+
183
+ /* Dark islands (ui#80): a data-theme="dark" element below a light element
184
+ takes its nearest theme's dark values. tokens.css resets it to the default
185
+ dark contract first; each block below repeats its theme's mode-dependent
186
+ base values (check:contrast fails if one drifts) and, like the light
187
+ blocks, yields to a nearer theme class. Without a light ancestor nothing
188
+ needs resetting, so these blocks do not match and the element inherits. */
189
+
190
+ [data-theme="dark"]:where(.theme-survey *):where([data-theme="light"] *):where(:not(.theme-console, .theme-flow, .theme-surface, .theme-station, .theme-survey :is(.theme-console, .theme-flow, .theme-surface, .theme-station) *)) {
191
+ --k-bg: #06080b;
192
+ --k-brand: #5ce0c6;
193
+ --k-action: #5ce0c6;
194
+ --k-action-contrast: #06080b;
195
+ --k-focus: #5ce0c6;
196
+ --k-text-faint: #78889b;
197
+ --k-focus-ring: var(--k-focus);
198
+ }
199
+
200
+ [data-theme="dark"]:where(.theme-console *):where([data-theme="light"] *):where(:not(.theme-survey, .theme-flow, .theme-surface, .theme-station, .theme-console :is(.theme-survey, .theme-flow, .theme-surface, .theme-station) *)) {
201
+ --k-brand: #c9ff4a;
202
+ --k-brand-contrast: #11120f;
203
+ --k-action: #c9ff4a;
204
+ --k-action-contrast: #11120f;
205
+ --k-focus: #c9ff4a;
206
+ --k-bg: #11120f;
207
+ --k-panel: #191b16;
208
+ --k-panel-raised: #20231e;
209
+ --k-line: #3a4035;
210
+ --k-line-strong: #8ea36e;
211
+ --k-text: #f2f0e8;
212
+ --k-text-muted: #a6ab9c;
213
+ --k-text-faint: #858b7e;
214
+ --k-positive: #a6d37b;
215
+ --k-caution: #e8c15f;
216
+ --k-negative: #ee776f;
217
+ --k-active: #84d8c8;
218
+ --k-status-contrast: #11120f;
219
+ --k-focus-ring: var(--k-focus);
220
+ --k-positive-soft: color-mix(in oklab, var(--k-positive) 14%, transparent);
221
+ --k-caution-soft: color-mix(in oklab, var(--k-caution) 14%, transparent);
222
+ --k-negative-soft: color-mix(in oklab, var(--k-negative) 14%, transparent);
223
+ --k-active-soft: color-mix(in oklab, var(--k-active) 14%, transparent);
224
+ }
225
+
226
+ [data-theme="dark"]:where(.theme-flow *):where([data-theme="light"] *):where(:not(.theme-survey, .theme-console, .theme-surface, .theme-station, .theme-flow :is(.theme-survey, .theme-console, .theme-surface, .theme-station) *)) {
227
+ --k-brand: #3890ae;
228
+ --k-action: #2f88a6;
229
+ --k-action-contrast: #06080b;
230
+ --k-focus: #2f88a6;
231
+ --k-focus-ring: var(--k-focus);
232
+ }
233
+
234
+ [data-theme="dark"]:where(.theme-surface *):where([data-theme="light"] *):where(:not(.theme-survey, .theme-console, .theme-flow, .theme-station, .theme-surface :is(.theme-survey, .theme-console, .theme-flow, .theme-station) *)) {
235
+ --k-brand: #14a37a;
236
+ --k-action: #14a37a;
237
+ --k-action-contrast: #06080b;
238
+ --k-focus: #14a37a;
239
+ --k-focus-ring: var(--k-focus);
240
+ }
241
+
242
+ [data-theme="dark"]:where(.theme-station *):where([data-theme="light"] *):where(:not(.theme-survey, .theme-console, .theme-flow, .theme-surface, .theme-station :is(.theme-survey, .theme-console, .theme-flow, .theme-surface) *)) {
243
+ --k-brand: #966aff;
244
+ --k-action: #7c3aed;
245
+ --k-action-contrast: #ffffff;
246
+ --k-focus: #9364ff;
247
+ --k-focus-ring: var(--k-focus);
69
248
  }
@@ -19,12 +19,23 @@
19
19
  /* text */
20
20
  --k-text: #eef3f8;
21
21
  --k-text-muted: #aebccb;
22
- --k-text-faint: #72869b;
22
+ --k-text-faint: #75889d;
23
23
 
24
- /* brand */
24
+ /* brand — the product identity slot (eyebrows, accents, the progress sweep).
25
+ A product theme or a white-label deployment may override it; nothing
26
+ interactive reads it, so a brand that fails contrast cannot break a
27
+ button or a focus ring. */
25
28
  --k-brand: #5ce0c6;
26
29
  --k-brand-contrast: #06080b;
27
30
 
31
+ /* interaction roles — primary actions and keyboard focus. They hold their
32
+ own values instead of var(--k-brand): an alias would make every brand
33
+ override repaint buttons whether or not the new color can carry text.
34
+ Each theme and mode sets its action and focus beside its brand. */
35
+ --k-action: #5ce0c6;
36
+ --k-action-contrast: #06080b;
37
+ --k-focus: #5ce0c6;
38
+
28
39
  /* semantic status scale */
29
40
  --k-positive: #34d399;
30
41
  --k-caution: #f3b14b;
@@ -35,6 +46,51 @@
35
46
  --k-caution-soft: color-mix(in oklab, var(--k-caution) 14%, transparent);
36
47
  --k-negative-soft: color-mix(in oklab, var(--k-negative) 14%, transparent);
37
48
  --k-active-soft: color-mix(in oklab, var(--k-active) 14%, transparent);
49
+ /* Text on a filled status tone (tone badges, status-toned buttons). Its own
50
+ role so a white-label --k-brand-contrast cannot recolor status text. */
51
+ --k-status-contrast: #06080b;
52
+
53
+ /* trust states — Surface's claim statuses (TRUST_STATUSES, in Surface's
54
+ order), shown as presentation states: separate from the five status
55
+ tones and from the product accents. Each state has its own ink (label,
56
+ glyph, border), fill (the chip's own background, so its text pair does
57
+ not depend on the container) and line style (the non-color cue borders
58
+ and chart strokes reuse). Values are literal, never aliases: an alias
59
+ declared here resolves here, so a light or themed scope would inherit
60
+ this scope's hue (ui#78). */
61
+ --k-trust-unknown: #a2acb7;
62
+ --k-trust-unknown-fill: #252d39;
63
+ --k-trust-unknown-line: dotted;
64
+ --k-trust-proposed: #87b1fd;
65
+ --k-trust-proposed-fill: #222d42;
66
+ --k-trust-proposed-line: dashed;
67
+ --k-trust-assumed: #c4a4fe;
68
+ --k-trust-assumed-fill: #2a2c43;
69
+ --k-trust-assumed-line: dashed;
70
+ --k-trust-verified: #50d492;
71
+ --k-trust-verified-fill: #1a3233;
72
+ --k-trust-verified-line: solid;
73
+ --k-trust-stale: #f6b84d;
74
+ --k-trust-stale-fill: #312e2a;
75
+ --k-trust-stale-line: dotted;
76
+ --k-trust-disputed: #ec81c0;
77
+ --k-trust-disputed-fill: #30273a;
78
+ --k-trust-disputed-line: double;
79
+ --k-trust-superseded: #6bc8d3;
80
+ --k-trust-superseded-fill: #1e313d;
81
+ --k-trust-superseded-line: dotted;
82
+ --k-trust-rejected: #f66d67;
83
+ --k-trust-rejected-fill: #31242d;
84
+ --k-trust-rejected-line: solid;
85
+ --k-trust-revoked: #fdc2a2;
86
+ --k-trust-revoked-fill: #323036;
87
+ --k-trust-revoked-line: dotted;
88
+
89
+ /* trust basis — the line after a trust-state chip. Caveat facets
90
+ (Model-derived, not evaluated, cited only, contradicts, failed) are
91
+ underlined with a dashed line in the text's own color: a line-style cue,
92
+ never a hue. Names no color, so it inherits the rated muted text. */
93
+ --k-basis-caveat-decoration: underline dashed 1px;
38
94
 
39
95
  /* spacing */
40
96
  --k-space-1: 4px;
@@ -85,8 +141,11 @@
85
141
  --k-tracking-wide: 0.08em;
86
142
 
87
143
  /* focus — one ring contract so every interactive primitive (controls,
88
- buttons, links) shows the same keyboard-focus affordance. */
89
- --k-focus-ring: var(--k-brand);
144
+ buttons, links) shows the same keyboard-focus affordance. The ring color
145
+ is the --k-focus role; --k-focus-ring is kept as a compatibility alias for
146
+ consumer styles. Primitives read --k-focus directly, so an override of
147
+ --k-focus on any element reaches them. */
148
+ --k-focus-ring: var(--k-focus);
90
149
  --k-focus-ring-width: 2px;
91
150
  --k-focus-ring-offset: 2px;
92
151
 
@@ -102,6 +161,63 @@
102
161
  --k-z-toast: 1400;
103
162
  }
104
163
 
164
+ /* The dark contract again, for a data-theme="dark" element below a light
165
+ element (ui#80). It sets exactly the tokens the light block sets, with the
166
+ :root values; check:contrast fails if either drifts. Mode-independent
167
+ tokens (spacing, type, radii, fonts) are not reset, so a theme's own values
168
+ for them survive a mode switch. With no light ancestor there is nothing to
169
+ reset, so it does not match and a dark element simply inherits. */
170
+ [data-theme="dark"]:where([data-theme="light"] *) {
171
+ color-scheme: dark;
172
+ --k-bg: #0a0e13;
173
+ --k-panel: #111824;
174
+ --k-panel-raised: #16202d;
175
+ --k-line: rgba(150, 180, 210, 0.12);
176
+ --k-line-strong: rgba(150, 180, 210, 0.22);
177
+ --k-shadow: 0 26px 60px -42px rgba(0, 0, 0, 0.95);
178
+ --k-elevation-overlay:
179
+ 0 1px 2px rgba(0, 0, 0, 0.35),
180
+ 0 12px 32px rgba(0, 0, 0, 0.45),
181
+ 0 24px 56px rgba(0, 0, 0, 0.4);
182
+ --k-text: #eef3f8;
183
+ --k-text-muted: #aebccb;
184
+ --k-text-faint: #75889d;
185
+ --k-brand: #5ce0c6;
186
+ --k-brand-contrast: #06080b;
187
+ --k-action: #5ce0c6;
188
+ --k-action-contrast: #06080b;
189
+ --k-focus: #5ce0c6;
190
+ --k-positive: #34d399;
191
+ --k-caution: #f3b14b;
192
+ --k-negative: #ff6f6f;
193
+ --k-neutral: #6f8095;
194
+ --k-active: #7aa2ff;
195
+ --k-status-contrast: #06080b;
196
+ --k-trust-unknown: #a2acb7;
197
+ --k-trust-unknown-fill: #252d39;
198
+ --k-trust-proposed: #87b1fd;
199
+ --k-trust-proposed-fill: #222d42;
200
+ --k-trust-assumed: #c4a4fe;
201
+ --k-trust-assumed-fill: #2a2c43;
202
+ --k-trust-verified: #50d492;
203
+ --k-trust-verified-fill: #1a3233;
204
+ --k-trust-stale: #f6b84d;
205
+ --k-trust-stale-fill: #312e2a;
206
+ --k-trust-disputed: #ec81c0;
207
+ --k-trust-disputed-fill: #30273a;
208
+ --k-trust-superseded: #6bc8d3;
209
+ --k-trust-superseded-fill: #1e313d;
210
+ --k-trust-rejected: #f66d67;
211
+ --k-trust-rejected-fill: #31242d;
212
+ --k-trust-revoked: #fdc2a2;
213
+ --k-trust-revoked-fill: #323036;
214
+ --k-focus-ring: var(--k-focus);
215
+ --k-positive-soft: color-mix(in oklab, var(--k-positive) 14%, transparent);
216
+ --k-caution-soft: color-mix(in oklab, var(--k-caution) 14%, transparent);
217
+ --k-negative-soft: color-mix(in oklab, var(--k-negative) 14%, transparent);
218
+ --k-active-soft: color-mix(in oklab, var(--k-active) 14%, transparent);
219
+ }
220
+
105
221
  [data-theme="light"] {
106
222
  color-scheme: light;
107
223
  --k-bg: #f5f4ef;
@@ -116,16 +232,51 @@
116
232
  0 18px 48px rgba(0, 0, 0, 0.08);
117
233
  --k-text: #202124;
118
234
  --k-text-muted: #5b626b;
119
- --k-text-faint: #707782;
235
+ --k-text-faint: #6a707b;
120
236
  /* The dark-mode brand (#5ce0c6) is too light to carry white text or read as
121
237
  text on the light canvas (~1.6:1). Darken it for light mode: #0e7c64 holds
122
238
  the teal hue while clearing WCAG AA both as a button fill (white text,
123
239
  5.1:1) and as text on --k-bg (4.7:1). */
124
240
  --k-brand: #0e7c64;
125
241
  --k-brand-contrast: #ffffff;
242
+ --k-action: #0e7c64;
243
+ --k-action-contrast: #ffffff;
244
+ --k-focus: #0e7c64;
126
245
  --k-positive: #168257;
127
246
  --k-caution: #8a5a00;
128
247
  --k-negative: #c83b3b;
129
248
  --k-neutral: #5f6975;
130
249
  --k-active: #3f6fd6;
250
+ --k-status-contrast: #ffffff;
251
+
252
+ /* Light trust inks are dark enough that each label clears AA on its own
253
+ tinted fill; check:contrast rates every pair. */
254
+ --k-trust-unknown: #535c66;
255
+ --k-trust-unknown-fill: #eeeff0;
256
+ --k-trust-proposed: #2855ad;
257
+ --k-trust-proposed-fill: #eaeef7;
258
+ --k-trust-assumed: #6938a7;
259
+ --k-trust-assumed-fill: #f0ebf6;
260
+ --k-trust-verified: #006d42;
261
+ --k-trust-verified-fill: #e6f0ec;
262
+ --k-trust-stale: #855a00;
263
+ --k-trust-stale-fill: #f3efe6;
264
+ --k-trust-disputed: #94296f;
265
+ --k-trust-disputed-fill: #f4eaf1;
266
+ --k-trust-superseded: #016770;
267
+ --k-trust-superseded-fill: #e6f0f1;
268
+ --k-trust-rejected: #a12628;
269
+ --k-trust-rejected-fill: #f6e9ea;
270
+ --k-trust-revoked: #713408;
271
+ --k-trust-revoked-fill: #f1ebe6;
272
+
273
+ /* Tokens derived with var() resolve on the element that declares them and
274
+ are inherited as computed values, so each scope that changes an input
275
+ redeclares them. Without this, data-theme on a descendant of <html> would
276
+ keep the dark default's ring and soft fills. */
277
+ --k-focus-ring: var(--k-focus);
278
+ --k-positive-soft: color-mix(in oklab, var(--k-positive) 14%, transparent);
279
+ --k-caution-soft: color-mix(in oklab, var(--k-caution) 14%, transparent);
280
+ --k-negative-soft: color-mix(in oklab, var(--k-negative) 14%, transparent);
281
+ --k-active-soft: color-mix(in oklab, var(--k-active) 14%, transparent);
131
282
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontourai/survey",
3
- "version": "8.0.0",
3
+ "version": "8.1.1",
4
4
  "description": "Producer-side source, extraction, candidate, and review contracts for projecting verified claims into Surface.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -35,7 +35,11 @@
35
35
  "./example-data/public-field-review": "./dist/example-data/public-field-review.js",
36
36
  "./example-data/corrected-document-candidates": "./dist/example-data/corrected-document-candidates.js",
37
37
  "./example-data/public-directory-review-resource": "./dist/example-data/public-directory-review-resource.js",
38
- "./example-data/regulated-document-review-resource": "./dist/example-data/regulated-document-review-resource.js"
38
+ "./example-data/regulated-document-review-resource": "./dist/example-data/regulated-document-review-resource.js",
39
+ "./review-console": {
40
+ "types": "./dist/src/console/review-console-server.d.ts",
41
+ "default": "./dist/src/console/review-console-server.js"
42
+ }
39
43
  },
40
44
  "files": [
41
45
  "bin/",
@@ -53,7 +57,7 @@
53
57
  "test:package-smoke": "npm run build && node --test dist/tests/package-smoke/*.test.js",
54
58
  "test:browser": "playwright test",
55
59
  "test:browser:concurrent": "npm run build && node scripts/test-playwright-concurrency.mjs",
56
- "verify": "npm run check:content-boundary && npm run check:decisions && npm run typecheck && npm test && npm run test:package-smoke && npm run check:review-workbench-assets && npm run check:review-workbench && npm run test:browser && npm run test:browser:concurrent",
60
+ "verify": "npm run check:ui-token-drift && npm run check:content-boundary && npm run check:decisions && npm run typecheck && npm test && npm run test:package-smoke && npm run check:review-workbench && npm run test:browser && npm run test:browser:concurrent",
57
61
  "check:content-boundary": "node --test tests/content-boundary-script.test.cjs && node scripts/check-content-boundary.cjs",
58
62
  "check:decisions": "node scripts/check-decisions.cjs check",
59
63
  "check:guards": "node scripts/check-guards.mjs",
@@ -65,9 +69,11 @@
65
69
  "check:review-workbench:static": "npm run build && node scripts/check-review-workbench.cjs",
66
70
  "setup:repo-hooks": "node scripts/setup-repo-hooks.cjs",
67
71
  "validate:repo-hooks": "node scripts/validate-repo-hooks.cjs",
68
- "docs:build": "npm run build --silent && node scripts/docs-site/build.ts",
69
- "docs:check": "npm run docs:build && node scripts/docs-site/check-links.ts",
72
+ "docs:build": "npx -y github:kontourai/docs-kit#efe0bfe4ad247861ef661c907f6354d6167fa3be docs-kit build",
73
+ "docs:check": "npx -y github:kontourai/docs-kit#efe0bfe4ad247861ef661c907f6354d6167fa3be docs-kit check",
74
+ "docs:demo": "npm run build && node scripts/build-demo.mjs",
70
75
  "check:generated-css": "node scripts/copy-review-workbench-package-assets.cjs --check",
76
+ "check:ui-token-drift": "npm run check:generated-css && npm run check:review-workbench-assets",
71
77
  "workflow:sidecar": "flow-agents-workflow-sidecar",
72
78
  "workflow:validate-artifacts": "flow-agents-validate-artifacts"
73
79
  },
@@ -86,11 +92,10 @@
86
92
  },
87
93
  "devDependencies": {
88
94
  "@kontourai/flow-agents": "5.10.0",
89
- "@kontourai/traverse": "^0.25.0",
90
- "@kontourai/ui": "^1.1.0",
95
+ "@kontourai/traverse": "^3.0.1",
96
+ "@kontourai/ui": "^1.18.0",
91
97
  "@playwright/test": "^1.62.0",
92
98
  "@types/node": "^26.1.2",
93
- "marked": "^18.0.7",
94
99
  "typescript": "^7.0.2"
95
100
  },
96
101
  "engines": {