@visitwonders/assembly 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +8 -0
  2. package/declarations/overlay/drawer.d.ts +11 -0
  3. package/declarations/overlay/drawer.d.ts.map +1 -1
  4. package/dist/_app_/data/pagination-cluster.js +1 -0
  5. package/dist/_app_/data/pagination.js +1 -0
  6. package/dist/action/button.css +30 -19
  7. package/dist/data/index.js +1 -0
  8. package/dist/data/index.js.map +1 -1
  9. package/dist/data/pagination-cluster.js +106 -0
  10. package/dist/data/pagination-cluster.js.map +1 -0
  11. package/dist/data/pagination.css +216 -0
  12. package/dist/data/pagination.js +287 -0
  13. package/dist/data/pagination.js.map +1 -0
  14. package/dist/form/calendar.css +6 -6
  15. package/dist/form/checkbox.css +25 -24
  16. package/dist/form/date-range-picker.css +1 -1
  17. package/dist/form/input.css +16 -15
  18. package/dist/form/multi-combobox.css +2 -2
  19. package/dist/form/multi-select.css +2 -2
  20. package/dist/form/radio.css +19 -16
  21. package/dist/form/toggle.css +4 -2
  22. package/dist/overlay/drawer.js +13 -4
  23. package/dist/status/tag.css +2 -2
  24. package/dist/styles/semantic/colors.css +31 -5
  25. package/dist/styles/semantic/component.css +154 -0
  26. package/dist/styles/semantic/effects.css +9 -3
  27. package/dist/styles/semantic/typography.css +60 -0
  28. package/dist/styles/tokens.css +3 -0
  29. package/dist/styles.css +258 -8
  30. package/dist/typography/{heading-css-726c4c3109f2b741657733e1ba103c67.css → heading-css-eca8b0ae619f69fcbe9535f4700db421.css} +35 -3
  31. package/dist/typography/heading.js +34 -39
  32. package/dist/typography/{text-css-935f55e9cd74b06a5ce61330c4c79ef9.css → text-css-a4c06f76a813db6b613c4f3c22e6bb85.css} +23 -9
  33. package/dist/typography/text.js +1 -1
  34. package/package.json +6 -6
@@ -0,0 +1,287 @@
1
+ import "./pagination.css"
2
+ import Component from '@glimmer/component';
3
+ import { tracked } from '@glimmer/tracking';
4
+ import { on } from '@ember/modifier';
5
+ import { fn } from '@ember/helper';
6
+ import { modifier } from 'ember-modifier';
7
+ import { eq } from 'ember-truth-helpers';
8
+ import { ChevronsRight, ChevronsLeft, ChevronRight, ChevronLeft } from 'lucide';
9
+ import Button from '../action/button.js';
10
+ import Icon from '../media/icon.js';
11
+ import Form from '../form/form.js';
12
+ import { buildPageCluster } from './pagination-cluster.js';
13
+ import { precompileTemplate } from '@ember/template-compilation';
14
+ import { setComponentTemplate } from '@ember/component';
15
+ import { g, i } from 'decorator-transforms/runtime';
16
+
17
+ ;
18
+
19
+ // ============================================================================
20
+ // Component
21
+ // ============================================================================
22
+ class Pagination extends Component {
23
+ static {
24
+ g(this.prototype, "internalCurrentPage", [tracked], function () {
25
+ return 1;
26
+ });
27
+ }
28
+ #internalCurrentPage = (i(this, "internalCurrentPage"), void 0); // Uncontrolled-mode state. When the consumer passes `@currentPage`, this
29
+ // value is ignored; otherwise it tracks page locally.
30
+ // Tracked snapshot of the last seen totalPages so the refresh-clamp modifier
31
+ // can detect a shrink-under-the-user without scheduling its own runloop.
32
+ previousTotalPages = null;
33
+ // Jump-to-page tracked value. The consumer's @onChange fires only on form
34
+ // submit — keystrokes flow through this field, not through @onChange.
35
+ // Stored as number | null (null = empty) since `NumberField`'s onInput
36
+ // hands us `null` when the user clears the input. The template converts
37
+ // null → undefined to match `NumberField`'s @value signature.
38
+ static {
39
+ g(this.prototype, "jumpToValue", [tracked], function () {
40
+ return null;
41
+ });
42
+ }
43
+ #jumpToValue = (i(this, "jumpToValue"), void 0);
44
+ get jumpToFieldValue() {
45
+ return this.jumpToValue ?? undefined;
46
+ }
47
+ // ============================================================================
48
+ // Resolved args
49
+ // ============================================================================
50
+ get variant() {
51
+ return this.args.variant ?? 'default';
52
+ }
53
+ get siblingCount() {
54
+ return this.args.siblingCount ?? 1;
55
+ }
56
+ get boundaryCount() {
57
+ return this.args.boundaryCount ?? 1;
58
+ }
59
+ get itemName() {
60
+ return this.args.itemName ?? 'item';
61
+ }
62
+ get itemNamePlural() {
63
+ return this.args.itemNamePlural ?? 'items';
64
+ }
65
+ get isDisabled() {
66
+ return this.args.isDisabled ?? false;
67
+ }
68
+ get ariaLabel() {
69
+ return this.args['aria-label'] ?? 'Pagination';
70
+ }
71
+ // showSummary is variant-aware when not explicitly passed: numbered hides
72
+ // by default; default + compact show it.
73
+ get showSummary() {
74
+ if (this.args.showSummary !== undefined) return this.args.showSummary;
75
+ return this.variant !== 'numbered';
76
+ }
77
+ // First/last and jump-to-page are silently ignored on the compact variant —
78
+ // the variant exists for narrow toolbars; adding affordances defeats its
79
+ // reason for existing. Spec §Variants > compact.
80
+ get showFirstLast() {
81
+ if (this.variant === 'compact') return false;
82
+ return this.args.showFirstLast ?? false;
83
+ }
84
+ get showJumpTo() {
85
+ if (this.variant === 'compact') return false;
86
+ return this.args.showJumpTo ?? false;
87
+ }
88
+ // ============================================================================
89
+ // Mode inference (mirrors Table's isControlledSelection / isControlledSort).
90
+ // Note: unlike Table, @onChange fires in BOTH modes — Pagination models a
91
+ // navigation event. See spec §Behaviour > Callback contract.
92
+ // ============================================================================
93
+ get isControlled() {
94
+ return this.args.currentPage !== undefined;
95
+ }
96
+ get currentPage() {
97
+ return this.args.currentPage ?? this.internalCurrentPage;
98
+ }
99
+ // ============================================================================
100
+ // Derived counts
101
+ // ============================================================================
102
+ // Total pages = ceil(totalItems / pageSize). Defensive: pageSize must be > 0.
103
+ // If it isn't, fall back to 1 so we never render NaN/Infinity in the cluster.
104
+ get totalPages() {
105
+ const {
106
+ totalItems,
107
+ pageSize
108
+ } = this.args;
109
+ if (!pageSize || pageSize <= 0) return 1;
110
+ if (!totalItems || totalItems <= 0) return 1;
111
+ return Math.max(1, Math.ceil(totalItems / pageSize));
112
+ }
113
+ get startItem() {
114
+ if (this.args.totalItems <= 0) return 0;
115
+ return (this.currentPage - 1) * this.args.pageSize + 1;
116
+ }
117
+ get endItem() {
118
+ if (this.args.totalItems <= 0) return 0;
119
+ return Math.min(this.currentPage * this.args.pageSize, this.args.totalItems);
120
+ }
121
+ get resolvedItemName() {
122
+ return this.args.totalItems === 1 ? this.itemName : this.itemNamePlural;
123
+ }
124
+ get summaryContext() {
125
+ return {
126
+ startItem: this.startItem,
127
+ endItem: this.endItem,
128
+ totalItems: this.args.totalItems,
129
+ itemName: this.itemName,
130
+ itemNamePlural: this.itemNamePlural
131
+ };
132
+ }
133
+ // ============================================================================
134
+ // Page cluster (delegated to the pure helper)
135
+ //
136
+ // The template iterates `pageItems`, where each entry already exposes the
137
+ // fields both branches need. This keeps the template free of discriminated-
138
+ // union narrowing (which Glint doesn't follow through opaque helpers).
139
+ // ============================================================================
140
+ // Max items the cluster could ever render at the current sibling/boundary
141
+ // settings: 2 boundaries on each side + 2 ellipses + current + 2*siblings.
142
+ // Reserved as a min-width so the cluster footprint stays stable across
143
+ // page changes — otherwise prev/next shift horizontally as the user clicks
144
+ // through pages and the cluster shape mutates between renders.
145
+ get maxClusterItems() {
146
+ return 2 * this.boundaryCount + 2 * this.siblingCount + 3;
147
+ }
148
+ // Inline custom property consumed by the cluster's CSS to reserve a stable
149
+ // footprint. Runtime style prop, not a token — `--pagination-*` tokens are
150
+ // forbidden by docs/component-tokens.md, but inline runtime style props
151
+ // (Glimmer's standard pattern, mirrored from Toast/Grid/Tag) are fine.
152
+ get clusterStyle() {
153
+ return `--pagination-max-items: ${this.maxClusterItems};`;
154
+ }
155
+ get pageItems() {
156
+ return buildPageCluster({
157
+ totalPages: this.totalPages,
158
+ currentPage: this.currentPage,
159
+ siblingCount: this.siblingCount,
160
+ boundaryCount: this.boundaryCount
161
+ }).map(item => item.kind === 'page' ? {
162
+ kind: 'page',
163
+ key: `p-${item.page}`,
164
+ page: item.page,
165
+ isCurrent: item.page === this.currentPage
166
+ } : {
167
+ kind: 'ellipsis',
168
+ key: item.key,
169
+ page: 0,
170
+ isCurrent: false
171
+ });
172
+ }
173
+ // ============================================================================
174
+ // Boundary / disabled state
175
+ // ============================================================================
176
+ get isPrevDisabled() {
177
+ return this.isDisabled || this.currentPage <= 1;
178
+ }
179
+ get isNextDisabled() {
180
+ return this.isDisabled || this.currentPage >= this.totalPages;
181
+ }
182
+ // ============================================================================
183
+ // Navigation
184
+ // ============================================================================
185
+ // Single update path. Fires @onChange in both modes — the callback models a
186
+ // navigation event regardless of whether the parent stores currentPage.
187
+ // Spec §Behaviour > Callback contract.
188
+ goToPage(page) {
189
+ const clamped = Math.max(1, Math.min(this.totalPages, page));
190
+ if (!this.isControlled) {
191
+ this.internalCurrentPage = clamped;
192
+ }
193
+ this.args.onChange(clamped);
194
+ }
195
+ handlePageClick = page => {
196
+ if (this.isDisabled) return;
197
+ this.goToPage(page);
198
+ };
199
+ handlePrevClick = () => {
200
+ if (this.isPrevDisabled) return;
201
+ this.goToPage(this.currentPage - 1);
202
+ };
203
+ handleNextClick = () => {
204
+ if (this.isNextDisabled) return;
205
+ this.goToPage(this.currentPage + 1);
206
+ };
207
+ handleFirstClick = () => {
208
+ if (this.isPrevDisabled) return;
209
+ this.goToPage(1);
210
+ };
211
+ handleLastClick = () => {
212
+ if (this.isNextDisabled) return;
213
+ this.goToPage(this.totalPages);
214
+ };
215
+ // ============================================================================
216
+ // Jump-to-page form
217
+ //
218
+ // The user types into `NumberField`; we accumulate the value into
219
+ // `jumpToValue` via `onInput`. The consumer's `@onChange` is wired ONLY to
220
+ // form submit — typing 1, 12, 123 must not fire @onChange three times.
221
+ // ============================================================================
222
+ handleJumpToInput = value => {
223
+ this.jumpToValue = value;
224
+ };
225
+ handleJumpToSubmit = event => {
226
+ event.preventDefault();
227
+ const typed = this.jumpToValue;
228
+ // Empty / non-numeric / NaN submit: no-op. No @onChange fire, no clearing.
229
+ // The user can correct the typo without retyping from scratch.
230
+ if (typed === null || typed === undefined || Number.isNaN(typed)) return;
231
+ // Out-of-range typed values are clamped, not rejected. A typo of 999 on
232
+ // 17 pages becomes 17; a 0 or -3 becomes 1. Operator-friendly behaviour
233
+ // per spec §Jump-to-page input.
234
+ const clamped = Math.max(1, Math.min(this.totalPages, typed));
235
+ this.goToPage(clamped);
236
+ // Clear after a successful submit. The input is a transient jump shortcut,
237
+ // not a persistent record — the page-cluster already shows where the user
238
+ // is. Clearing also makes the next jump frictionless.
239
+ this.jumpToValue = null;
240
+ };
241
+ // ============================================================================
242
+ // Refresh-clamp modifier
243
+ //
244
+ // Fires when totalPages changes. If totalItems shrinks under the user and
245
+ // currentPage is now out of range, clamp to the new last page and fire
246
+ // @onChange once. Never re-fires on growth.
247
+ // ============================================================================
248
+ refreshClamp = modifier((_element, [totalPages, currentPage]) => {
249
+ const previous = this.previousTotalPages;
250
+ this.previousTotalPages = totalPages;
251
+ // First run: just record. We don't know yet whether totalItems is
252
+ // shrinking or growing, and the consumer's initial @currentPage is
253
+ // assumed to be valid.
254
+ if (previous === null) return;
255
+ // Only clamp on shrink-past-current. Growth never re-fires.
256
+ // The mutation is deferred to a microtask: the modifier reads
257
+ // `currentPage` (which in uncontrolled mode is `internalCurrentPage`)
258
+ // and `goToPage` writes it. Glimmer rejects same-computation read+write
259
+ // on a tracked field, so we punt the write to the next microtask.
260
+ if (totalPages < previous && currentPage > totalPages) {
261
+ void Promise.resolve().then(() => this.goToPage(totalPages));
262
+ }
263
+ });
264
+ // ============================================================================
265
+ // Template
266
+ // ============================================================================
267
+ static {
268
+ setComponentTemplate(precompileTemplate("<nav class=\"pagination_e7638bd11\" data-variant={{this.variant}} data-test-pagination aria-label={{this.ariaLabel}} {{this.refreshClamp this.totalPages this.currentPage}} ...attributes>\n {{#if (eq this.variant \"compact\")}}\n {{!-- ============================================================\n Compact: icon-only prev/next bracketing a single indicator.\n The aria-live region wraps the indicator (it IS the summary).\n @showFirstLast / @showJumpTo are silently ignored here.\n ============================================================ --}}\n {{#if (has-block \"prev\")}}\n <Button @variant=\"ghost\" @size=\"sm\" @isDisabled={{this.isPrevDisabled}} aria-label=\"Previous page\" data-test-pagination-prev {{on \"click\" this.handlePrevClick}}>\n {{yield to=\"prev\"}}\n </Button>\n {{else}}\n <Button @variant=\"ghost\" @size=\"sm\" @isDisabled={{this.isPrevDisabled}} aria-label=\"Previous page\" data-test-pagination-prev {{on \"click\" this.handlePrevClick}}>\n <:prefix><Icon @icon={{ChevronLeft}} @size=\"sm\" /></:prefix>\n </Button>\n {{/if}}\n\n <span class=\"indicator_e7638bd11\" aria-live=\"polite\" data-test-pagination-indicator>\n Page\n {{this.currentPage}}\n of\n {{this.totalPages}}\n </span>\n\n {{#if (has-block \"next\")}}\n <Button @variant=\"ghost\" @size=\"sm\" @isDisabled={{this.isNextDisabled}} aria-label=\"Next page\" data-test-pagination-next {{on \"click\" this.handleNextClick}}>\n {{yield to=\"next\"}}\n </Button>\n {{else}}\n <Button @variant=\"ghost\" @size=\"sm\" @isDisabled={{this.isNextDisabled}} aria-label=\"Next page\" data-test-pagination-next {{on \"click\" this.handleNextClick}}>\n <:prefix><Icon @icon={{ChevronRight}} @size=\"sm\" /></:prefix>\n </Button>\n {{/if}}\n {{else}}\n {{!-- ============================================================\n default and numbered: summary (optional) + cluster + prev/next,\n with optional first/last and jump-to-page affordances.\n ============================================================ --}}\n {{#if this.showSummary}}\n <div class=\"summary_e7638bd11\" aria-live=\"polite\" data-test-pagination-summary>\n {{#if (has-block \"summary\")}}\n {{yield this.summaryContext to=\"summary\"}}\n {{else}}\n {{this.startItem}}\u2013{{this.endItem}}\n of\n {{@totalItems}}\n {{this.resolvedItemName}}\n {{/if}}\n </div>\n {{/if}}\n\n <div class=\"controls_e7638bd11\">\n {{#if this.showFirstLast}}\n <Button @size=\"sm\" @isDisabled={{this.isPrevDisabled}} aria-label=\"First page\" data-test-pagination-first {{on \"click\" this.handleFirstClick}}>\n <:prefix><Icon @icon={{ChevronsLeft}} @size=\"sm\" /></:prefix>\n </Button>\n {{/if}}\n\n {{#if (has-block \"prev\")}}\n <Button @size=\"sm\" @isDisabled={{this.isPrevDisabled}} data-test-pagination-prev {{on \"click\" this.handlePrevClick}}>\n {{yield to=\"prev\"}}\n </Button>\n {{else}}\n <Button @size=\"sm\" @isDisabled={{this.isPrevDisabled}} data-test-pagination-prev {{on \"click\" this.handlePrevClick}}>\n <:prefix><Icon @icon={{ChevronLeft}} @size=\"sm\" /></:prefix>\n <:default>Prev</:default>\n </Button>\n {{/if}}\n\n <ol class=\"cluster_e7638bd11\" style={{this.clusterStyle}} data-test-pagination-cluster>\n {{#each this.pageItems key=\"key\" as |entry|}}\n {{#if (eq entry.kind \"page\")}}\n <li class=\"item_e7638bd11\">\n <Button @variant=\"ghost\" @size=\"sm\" @isDisabled={{this.isDisabled}} aria-current={{if entry.isCurrent \"page\"}} data-current={{if entry.isCurrent \"true\"}} data-test-pagination-page={{entry.page}} {{on \"click\" (fn this.handlePageClick entry.page)}}>\n {{entry.page}}\n </Button>\n </li>\n {{else}}\n <li class=\"ellipsis_e7638bd11\" aria-hidden=\"true\" data-test-pagination-ellipsis>\u2026</li>\n {{/if}}\n {{/each}}\n </ol>\n\n {{#if (has-block \"next\")}}\n <Button @size=\"sm\" @isDisabled={{this.isNextDisabled}} data-test-pagination-next {{on \"click\" this.handleNextClick}}>\n {{yield to=\"next\"}}\n </Button>\n {{else}}\n <Button @size=\"sm\" @isDisabled={{this.isNextDisabled}} data-test-pagination-next {{on \"click\" this.handleNextClick}}>\n <:default>Next</:default>\n <:suffix><Icon @icon={{ChevronRight}} @size=\"sm\" /></:suffix>\n </Button>\n {{/if}}\n\n {{#if this.showFirstLast}}\n <Button @size=\"sm\" @isDisabled={{this.isNextDisabled}} aria-label=\"Last page\" data-test-pagination-last {{on \"click\" this.handleLastClick}}>\n <:prefix><Icon @icon={{ChevronsRight}} @size=\"sm\" /></:prefix>\n </Button>\n {{/if}}\n\n {{#if this.showJumpTo}}\n {{!-- Form's @isDisabled is forwarded to every yielded child,\n so passing it here disables both the input and the submit\n Button without re-passing on each. Form does not introduce\n a separate <nav> landmark \u2014 it sits inside Pagination's. --}}\n <Form class=\"jump-to_e7638bd11\" @onSubmit={{this.handleJumpToSubmit}} @isDisabled={{this.isDisabled}} data-test-pagination-jump-form as |form|>\n <form.NumberField @label=\"Go to page\" @value={{this.jumpToFieldValue}} @onInput={{this.handleJumpToInput}} @min={{1}} @max={{this.totalPages}} @step={{1}} @showStepper={{false}} @inputMode=\"numeric\" data-test-pagination-jump-input />\n <form.Button @type=\"submit\" @size=\"sm\" data-test-pagination-jump-submit>\n Go\n </form.Button>\n </Form>\n {{/if}}\n </div>\n {{/if}}\n</nav>", {
269
+ strictMode: true,
270
+ scope: () => ({
271
+ eq,
272
+ Button,
273
+ on,
274
+ Icon,
275
+ ChevronLeft,
276
+ ChevronRight,
277
+ ChevronsLeft,
278
+ fn,
279
+ ChevronsRight,
280
+ Form
281
+ })
282
+ }), this);
283
+ }
284
+ }
285
+
286
+ export { Pagination as default };
287
+ //# sourceMappingURL=pagination.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -163,13 +163,13 @@
163
163
  transform: translateX(-50%);
164
164
  width: 0.25rem;
165
165
  height: 0.25rem;
166
- background-color: var(--color-bg-fill-accent);
166
+ background-color: var(--color-bg-control-checked);
167
167
  border-radius: 50%;
168
168
  }
169
169
 
170
170
  /* Selected state */
171
171
  .calendar-day_e7aa819da[data-selected="true"]:not([data-disabled="true"]) {
172
- background-color: var(--color-bg-fill-accent);
172
+ background-color: var(--color-bg-control-checked);
173
173
  color: var(--color-text-on-accent);
174
174
  }
175
175
 
@@ -183,7 +183,7 @@
183
183
  }
184
184
 
185
185
  .calendar-day_e7aa819da[data-outside="true"][data-selected="true"] {
186
- background-color: var(--color-bg-fill-accent);
186
+ background-color: var(--color-bg-control-checked);
187
187
  color: var(--color-text-on-accent);
188
188
  }
189
189
 
@@ -205,7 +205,7 @@
205
205
  .calendar-day_e7aa819da[data-in-range="true"]:not([data-disabled="true"]) {
206
206
  background-color: color-mix(
207
207
  in srgb,
208
- var(--color-bg-fill-accent) 15%,
208
+ var(--color-bg-control-checked) 15%,
209
209
  transparent
210
210
  );
211
211
  border-radius: 0;
@@ -213,14 +213,14 @@
213
213
 
214
214
  /* Range start */
215
215
  .calendar-day_e7aa819da[data-range-start="true"]:not([data-disabled="true"]) {
216
- background-color: var(--color-bg-fill-accent);
216
+ background-color: var(--color-bg-control-checked);
217
217
  color: var(--color-text-on-accent);
218
218
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
219
219
  }
220
220
 
221
221
  /* Range end */
222
222
  .calendar-day_e7aa819da[data-range-end="true"]:not([data-disabled="true"]) {
223
- background-color: var(--color-bg-fill-accent);
223
+ background-color: var(--color-bg-control-checked);
224
224
  color: var(--color-text-on-accent);
225
225
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
226
226
  }
@@ -31,9 +31,9 @@
31
31
  display: flex;
32
32
  align-items: center;
33
33
  justify-content: center;
34
- border: var(--border-width-1) solid var(--color-border-control);
34
+ border: var(--border-width-1) solid var(--color-input-border-default);
35
35
  border-radius: var(--radius-sm);
36
- background-color: var(--color-bg-surface);
36
+ background-color: var(--color-input-bg-default);
37
37
  transition: all 0.15s ease;
38
38
  }
39
39
 
@@ -55,80 +55,81 @@
55
55
 
56
56
  /* Hover */
57
57
  .label-wrapper_eed179744:hover .control_eed179744 {
58
- border-color: var(--color-border-control-hover);
58
+ border-color: var(--color-input-border-hover);
59
59
  }
60
60
 
61
61
  .wrapper_eed179744[data-disabled="true"] .label-wrapper_eed179744:hover .control_eed179744 {
62
- border-color: var(--color-border-control-disabled);
62
+ border-color: var(--color-input-border-disabled);
63
63
  }
64
64
 
65
65
  /* Focus */
66
66
  .input_eed179744:focus-visible + .control_eed179744 {
67
- border-color: var(--color-border-focus);
67
+ border-color: var(--color-input-border-focus);
68
68
  box-shadow: var(--focus-ring);
69
69
  }
70
70
 
71
71
  /* Checked */
72
72
  .input_eed179744:checked + .control_eed179744 {
73
- background-color: var(--color-bg-fill-accent);
74
- border-color: var(--color-bg-fill-accent);
73
+ background-color: var(--color-input-checked-bg);
74
+ border-color: var(--color-input-checked-border);
75
75
  }
76
76
 
77
77
  /* Checked + Hover */
78
78
  .label-wrapper_eed179744:hover .input_eed179744:checked + .control_eed179744 {
79
- background-color: var(--color-bg-fill-accent-hover);
80
- border-color: var(--color-bg-fill-accent-hover);
79
+ background-color: var(--color-input-checked-bg-hover);
80
+ border-color: var(--color-input-checked-bg-hover);
81
81
  }
82
82
 
83
83
  /* Indeterminate */
84
84
  .input_eed179744[aria-checked="mixed"] + .control_eed179744 {
85
- background-color: var(--color-bg-fill-accent);
86
- border-color: var(--color-bg-fill-accent);
85
+ background-color: var(--color-input-checked-bg);
86
+ border-color: var(--color-input-checked-border);
87
87
  }
88
88
 
89
- /* Invalid */
89
+ /* Invalid — error path goes through `--color-input-border-error`,
90
+ not `--color-border-critical` directly. */
90
91
  .wrapper_eed179744[data-invalid="true"] .control_eed179744 {
91
- border-color: var(--color-border-critical);
92
+ border-color: var(--color-input-border-error);
92
93
  }
93
94
 
94
95
  .wrapper_eed179744[data-invalid="true"] .input_eed179744:checked + .control_eed179744 {
95
96
  background-color: var(--color-bg-fill-critical);
96
- border-color: var(--color-bg-fill-critical);
97
+ border-color: var(--color-input-border-error);
97
98
  }
98
99
 
99
100
  .wrapper_eed179744[data-invalid="true"] .input_eed179744[aria-checked="mixed"] + .control_eed179744 {
100
101
  background-color: var(--color-bg-fill-critical);
101
- border-color: var(--color-bg-fill-critical);
102
+ border-color: var(--color-input-border-error);
102
103
  }
103
104
 
104
105
  /* Disabled */
105
106
  .input_eed179744:disabled + .control_eed179744 {
106
- background-color: var(--color-bg-disabled);
107
- border-color: var(--color-border-control-disabled);
107
+ background-color: var(--color-input-bg-disabled);
108
+ border-color: var(--color-input-border-disabled);
108
109
  cursor: not-allowed;
109
110
  }
110
111
 
111
112
  .input_eed179744:disabled:checked + .control_eed179744 {
112
- background-color: var(--color-bg-disabled);
113
- border-color: var(--color-border-control-disabled);
113
+ background-color: var(--color-input-bg-disabled);
114
+ border-color: var(--color-input-border-disabled);
114
115
  }
115
116
 
116
117
  .input_eed179744:disabled[aria-checked="mixed"] + .control_eed179744 {
117
- background-color: var(--color-bg-disabled);
118
- border-color: var(--color-border-control-disabled);
118
+ background-color: var(--color-input-bg-disabled);
119
+ border-color: var(--color-input-border-disabled);
119
120
  }
120
121
 
121
122
  /* Disabled icon colors */
122
123
  .input_eed179744:disabled + .control_eed179744 .check-icon_eed179744,
123
124
  .input_eed179744:disabled + .control_eed179744 .indeterminate-icon_eed179744 {
124
- background-color: var(--color-text-disabled);
125
+ background-color: var(--color-input-text-disabled);
125
126
  }
126
127
 
127
128
  /* Check icon */
128
129
  .check-icon_eed179744 {
129
130
  width: 100%;
130
131
  height: 100%;
131
- background-color: var(--color-text-on-accent);
132
+ background-color: var(--color-input-checked-icon);
132
133
  mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M13.5 4.5L6 12L2.5 8.5' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
133
134
  mask-size: 80%;
134
135
  mask-position: center;
@@ -139,7 +140,7 @@
139
140
  .indeterminate-icon_eed179744 {
140
141
  width: 60%;
141
142
  height: 2px;
142
- background-color: var(--color-text-on-accent);
143
+ background-color: var(--color-input-checked-icon);
143
144
  border-radius: 1px;
144
145
  }
145
146
 
@@ -115,7 +115,7 @@
115
115
  .date-range-picker-input_e973c8cc7[data-active="true"] {
116
116
  background-color: color-mix(
117
117
  in srgb,
118
- var(--color-bg-fill-accent) 10%,
118
+ var(--color-bg-control-checked) 10%,
119
119
  transparent
120
120
  );
121
121
  }
@@ -34,10 +34,10 @@
34
34
  min-width: 0;
35
35
  height: 100%;
36
36
  box-sizing: border-box;
37
- border: var(--border-width-1) solid var(--color-border-control);
37
+ border: var(--border-width-1) solid var(--color-input-border-default);
38
38
  border-radius: var(--radius-md);
39
- background-color: var(--color-bg);
40
- color: var(--color-text);
39
+ background-color: var(--color-input-bg-default);
40
+ color: var(--color-input-text-default);
41
41
  font-family: inherit;
42
42
  font-size: inherit;
43
43
  line-height: var(--line-height-tight);
@@ -66,13 +66,13 @@
66
66
 
67
67
  /* Hover */
68
68
  .input_ef268a5e9:hover:not(:disabled, :focus, :read-only) {
69
- border-color: var(--color-border-control-hover);
69
+ border-color: var(--color-input-border-hover);
70
70
  }
71
71
 
72
72
  /* Focus */
73
73
  .input_ef268a5e9:focus {
74
74
  outline: none;
75
- border-color: var(--color-border-focus);
75
+ border-color: var(--color-input-border-focus);
76
76
  box-shadow: var(--focus-ring);
77
77
  }
78
78
 
@@ -84,17 +84,18 @@
84
84
 
85
85
  .input-wrapper_ef268a5e9[data-variant="filled"]
86
86
  .input_ef268a5e9:hover:not(:disabled, :focus, :read-only) {
87
- border-color: var(--color-border-control);
87
+ border-color: var(--color-input-border-default);
88
88
  }
89
89
 
90
90
  .input-wrapper_ef268a5e9[data-variant="filled"] .input_ef268a5e9:focus {
91
- background-color: var(--color-bg);
92
- border-color: var(--color-border-focus);
91
+ background-color: var(--color-input-bg-focus);
92
+ border-color: var(--color-input-border-focus);
93
93
  }
94
94
 
95
- /* Invalid State */
95
+ /* Invalid State — error path goes through the input matrix, not
96
+ `--color-border-critical` directly. */
96
97
  .input-wrapper_ef268a5e9[data-invalid="true"] .input_ef268a5e9 {
97
- border-color: var(--color-border-critical);
98
+ border-color: var(--color-input-border-error);
98
99
  }
99
100
 
100
101
  .input-wrapper_ef268a5e9[data-invalid="true"] .input_ef268a5e9:focus {
@@ -103,9 +104,9 @@
103
104
 
104
105
  /* Disabled State */
105
106
  .input_ef268a5e9:disabled {
106
- background-color: var(--color-bg-disabled);
107
- color: var(--color-text-disabled);
108
- border-color: var(--color-border-control-disabled);
107
+ background-color: var(--color-input-bg-disabled);
108
+ color: var(--color-input-text-disabled);
109
+ border-color: var(--color-input-border-disabled);
109
110
  cursor: not-allowed;
110
111
  }
111
112
 
@@ -167,11 +168,11 @@
167
168
 
168
169
  /* Invalid state for prefix/suffix borders */
169
170
  .input-wrapper_ef268a5e9[data-invalid="true"] .input-prefix_ef268a5e9 {
170
- border-color: var(--color-border-critical);
171
+ border-color: var(--color-input-border-error);
171
172
  border-right: none;
172
173
  }
173
174
 
174
175
  .input-wrapper_ef268a5e9[data-invalid="true"] .input-suffix_ef268a5e9 {
175
- border-color: var(--color-border-critical);
176
+ border-color: var(--color-input-border-error);
176
177
  border-left: none;
177
178
  }
@@ -405,8 +405,8 @@
405
405
  }
406
406
 
407
407
  .multi-combobox-checkbox_e1a041f66[data-checked="true"] {
408
- background-color: var(--color-bg-fill-accent);
409
- border-color: var(--color-bg-fill-accent);
408
+ background-color: var(--color-bg-control-checked);
409
+ border-color: var(--color-bg-control-checked);
410
410
  }
411
411
 
412
412
  .multi-combobox-checkbox_e1a041f66[data-checked="true"]::before {
@@ -263,8 +263,8 @@
263
263
  }
264
264
 
265
265
  .multi-select-option_ed2d11911[data-selected="true"] .multi-select-checkbox_ed2d11911 {
266
- background-color: var(--color-bg-fill-accent);
267
- border-color: var(--color-bg-fill-accent);
266
+ background-color: var(--color-bg-control-checked);
267
+ border-color: var(--color-bg-control-checked);
268
268
  }
269
269
 
270
270
  .multi-select-option_ed2d11911[data-selected="true"]:hover:not([data-disabled="true"])