@attrus-ds/core 0.2.0 → 1.0.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 (80) hide show
  1. package/LICENSE +27 -27
  2. package/dist/assets/flags/Brazil-rounded.svg +15 -15
  3. package/dist/assets/flags/Brazil-square.svg +16 -16
  4. package/dist/assets/flags/Chile-rounded.svg +10 -10
  5. package/dist/assets/flags/Chile-square.svg +10 -10
  6. package/dist/assets/flags/Colombia-rounded.svg +9 -9
  7. package/dist/assets/flags/Colombia-square.svg +9 -9
  8. package/dist/assets/flags/EUA-rounded.svg +10 -10
  9. package/dist/assets/flags/EUA-square.svg +10 -10
  10. package/dist/assets/flags/EUR-rounded.svg +8 -8
  11. package/dist/assets/flags/EUR-square.svg +8 -8
  12. package/dist/assets/flags/Mexico-rounded.svg +18 -18
  13. package/dist/assets/flags/Mexico-square.svg +18 -18
  14. package/dist/assets/icon-attrus-dark.svg +2 -2
  15. package/dist/assets/icon-attrus-light.svg +2 -2
  16. package/dist/assets/logo-attrus-dark.svg +7 -7
  17. package/dist/assets/logo-attrus-light.svg +7 -7
  18. package/dist/css/components/buttons.css +301 -301
  19. package/dist/css/components/callout.css +195 -195
  20. package/dist/css/components/cards.css +272 -272
  21. package/dist/css/components/combobox.css +319 -319
  22. package/dist/css/components/empty-states.css +61 -61
  23. package/dist/css/components/inputs.css +975 -975
  24. package/dist/css/components/number-input.css +138 -138
  25. package/dist/css/components/overlays.css +374 -374
  26. package/dist/css/components/primitives.css +314 -314
  27. package/dist/css/components/sidebar.css +179 -179
  28. package/dist/css/components/smart-search.css +91 -91
  29. package/dist/css/components/status-pills.css +207 -207
  30. package/dist/css/components/stepper.css +309 -309
  31. package/dist/css/components/table.css +602 -602
  32. package/dist/css/components/tabs.css +319 -319
  33. package/dist/css/components/toast.css +243 -243
  34. package/dist/css/components/tooltip.css +231 -231
  35. package/dist/css/components/topbar.css +148 -148
  36. package/dist/css/tokens.css +713 -666
  37. package/dist/react/AppSidebar/AppSidebar.d.ts +50 -50
  38. package/dist/react/AppSidebar/AppSidebar.tsx +197 -197
  39. package/dist/react/AppTopbar/AppTopbar.d.ts +58 -58
  40. package/dist/react/AppTopbar/AppTopbar.tsx +203 -203
  41. package/dist/react/Atoms/Atoms.d.ts +149 -149
  42. package/dist/react/Atoms/Atoms.tsx +407 -407
  43. package/dist/react/Button/Button.d.ts +25 -25
  44. package/dist/react/Button/Button.tsx +83 -83
  45. package/dist/react/Callout/Callout.d.ts +29 -29
  46. package/dist/react/Callout/Callout.tsx +98 -98
  47. package/dist/react/Card/Card.d.ts +38 -38
  48. package/dist/react/Card/Card.tsx +93 -93
  49. package/dist/react/Combobox/Combobox.d.ts +52 -52
  50. package/dist/react/Combobox/Combobox.tsx +254 -254
  51. package/dist/react/DataTable/DataTable.d.ts +81 -81
  52. package/dist/react/DataTable/DataTable.tsx +308 -308
  53. package/dist/react/Drawer/Drawer.d.ts +35 -35
  54. package/dist/react/Drawer/Drawer.tsx +226 -226
  55. package/dist/react/Input/Input.d.ts +155 -155
  56. package/dist/react/Input/Input.tsx +478 -478
  57. package/dist/react/Modal/Modal.d.ts +27 -27
  58. package/dist/react/Modal/Modal.tsx +173 -173
  59. package/dist/react/NumberInput/NumberInput.d.ts +25 -25
  60. package/dist/react/NumberInput/NumberInput.tsx +117 -117
  61. package/dist/react/Pill/Pill.d.ts +31 -31
  62. package/dist/react/Pill/Pill.tsx +104 -104
  63. package/dist/react/SearchPill/SearchPill.d.ts +14 -14
  64. package/dist/react/SearchPill/SearchPill.tsx +40 -40
  65. package/dist/react/SmartSearch/SmartSearch.d.ts +65 -65
  66. package/dist/react/SmartSearch/SmartSearch.tsx +271 -271
  67. package/dist/react/Stepper/Stepper.d.ts +25 -25
  68. package/dist/react/Stepper/Stepper.tsx +94 -94
  69. package/dist/react/Tabs/Tabs.d.ts +32 -32
  70. package/dist/react/Tabs/Tabs.tsx +147 -147
  71. package/dist/react/Toast/Toast.d.ts +30 -30
  72. package/dist/react/Toast/Toast.tsx +94 -94
  73. package/dist/react/Tooltip/Tooltip.d.ts +23 -23
  74. package/dist/react/Tooltip/Tooltip.tsx +80 -80
  75. package/dist/react/ZeroState/ZeroState.d.ts +17 -17
  76. package/dist/react/ZeroState/ZeroState.tsx +45 -45
  77. package/dist/react/index.ts +35 -35
  78. package/dist/tokens/attrus-tokens.flat.json +1234 -1234
  79. package/dist/tokens/attrus-tokens.json +1089 -1089
  80. package/package.json +66 -64
@@ -1,975 +1,975 @@
1
- /* ============================================================
2
- INPUTS & FORM CONTROLS — ATTRUS Design System
3
- Component CSS — pure tokens, no hardcoded values.
4
-
5
- Anatomy (vertical stack):
6
- [label] .field > label
7
- [field row] .field > .input | .group | .affix
8
- [helper / error] .field > .help
9
-
10
- Field variants:
11
- .input base text input (size: md = 40px)
12
- .input.is-error danger border + danger focus ring
13
- .input.is-success success border + success focus ring
14
- .input[disabled] opacity .5 + bg-subtle
15
- .input.is-readonly no border, only value text
16
-
17
- Sizes (apply to .input or wrapper):
18
- .input-sm (32h, fs-sm)
19
- default (40h, fs-md)
20
- .input-lg (48h, fs-lg)
21
-
22
- Wrappers (compose with .input):
23
- .affix .lead | .trail leading / trailing icon
24
- .group .fix.l | .fix.r prefix / suffix attached
25
- .pill-search ⌘K-style search bar
26
- .underline ghost / quiet input
27
- .chips multi-select with embedded text input
28
- .otp one-time-password digit cells
29
-
30
- Other controls (siblings, not .input):
31
- .select wrapper around <select>
32
- .switch toggle
33
- .check custom checkbox
34
- .radio custom radio
35
- .number-input number input with +/- buttons
36
- .file-drop dropzone
37
- .slider range with track + thumb
38
- .date-trigger trigger button for date/time picker
39
-
40
- Inverse:
41
- .input.on-inverse dark-aware text input
42
- surfaces with .dark inherit white-on-dark text
43
- ============================================================ */
44
-
45
-
46
- /* ----------------------------------------------------------------
47
- 1. FIELD WRAPPER
48
- ---------------------------------------------------------------- */
49
- .field {
50
- display: flex;
51
- flex-direction: column;
52
- gap: var(--space-2);
53
- min-width: 0;
54
- }
55
- .field > label {
56
- font-family: var(--font-sans);
57
- font-size: var(--fs-sm);
58
- font-weight: var(--w-semibold);
59
- color: var(--color-foreground-default);
60
- letter-spacing: var(--ls-body);
61
- }
62
- .field > label .req {
63
- color: var(--color-feedback-danger-foreground-muted);
64
- margin-left: 2px;
65
- }
66
- .field > label .opt {
67
- color: var(--color-foreground-muted);
68
- font-weight: var(--w-regular);
69
- margin-left: var(--space-2);
70
- font-size: var(--fs-xs);
71
- }
72
- .field > .help {
73
- font-size: var(--fs-xs);
74
- color: var(--color-foreground-muted);
75
- display: flex;
76
- gap: var(--space-2);
77
- align-items: flex-start;
78
- line-height: var(--lh-snug, 1.4);
79
- }
80
- .field > .help i, .field > .help svg,
81
- .field > .help svg {
82
- width: var(--icon-xs);
83
- height: var(--icon-xs);
84
- stroke-width: var(--icon-stroke);
85
- flex-shrink: 0;
86
- margin-top: 1px;
87
- }
88
- .field > .help.is-error { color: var(--color-feedback-danger-foreground); }
89
- .field > .help.is-error i, .field > .help.is-error svg { color: var(--color-feedback-danger-foreground-muted); }
90
- .field > .help.is-success { color: var(--color-feedback-success-foreground); }
91
- .field > .help.is-success i, .field > .help.is-success svg{ color: var(--color-feedback-success-foreground-muted); }
92
- .field > .help.is-warning { color: var(--color-feedback-warning-foreground); }
93
- .field > .help.is-warning i, .field > .help.is-warning svg{ color: var(--color-feedback-warning-foreground-muted); }
94
-
95
-
96
- /* ----------------------------------------------------------------
97
- 2. BASE INPUT
98
- ---------------------------------------------------------------- */
99
- .input {
100
- /* Box — default size = md (40px tall) */
101
- width: 100%;
102
- box-sizing: border-box;
103
- height: 40px;
104
- padding: 0 var(--space-4);
105
- border: 1px solid var(--color-border-default);
106
- border-radius: var(--radius-sm);
107
- background: var(--color-background-surface);
108
- color: var(--color-foreground-default);
109
-
110
- /* Type */
111
- font-family: var(--font-sans);
112
- font-size: var(--fs-md);
113
- font-weight: var(--w-regular);
114
- line-height: 1;
115
- letter-spacing: var(--ls-body);
116
-
117
- /* Behavior */
118
- outline: none;
119
- transition:
120
- background var(--transition-fast),
121
- border-color var(--transition-fast),
122
- color var(--transition-fast),
123
- box-shadow var(--transition-fast);
124
- }
125
- .input::placeholder { color: var(--color-foreground-placeholder); }
126
-
127
- .input:hover:not(:focus):not([disabled]):not(.is-error):not(.is-success) {
128
- border-color: var(--color-border-strong);
129
- }
130
- .input:focus,
131
- .input:focus-visible {
132
- border-color: var(--color-border-focus);
133
- box-shadow: var(--shadow-focus);
134
- }
135
- .input[disabled],
136
- .input.is-disabled {
137
- background: var(--color-background-subtle);
138
- color: var(--color-foreground-placeholder);
139
- cursor: not-allowed;
140
- opacity: 0.7;
141
- }
142
- .input[readonly],
143
- .input.is-readonly {
144
- background: transparent;
145
- border-color: transparent;
146
- padding-left: 0;
147
- padding-right: 0;
148
- cursor: default;
149
- }
150
-
151
- /* Validation states */
152
- .input.is-error { border-color: var(--color-border-danger); }
153
- .input.is-error:focus { box-shadow: var(--shadow-focus-danger); }
154
- .input.is-success { border-color: var(--color-border-success); }
155
- .input.is-success:focus { box-shadow: var(--shadow-focus-success); }
156
- .input.is-warning { border-color: var(--color-border-warning); }
157
- .input.is-warning:focus { box-shadow: var(--shadow-focus-warning); }
158
-
159
- /* Textarea */
160
- textarea.input {
161
- height: auto;
162
- min-height: 88px;
163
- padding: var(--space-3) var(--space-4);
164
- resize: vertical;
165
- line-height: var(--lh-normal, 1.5);
166
- }
167
-
168
-
169
- /* ----------------------------------------------------------------
170
- 3. SIZES
171
- ---------------------------------------------------------------- */
172
- .input-sm {
173
- height: 32px;
174
- padding: 0 var(--space-3);
175
- font-size: var(--fs-sm);
176
- border-radius: var(--radius-xs);
177
- }
178
- .input-lg {
179
- height: 48px;
180
- padding: 0 var(--space-5);
181
- font-size: var(--fs-lg);
182
- border-radius: var(--radius-md);
183
- }
184
- textarea.input.input-sm { height: auto; min-height: 64px; padding: var(--space-2) var(--space-3); }
185
- textarea.input.input-lg { height: auto; min-height: 120px; padding: var(--space-4) var(--space-5); }
186
-
187
-
188
- /* ----------------------------------------------------------------
189
- 4. AFFIX — leading / trailing icon
190
- ---------------------------------------------------------------- */
191
- .affix { position: relative; display: block; }
192
- .affix .lead,
193
- .affix .trail {
194
- position: absolute;
195
- top: 50%;
196
- transform: translateY(-50%);
197
- width: var(--icon-sm);
198
- height: var(--icon-sm);
199
- stroke-width: var(--icon-stroke);
200
- color: var(--color-foreground-muted);
201
- pointer-events: none;
202
- flex-shrink: 0;
203
- }
204
- .affix .lead { left: var(--space-4); }
205
- .affix .trail { right: var(--space-4); }
206
-
207
- /* Pad the input to make room for the icon */
208
- .affix.lead-pad > .input { padding-left: calc(var(--space-4) + var(--icon-sm) + var(--space-3)); }
209
- .affix.trail-pad > .input { padding-right: calc(var(--space-4) + var(--icon-sm) + var(--space-3)); }
210
-
211
- /* Trailing button (e.g. password reveal, clear) — clickable */
212
- .affix .trail-btn {
213
- position: absolute;
214
- top: 50%;
215
- right: var(--space-2);
216
- transform: translateY(-50%);
217
- width: 28px;
218
- height: 28px;
219
- display: inline-flex;
220
- align-items: center;
221
- justify-content: center;
222
- border: 0;
223
- border-radius: var(--radius-xs);
224
- background: transparent;
225
- color: var(--color-foreground-muted);
226
- cursor: pointer;
227
- transition: background var(--transition-fast), color var(--transition-fast);
228
- }
229
- .affix .trail-btn:hover { background: var(--color-background-hover); color: var(--color-foreground-default); }
230
- .affix .trail-btn:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
231
- .affix .trail-btn > i, .affix .trail-btn > svg,
232
- .affix .trail-btn > svg { width: var(--icon-xs); height: var(--icon-xs); stroke-width: var(--icon-stroke); }
233
-
234
-
235
- /* ----------------------------------------------------------------
236
- 5. PREFIX / SUFFIX GROUP
237
- ---------------------------------------------------------------- */
238
- .group {
239
- display: flex;
240
- align-items: stretch;
241
- width: 100%;
242
- height: 40px;
243
- border: 1px solid var(--color-border-default);
244
- border-radius: var(--radius-sm);
245
- background: var(--color-background-surface);
246
- overflow: hidden;
247
- transition:
248
- border-color var(--transition-fast),
249
- box-shadow var(--transition-fast);
250
- }
251
- .group:focus-within {
252
- border-color: var(--color-border-focus);
253
- box-shadow: var(--shadow-focus);
254
- }
255
- .group .fix {
256
- display: flex;
257
- align-items: center;
258
- gap: var(--space-2);
259
- padding: 0 var(--space-4);
260
- background: var(--color-background-subtle);
261
- color: var(--color-foreground-muted);
262
- font-family: var(--font-mono);
263
- font-size: var(--fs-sm);
264
- flex-shrink: 0;
265
- }
266
- .group .fix.l { border-right: 1px solid var(--color-border-default); }
267
- .group .fix.r { border-left: 1px solid var(--color-border-default); }
268
- .group > input {
269
- flex: 1;
270
- min-width: 0;
271
- border: 0;
272
- outline: none;
273
- padding: 0 var(--space-4);
274
- background: transparent;
275
- color: var(--color-foreground-default);
276
- font-family: var(--font-sans);
277
- font-size: var(--fs-md);
278
- }
279
- .group > input::placeholder { color: var(--color-foreground-placeholder); }
280
- .group.is-error { border-color: var(--color-border-danger); }
281
- .group.is-error:focus-within { box-shadow: var(--shadow-focus-danger); }
282
-
283
-
284
- /* ----------------------------------------------------------------
285
- 6. PILL SEARCH (⌘K-style)
286
- ---------------------------------------------------------------- */
287
- .pill-search {
288
- display: flex;
289
- align-items: center;
290
- gap: var(--space-3);
291
- height: 40px;
292
- padding: 0 var(--space-4);
293
- border: 1px solid var(--color-border-default);
294
- border-radius: var(--radius-pill);
295
- background: var(--color-background-surface);
296
- transition:
297
- border-color var(--transition-fast),
298
- box-shadow var(--transition-fast),
299
- background var(--transition-fast);
300
- }
301
- .pill-search:hover { border-color: var(--color-border-strong); }
302
- .pill-search:focus-within {
303
- border-color: var(--color-border-focus);
304
- box-shadow: var(--shadow-focus);
305
- }
306
- .pill-search > i, .pill-search > svg,
307
- .pill-search > svg {
308
- width: var(--icon-sm);
309
- height: var(--icon-sm);
310
- stroke-width: var(--icon-stroke);
311
- color: var(--color-foreground-muted);
312
- flex-shrink: 0;
313
- }
314
- .pill-search > input {
315
- flex: 1;
316
- min-width: 0;
317
- border: 0;
318
- outline: none;
319
- background: transparent;
320
- font-family: var(--font-sans);
321
- font-size: var(--fs-md);
322
- color: var(--color-foreground-default);
323
- }
324
- .pill-search > input::placeholder { color: var(--color-foreground-placeholder); }
325
- .kbd {
326
- display: inline-flex;
327
- align-items: center;
328
- font-family: var(--font-mono);
329
- font-size: var(--fs-xxs);
330
- font-weight: var(--w-semibold);
331
- color: var(--color-foreground-muted);
332
- background: var(--color-background-subtle);
333
- border: 1px solid var(--color-border-default);
334
- border-radius: var(--radius-2xs);
335
- padding: 1px var(--space-2);
336
- letter-spacing: var(--ls-caps);
337
- }
338
-
339
-
340
- /* ----------------------------------------------------------------
341
- 7. UNDERLINE — quiet / ghost input
342
- ---------------------------------------------------------------- */
343
- .input.underline {
344
- border: 0;
345
- border-bottom: 1px solid var(--color-border-default);
346
- border-radius: 0;
347
- background: transparent;
348
- padding: var(--space-2) 0;
349
- }
350
- .input.underline:focus,
351
- .input.underline:focus-visible {
352
- border-bottom-color: var(--color-border-focus);
353
- box-shadow: none;
354
- }
355
- .input.underline.is-error { border-bottom-color: var(--color-border-danger); }
356
-
357
-
358
- /* ----------------------------------------------------------------
359
- 8. CHIPS — multi-select / token input
360
- ---------------------------------------------------------------- */
361
- .chips {
362
- display: flex;
363
- flex-wrap: wrap;
364
- gap: 6px;
365
- align-items: center;
366
- min-height: 40px;
367
- padding: 5px 8px;
368
- border: 1px solid var(--color-border-default);
369
- border-radius: var(--radius-sm);
370
- background: var(--color-background-surface);
371
- transition:
372
- border-color var(--transition-fast),
373
- box-shadow var(--transition-fast);
374
- }
375
- .chips:hover { border-color: var(--color-border-strong); }
376
- .chips:focus-within {
377
- border-color: var(--color-border-focus);
378
- box-shadow: var(--shadow-focus);
379
- }
380
- .chip {
381
- display: inline-flex;
382
- align-items: center;
383
- gap: 4px;
384
- height: 26px;
385
- padding: 0 4px 0 10px;
386
- background: var(--color-background-subtle);
387
- color: var(--color-foreground-default);
388
- border: 1px solid var(--color-border-default);
389
- border-radius: var(--radius-xs);
390
- font-family: var(--font-sans);
391
- font-size: var(--fs-xs);
392
- font-weight: var(--w-medium);
393
- line-height: 1;
394
- white-space: nowrap;
395
- flex-shrink: 0;
396
- transition: background var(--transition-fast), border-color var(--transition-fast);
397
- }
398
- .chip:hover { background: var(--color-background-canvas); border-color: var(--color-border-strong); }
399
- .chip-x {
400
- display: inline-flex;
401
- align-items: center;
402
- justify-content: center;
403
- width: 18px;
404
- height: 18px;
405
- margin-left: 2px;
406
- border: 0;
407
- padding: 0;
408
- background: transparent;
409
- cursor: pointer;
410
- border-radius: var(--radius-xs);
411
- color: var(--color-foreground-muted);
412
- transition: background var(--transition-fast), color var(--transition-fast);
413
- }
414
- .chip-x svg, .chip-x i { width: 11px; height: 11px; stroke-width: 2.25; }
415
- .chip-x:hover { background: var(--color-border-default); color: var(--color-foreground-default); }
416
- .chips > input {
417
- flex: 1;
418
- min-width: 80px;
419
- height: 26px;
420
- border: 0;
421
- outline: none;
422
- background: transparent;
423
- font-family: var(--font-sans);
424
- font-size: var(--fs-sm);
425
- padding: 0 6px;
426
- color: var(--color-foreground-default);
427
- }
428
- .chips > input::placeholder { color: var(--color-foreground-placeholder); }
429
-
430
-
431
- /* ----------------------------------------------------------------
432
- 9. SELECT (native)
433
- ---------------------------------------------------------------- */
434
- .select {
435
- position: relative;
436
- display: block;
437
- }
438
- .select > select.input {
439
- appearance: none;
440
- -webkit-appearance: none;
441
- cursor: pointer;
442
- padding-right: calc(var(--space-4) + var(--icon-sm) + var(--space-3));
443
- background-image: none;
444
- }
445
- .select > .chev {
446
- position: absolute;
447
- top: 50%;
448
- right: var(--space-4);
449
- transform: translateY(-50%);
450
- width: var(--icon-sm);
451
- height: var(--icon-sm);
452
- stroke-width: var(--icon-stroke);
453
- color: var(--color-foreground-muted);
454
- pointer-events: none;
455
- }
456
-
457
-
458
- /* (NUMBER INPUT moved to number-input.css — canonical single source) */
459
-
460
- /* ----------------------------------------------------------------
461
- 11. OTP — one-time password digit cells
462
- ---------------------------------------------------------------- */
463
- .otp { display: inline-flex; gap: var(--space-2); }
464
- .otp > input {
465
- width: 40px;
466
- height: 48px;
467
- text-align: center;
468
- font-family: var(--font-mono);
469
- font-size: var(--fs-xl);
470
- font-weight: var(--w-semibold);
471
- border: 1px solid var(--color-border-default);
472
- border-radius: var(--radius-sm);
473
- outline: none;
474
- background: var(--color-background-surface);
475
- color: var(--color-foreground-default);
476
- transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
477
- }
478
- .otp > input:focus { border-color: var(--color-border-focus); box-shadow: var(--shadow-focus); }
479
- .otp > input.is-error { border-color: var(--color-border-danger); }
480
-
481
-
482
- /* ----------------------------------------------------------------
483
- 12. SWITCH (toggle)
484
- ---------------------------------------------------------------- */
485
- .switch {
486
- display: inline-flex;
487
- align-items: center;
488
- gap: var(--space-3);
489
- cursor: pointer;
490
- user-select: none;
491
- }
492
- .switch-track {
493
- position: relative;
494
- width: 36px;
495
- height: 20px;
496
- border-radius: var(--radius-pill);
497
- background: var(--color-neutral-300);
498
- transition: background var(--transition-base);
499
- flex-shrink: 0;
500
- }
501
- .switch-thumb {
502
- position: absolute;
503
- top: 2px;
504
- left: 2px;
505
- width: 16px;
506
- height: 16px;
507
- border-radius: var(--radius-pill);
508
- background: var(--color-pure-white);
509
- box-shadow: 0 1px 2px color-mix(in srgb, var(--color-pure-black) 18%, transparent);
510
- transition: transform var(--transition-base);
511
- }
512
- .switch input { position: absolute; opacity: 0; pointer-events: none; }
513
- .switch input:checked ~ .switch-track { background: var(--color-brand-secondary-500); }
514
- .switch input:checked ~ .switch-track .switch-thumb { transform: translateX(16px); }
515
- .switch input:focus-visible ~ .switch-track { box-shadow: var(--shadow-focus); }
516
- .switch input:disabled ~ .switch-track { opacity: 0.5; cursor: not-allowed; }
517
- .switch-label {
518
- font-family: var(--font-sans);
519
- font-size: var(--fs-sm);
520
- color: var(--color-foreground-default);
521
- }
522
-
523
-
524
- /* ----------------------------------------------------------------
525
- 13. CHECKBOX
526
- ---------------------------------------------------------------- */
527
- .check {
528
- display: inline-flex;
529
- align-items: center;
530
- gap: var(--space-3);
531
- cursor: pointer;
532
- user-select: none;
533
- font-family: var(--font-sans);
534
- font-size: var(--fs-sm);
535
- color: var(--color-foreground-default);
536
- }
537
- .check input { position: absolute; opacity: 0; pointer-events: none; }
538
- .check-box {
539
- width: 18px;
540
- height: 18px;
541
- border: 1px solid var(--color-border-strong);
542
- border-radius: var(--radius-xs);
543
- background: var(--color-background-surface);
544
- display: inline-flex;
545
- align-items: center;
546
- justify-content: center;
547
- flex-shrink: 0;
548
- color: var(--color-pure-white);
549
- transition:
550
- background var(--transition-fast),
551
- border-color var(--transition-fast),
552
- box-shadow var(--transition-fast);
553
- }
554
- .check-box svg { width: 14px; height: 14px; stroke-width: 3; opacity: 0; transform: scale(0.8); transition: opacity var(--transition-fast), transform var(--transition-fast); }
555
- .check input:checked ~ .check-box {
556
- background: var(--color-brand-secondary-500);
557
- border-color: var(--color-brand-secondary-500);
558
- }
559
- .check input:checked ~ .check-box svg { opacity: 1; transform: scale(1); }
560
- .check input:indeterminate ~ .check-box {
561
- background: var(--color-brand-secondary-500);
562
- border-color: var(--color-brand-secondary-500);
563
- }
564
- .check input:indeterminate ~ .check-box::after {
565
- content: '';
566
- width: 10px;
567
- height: 2px;
568
- background: var(--color-pure-white);
569
- border-radius: 1px;
570
- }
571
- .check input:indeterminate ~ .check-box svg { display: none; }
572
- .check input:focus-visible ~ .check-box { box-shadow: var(--shadow-focus); }
573
- .check input:disabled ~ .check-box { opacity: 0.5; cursor: not-allowed; }
574
- .check.is-error .check-box { border-color: var(--color-border-danger); }
575
-
576
-
577
- /* ----------------------------------------------------------------
578
- 14. RADIO
579
- ---------------------------------------------------------------- */
580
- .radio {
581
- display: inline-flex;
582
- align-items: center;
583
- gap: var(--space-3);
584
- cursor: pointer;
585
- user-select: none;
586
- font-family: var(--font-sans);
587
- font-size: var(--fs-sm);
588
- color: var(--color-foreground-default);
589
- }
590
- .radio input { position: absolute; opacity: 0; pointer-events: none; }
591
- .radio-dot {
592
- width: 18px;
593
- height: 18px;
594
- border: 1px solid var(--color-border-strong);
595
- border-radius: var(--radius-pill);
596
- background: var(--color-background-surface);
597
- display: inline-flex;
598
- align-items: center;
599
- justify-content: center;
600
- flex-shrink: 0;
601
- transition:
602
- border-color var(--transition-fast),
603
- box-shadow var(--transition-fast);
604
- }
605
- .radio-dot::after {
606
- content: '';
607
- width: 8px;
608
- height: 8px;
609
- border-radius: var(--radius-pill);
610
- background: var(--color-brand-secondary-500);
611
- transform: scale(0);
612
- transition: transform var(--transition-fast);
613
- }
614
- .radio input:checked ~ .radio-dot { border-color: var(--color-brand-secondary-500); }
615
- .radio input:checked ~ .radio-dot::after { transform: scale(1); }
616
- .radio input:focus-visible ~ .radio-dot { box-shadow: var(--shadow-focus); }
617
- .radio input:disabled ~ .radio-dot { opacity: 0.5; cursor: not-allowed; }
618
-
619
-
620
- /* ----------------------------------------------------------------
621
- 15. DATE / TIME TRIGGER
622
- ---------------------------------------------------------------- */
623
- .date-trigger {
624
- display: inline-flex;
625
- align-items: center;
626
- justify-content: space-between;
627
- gap: var(--space-3);
628
- width: 100%;
629
- height: 40px;
630
- padding: 0 var(--space-4);
631
- border: 1px solid var(--color-border-default);
632
- border-radius: var(--radius-sm);
633
- background: var(--color-background-surface);
634
- color: var(--color-foreground-default);
635
- font-family: var(--font-sans);
636
- font-size: var(--fs-md);
637
- cursor: pointer;
638
- transition:
639
- border-color var(--transition-fast),
640
- box-shadow var(--transition-fast),
641
- background var(--transition-fast);
642
- }
643
- .date-trigger:hover { border-color: var(--color-border-strong); }
644
- .date-trigger:focus,
645
- .date-trigger:focus-visible {
646
- outline: none;
647
- border-color: var(--color-border-focus);
648
- box-shadow: var(--shadow-focus);
649
- }
650
- .date-trigger.is-error { border-color: var(--color-border-danger); }
651
- .date-trigger.is-error:focus,
652
- .date-trigger.is-error:focus-visible { box-shadow: var(--shadow-focus-danger); }
653
- .date-trigger .placeholder { color: var(--color-foreground-placeholder); }
654
- .date-trigger > i, .date-trigger > svg,
655
- .date-trigger > svg {
656
- width: var(--icon-sm);
657
- height: var(--icon-sm);
658
- stroke-width: var(--icon-stroke);
659
- color: var(--color-foreground-muted);
660
- flex-shrink: 0;
661
- }
662
-
663
-
664
- /* ----------------------------------------------------------------
665
- 16. FILE DROPZONE
666
- ---------------------------------------------------------------- */
667
- .file-drop {
668
- display: flex;
669
- flex-direction: column;
670
- align-items: center;
671
- justify-content: center;
672
- gap: var(--space-3);
673
- padding: var(--space-7) var(--space-5);
674
- border: 1.5px dashed var(--color-border-default);
675
- border-radius: var(--radius-md);
676
- background: var(--color-background-canvas);
677
- color: var(--color-foreground-secondary);
678
- text-align: center;
679
- cursor: pointer;
680
- transition:
681
- border-color var(--transition-fast),
682
- background var(--transition-fast);
683
- }
684
- .file-drop:hover {
685
- border-color: var(--color-border-focus);
686
- background: var(--color-background-selected);
687
- }
688
- .file-drop.is-dragging {
689
- border-color: var(--color-border-focus);
690
- background: var(--color-background-selected);
691
- border-style: solid;
692
- }
693
- .file-drop > i, .file-drop > svg,
694
- .file-drop > svg {
695
- width: 28px;
696
- height: 28px;
697
- stroke-width: var(--icon-stroke);
698
- color: var(--color-foreground-muted);
699
- }
700
- .file-drop .ttl { font-size: var(--fs-md); font-weight: var(--w-semibold); color: var(--color-foreground-default); }
701
- .file-drop .sub { font-size: var(--fs-xs); color: var(--color-foreground-muted); }
702
- .file-drop .anchor { color: var(--color-foreground-highlight); font-weight: var(--w-semibold); }
703
-
704
- /* ----------------------------------------------------------------
705
- 16b. FILE LIST (post-upload state)
706
- ---------------------------------------------------------------- */
707
- .file-list {
708
- width: 100%;
709
- background: var(--color-background-surface);
710
- border: 1px solid var(--color-border-default);
711
- border-radius: var(--radius-md);
712
- overflow: hidden;
713
- }
714
- .file-list-head {
715
- display: flex;
716
- align-items: center;
717
- justify-content: space-between;
718
- padding: var(--space-3) var(--space-5);
719
- background: var(--color-background-subtle);
720
- border-bottom: 1px solid var(--color-border-subtle);
721
- font-family: var(--font-mono);
722
- font-size: var(--fs-xxs);
723
- color: var(--color-foreground-muted);
724
- text-transform: uppercase;
725
- letter-spacing: var(--ls-caps);
726
- }
727
- .file-list-action {
728
- display: inline-flex;
729
- align-items: center;
730
- gap: var(--space-2);
731
- background: transparent;
732
- border: 0;
733
- padding: 0;
734
- font-family: var(--font-mono);
735
- font-size: var(--fs-xxs);
736
- color: var(--color-foreground-highlight);
737
- text-transform: uppercase;
738
- letter-spacing: var(--ls-caps);
739
- cursor: pointer;
740
- transition: color var(--transition-fast);
741
- }
742
- .file-list-action:hover { color: var(--color-brand-secondary-700); }
743
-
744
- .file-rows {
745
- list-style: none;
746
- margin: 0;
747
- padding: 0;
748
- }
749
- .file-row {
750
- display: grid;
751
- grid-template-columns: auto 1fr auto auto;
752
- align-items: center;
753
- gap: var(--space-4);
754
- padding: var(--space-4) var(--space-5);
755
- border-bottom: 1px solid var(--color-border-subtle);
756
- transition: background var(--transition-fast);
757
- }
758
- .file-row:last-child { border-bottom: 0; }
759
- .file-row:hover { background: var(--color-background-canvas); }
760
-
761
- .file-icon {
762
- position: relative;
763
- width: 40px;
764
- height: 48px;
765
- display: flex;
766
- align-items: center;
767
- justify-content: center;
768
- flex-shrink: 0;
769
- border-radius: var(--radius-xs);
770
- background: var(--color-background-subtle);
771
- color: var(--color-foreground-muted);
772
- }
773
- .file-icon[data-kind="pdf"] { background: color-mix(in srgb, var(--color-danger-500) 8%, var(--color-background-surface)); color: var(--color-feedback-danger-foreground); }
774
- .file-icon[data-kind="img"] { background: color-mix(in srgb, var(--color-brand-secondary-500) 8%, var(--color-background-surface)); color: var(--color-brand-secondary-700); }
775
- .file-icon[data-kind="csv"] { background: color-mix(in srgb, var(--color-success-500) 8%, var(--color-background-surface)); color: var(--color-feedback-success-foreground); }
776
- .file-icon[data-kind="doc"] { background: color-mix(in srgb, var(--color-brand-secondary-500) 10%, var(--color-background-surface)); color: var(--color-brand-secondary-700); }
777
-
778
- .file-icon-tag {
779
- position: absolute;
780
- bottom: 4px;
781
- left: 50%;
782
- transform: translateX(-50%);
783
- font-family: var(--font-mono);
784
- font-size: 8px;
785
- font-weight: var(--w-bold);
786
- letter-spacing: 0.04em;
787
- line-height: 1;
788
- color: currentColor;
789
- background: var(--color-background-surface);
790
- padding: 1px 3px;
791
- border-radius: 2px;
792
- }
793
-
794
- .file-meta {
795
- min-width: 0;
796
- display: flex;
797
- flex-direction: column;
798
- gap: 2px;
799
- }
800
- .file-name {
801
- font-family: var(--font-sans);
802
- font-size: var(--fs-sm);
803
- font-weight: var(--w-semibold);
804
- color: var(--color-foreground-default);
805
- white-space: nowrap;
806
- overflow: hidden;
807
- text-overflow: ellipsis;
808
- }
809
- .file-sub {
810
- font-family: var(--font-mono);
811
- font-size: var(--fs-xxs);
812
- color: var(--color-foreground-muted);
813
- }
814
- .file-sub.err { color: var(--color-feedback-danger-foreground); }
815
-
816
- .file-progress {
817
- margin-top: 6px;
818
- height: 3px;
819
- background: var(--color-background-subtle);
820
- border-radius: var(--radius-pill);
821
- overflow: hidden;
822
- }
823
- .file-progress > span {
824
- display: block;
825
- height: 100%;
826
- background: var(--color-brand-secondary-500);
827
- border-radius: inherit;
828
- transition: width var(--transition-fast);
829
- }
830
-
831
- .file-status {
832
- display: inline-flex;
833
- align-items: center;
834
- gap: 4px;
835
- padding: 3px var(--space-2);
836
- border-radius: var(--radius-pill);
837
- font-family: var(--font-mono);
838
- font-size: var(--fs-xxs);
839
- font-weight: var(--w-semibold);
840
- text-transform: uppercase;
841
- letter-spacing: var(--ls-caps);
842
- white-space: nowrap;
843
- }
844
- .file-status.ok { color: var(--color-feedback-success-foreground); background: var(--color-feedback-success-background); }
845
- .file-status.pending { color: var(--color-brand-secondary-700); background: color-mix(in srgb, var(--color-brand-secondary-500) 10%, transparent); }
846
- .file-status.err { color: var(--color-feedback-danger-foreground); background: var(--color-feedback-danger-background); cursor: pointer; }
847
-
848
- .file-remove {
849
- width: 28px;
850
- height: 28px;
851
- display: inline-flex;
852
- align-items: center;
853
- justify-content: center;
854
- background: transparent;
855
- border: 0;
856
- border-radius: var(--radius-xs);
857
- color: var(--color-foreground-muted);
858
- cursor: pointer;
859
- transition: background var(--transition-fast), color var(--transition-fast);
860
- }
861
- .file-remove:hover { background: var(--color-background-subtle); color: var(--color-foreground-default); }
862
- .file-remove > svg, .file-remove > i { width: 14px; height: 14px; }
863
-
864
-
865
- /* ----------------------------------------------------------------
866
- 17. SLIDER (range)
867
- ---------------------------------------------------------------- */
868
- .slider {
869
- -webkit-appearance: none;
870
- appearance: none;
871
- width: 100%;
872
- height: 24px;
873
- background: transparent;
874
- cursor: pointer;
875
- }
876
- .slider::-webkit-slider-runnable-track {
877
- height: 4px;
878
- background: var(--color-border-default);
879
- border-radius: var(--radius-pill);
880
- }
881
- .slider::-moz-range-track {
882
- height: 4px;
883
- background: var(--color-border-default);
884
- border-radius: var(--radius-pill);
885
- }
886
- .slider::-webkit-slider-thumb {
887
- -webkit-appearance: none;
888
- appearance: none;
889
- width: 18px;
890
- height: 18px;
891
- border-radius: var(--radius-pill);
892
- background: var(--color-brand-secondary-500);
893
- border: 2px solid var(--color-pure-white);
894
- box-shadow: 0 1px 4px color-mix(in srgb, var(--color-shadow-tint) 22%, transparent);
895
- margin-top: -7px;
896
- transition: transform var(--transition-fast);
897
- }
898
- .slider::-moz-range-thumb {
899
- width: 18px;
900
- height: 18px;
901
- border-radius: var(--radius-pill);
902
- background: var(--color-brand-secondary-500);
903
- border: 2px solid var(--color-pure-white);
904
- box-shadow: 0 1px 4px color-mix(in srgb, var(--color-shadow-tint) 22%, transparent);
905
- }
906
- .slider:focus-visible::-webkit-slider-thumb {
907
- box-shadow: var(--shadow-focus);
908
- }
909
- .slider::-webkit-slider-thumb:hover { transform: scale(1.1); }
910
-
911
-
912
- /* ----------------------------------------------------------------
913
- 18. ON INVERSE — dark surfaces
914
- ---------------------------------------------------------------- */
915
- .input.on-inverse,
916
- .dark .input,
917
- .dark .group,
918
- .dark .pill-search,
919
- .dark .chips,
920
- .dark .number-input,
921
- .dark .date-trigger {
922
- background: color-mix(in srgb, var(--color-pure-white) 6%, transparent);
923
- border-color: var(--color-border-inverse);
924
- color: var(--color-foreground-inverse-default);
925
- }
926
- .input.on-inverse::placeholder,
927
- .dark .input::placeholder,
928
- .dark .group > input::placeholder,
929
- .dark .pill-search > input::placeholder,
930
- .dark .chips > input::placeholder {
931
- color: var(--color-foreground-inverse-placeholder);
932
- }
933
- .dark .group > input,
934
- .dark .pill-search > input,
935
- .dark .chips > input,
936
- .dark .number-input > input,
937
- .dark .date-trigger { color: var(--color-foreground-inverse-default); }
938
- .dark .group .fix {
939
- background: color-mix(in srgb, var(--color-pure-white) 4%, transparent);
940
- color: var(--color-foreground-inverse-secondary);
941
- border-color: var(--color-border-inverse);
942
- }
943
- .dark .number-input button {
944
- background: color-mix(in srgb, var(--color-pure-white) 4%, transparent);
945
- color: var(--color-foreground-inverse-default);
946
- border-color: var(--color-border-inverse);
947
- }
948
- .dark .number-input button:hover { background: color-mix(in srgb, var(--color-pure-white) 10%, transparent); }
949
- .dark .input:focus,
950
- .dark .group:focus-within,
951
- .dark .pill-search:focus-within,
952
- .dark .chips:focus-within,
953
- .dark .number-input:focus-within,
954
- .dark .date-trigger:focus-visible {
955
- border-color: var(--color-brand-secondary-300);
956
- box-shadow: var(--shadow-focus-sky);
957
- }
958
- .dark .field > label { color: var(--color-foreground-inverse-default); }
959
- .dark .field > .help { color: var(--color-foreground-inverse-muted); }
960
- .dark .kbd {
961
- background: color-mix(in srgb, var(--color-pure-white) 8%, transparent);
962
- color: var(--color-foreground-inverse-secondary);
963
- border-color: var(--color-border-inverse);
964
- }
965
- .dark .file-drop {
966
- background: color-mix(in srgb, var(--color-pure-white) 4%, transparent);
967
- border-color: var(--color-border-inverse);
968
- color: var(--color-foreground-inverse-muted);
969
- }
970
- .dark .file-drop .ttl { color: var(--color-foreground-inverse-default); }
971
- .dark .check-box,
972
- .dark .radio-dot {
973
- background: color-mix(in srgb, var(--color-pure-white) 6%, transparent);
974
- border-color: var(--color-border-inverse);
975
- }
1
+ /* ============================================================
2
+ INPUTS & FORM CONTROLS — ATTRUS Design System
3
+ Component CSS — pure tokens, no hardcoded values.
4
+
5
+ Anatomy (vertical stack):
6
+ [label] .field > label
7
+ [field row] .field > .input | .group | .affix
8
+ [helper / error] .field > .help
9
+
10
+ Field variants:
11
+ .input base text input (size: md = 40px)
12
+ .input.is-error danger border + danger focus ring
13
+ .input.is-success success border + success focus ring
14
+ .input[disabled] opacity .5 + bg-subtle
15
+ .input.is-readonly no border, only value text
16
+
17
+ Sizes (apply to .input or wrapper):
18
+ .input-sm (32h, fs-sm)
19
+ default (40h, fs-md)
20
+ .input-lg (48h, fs-lg)
21
+
22
+ Wrappers (compose with .input):
23
+ .affix .lead | .trail leading / trailing icon
24
+ .group .fix.l | .fix.r prefix / suffix attached
25
+ .pill-search ⌘K-style search bar
26
+ .underline ghost / quiet input
27
+ .chips multi-select with embedded text input
28
+ .otp one-time-password digit cells
29
+
30
+ Other controls (siblings, not .input):
31
+ .select wrapper around <select>
32
+ .switch toggle
33
+ .check custom checkbox
34
+ .radio custom radio
35
+ .number-input number input with +/- buttons
36
+ .file-drop dropzone
37
+ .slider range with track + thumb
38
+ .date-trigger trigger button for date/time picker
39
+
40
+ Inverse:
41
+ .input.on-inverse dark-aware text input
42
+ surfaces with .dark inherit white-on-dark text
43
+ ============================================================ */
44
+
45
+
46
+ /* ----------------------------------------------------------------
47
+ 1. FIELD WRAPPER
48
+ ---------------------------------------------------------------- */
49
+ .field {
50
+ display: flex;
51
+ flex-direction: column;
52
+ gap: var(--space-2);
53
+ min-width: 0;
54
+ }
55
+ .field > label {
56
+ font-family: var(--font-sans);
57
+ font-size: var(--fs-sm);
58
+ font-weight: var(--w-semibold);
59
+ color: var(--color-foreground-default);
60
+ letter-spacing: var(--ls-body);
61
+ }
62
+ .field > label .req {
63
+ color: var(--color-feedback-danger-foreground-muted);
64
+ margin-left: 2px;
65
+ }
66
+ .field > label .opt {
67
+ color: var(--color-foreground-muted);
68
+ font-weight: var(--w-regular);
69
+ margin-left: var(--space-2);
70
+ font-size: var(--fs-xs);
71
+ }
72
+ .field > .help {
73
+ font-size: var(--fs-xs);
74
+ color: var(--color-foreground-muted);
75
+ display: flex;
76
+ gap: var(--space-2);
77
+ align-items: flex-start;
78
+ line-height: var(--lh-snug, 1.4);
79
+ }
80
+ .field > .help i, .field > .help svg,
81
+ .field > .help svg {
82
+ width: var(--icon-xs);
83
+ height: var(--icon-xs);
84
+ stroke-width: var(--icon-stroke);
85
+ flex-shrink: 0;
86
+ margin-top: 1px;
87
+ }
88
+ .field > .help.is-error { color: var(--color-feedback-danger-foreground); }
89
+ .field > .help.is-error i, .field > .help.is-error svg { color: var(--color-feedback-danger-foreground-muted); }
90
+ .field > .help.is-success { color: var(--color-feedback-success-foreground); }
91
+ .field > .help.is-success i, .field > .help.is-success svg{ color: var(--color-feedback-success-foreground-muted); }
92
+ .field > .help.is-warning { color: var(--color-feedback-warning-foreground); }
93
+ .field > .help.is-warning i, .field > .help.is-warning svg{ color: var(--color-feedback-warning-foreground-muted); }
94
+
95
+
96
+ /* ----------------------------------------------------------------
97
+ 2. BASE INPUT
98
+ ---------------------------------------------------------------- */
99
+ .input {
100
+ /* Box — default size = md (40px tall) */
101
+ width: 100%;
102
+ box-sizing: border-box;
103
+ height: 40px;
104
+ padding: 0 var(--space-4);
105
+ border: 1px solid var(--color-border-default);
106
+ border-radius: var(--shape-control);
107
+ background: var(--color-background-surface);
108
+ color: var(--color-foreground-default);
109
+
110
+ /* Type */
111
+ font-family: var(--font-sans);
112
+ font-size: var(--fs-md);
113
+ font-weight: var(--w-regular);
114
+ line-height: 1;
115
+ letter-spacing: var(--ls-body);
116
+
117
+ /* Behavior */
118
+ outline: none;
119
+ transition:
120
+ background var(--transition-fast),
121
+ border-color var(--transition-fast),
122
+ color var(--transition-fast),
123
+ box-shadow var(--transition-fast);
124
+ }
125
+ .input::placeholder { color: var(--color-foreground-placeholder); }
126
+
127
+ .input:hover:not(:focus):not([disabled]):not(.is-error):not(.is-success) {
128
+ border-color: var(--color-border-strong);
129
+ }
130
+ .input:focus,
131
+ .input:focus-visible {
132
+ border-color: var(--color-border-focus);
133
+ box-shadow: var(--shadow-focus);
134
+ }
135
+ .input[disabled],
136
+ .input.is-disabled {
137
+ background: var(--color-background-subtle);
138
+ color: var(--color-foreground-placeholder);
139
+ cursor: not-allowed;
140
+ opacity: 0.7;
141
+ }
142
+ .input[readonly],
143
+ .input.is-readonly {
144
+ background: transparent;
145
+ border-color: transparent;
146
+ padding-left: 0;
147
+ padding-right: 0;
148
+ cursor: default;
149
+ }
150
+
151
+ /* Validation states */
152
+ .input.is-error { border-color: var(--color-border-danger); }
153
+ .input.is-error:focus { box-shadow: var(--shadow-focus-danger); }
154
+ .input.is-success { border-color: var(--color-border-success); }
155
+ .input.is-success:focus { box-shadow: var(--shadow-focus-success); }
156
+ .input.is-warning { border-color: var(--color-border-warning); }
157
+ .input.is-warning:focus { box-shadow: var(--shadow-focus-warning); }
158
+
159
+ /* Textarea */
160
+ textarea.input {
161
+ height: auto;
162
+ min-height: 88px;
163
+ padding: var(--space-3) var(--space-4);
164
+ resize: vertical;
165
+ line-height: var(--lh-normal, 1.5);
166
+ }
167
+
168
+
169
+ /* ----------------------------------------------------------------
170
+ 3. SIZES
171
+ ---------------------------------------------------------------- */
172
+ .input-sm {
173
+ height: 32px;
174
+ padding: 0 var(--space-3);
175
+ font-size: var(--fs-sm);
176
+ border-radius: var(--radius-xs);
177
+ }
178
+ .input-lg {
179
+ height: 48px;
180
+ padding: 0 var(--space-5);
181
+ font-size: var(--fs-lg);
182
+ border-radius: var(--radius-md);
183
+ }
184
+ textarea.input.input-sm { height: auto; min-height: 64px; padding: var(--space-2) var(--space-3); }
185
+ textarea.input.input-lg { height: auto; min-height: 120px; padding: var(--space-4) var(--space-5); }
186
+
187
+
188
+ /* ----------------------------------------------------------------
189
+ 4. AFFIX — leading / trailing icon
190
+ ---------------------------------------------------------------- */
191
+ .affix { position: relative; display: block; }
192
+ .affix .lead,
193
+ .affix .trail {
194
+ position: absolute;
195
+ top: 50%;
196
+ transform: translateY(-50%);
197
+ width: var(--icon-sm);
198
+ height: var(--icon-sm);
199
+ stroke-width: var(--icon-stroke);
200
+ color: var(--color-foreground-muted);
201
+ pointer-events: none;
202
+ flex-shrink: 0;
203
+ }
204
+ .affix .lead { left: var(--space-4); }
205
+ .affix .trail { right: var(--space-4); }
206
+
207
+ /* Pad the input to make room for the icon */
208
+ .affix.lead-pad > .input { padding-left: calc(var(--space-4) + var(--icon-sm) + var(--space-3)); }
209
+ .affix.trail-pad > .input { padding-right: calc(var(--space-4) + var(--icon-sm) + var(--space-3)); }
210
+
211
+ /* Trailing button (e.g. password reveal, clear) — clickable */
212
+ .affix .trail-btn {
213
+ position: absolute;
214
+ top: 50%;
215
+ right: var(--space-2);
216
+ transform: translateY(-50%);
217
+ width: 28px;
218
+ height: 28px;
219
+ display: inline-flex;
220
+ align-items: center;
221
+ justify-content: center;
222
+ border: 0;
223
+ border-radius: var(--radius-xs);
224
+ background: transparent;
225
+ color: var(--color-foreground-muted);
226
+ cursor: pointer;
227
+ transition: background var(--transition-fast), color var(--transition-fast);
228
+ }
229
+ .affix .trail-btn:hover { background: var(--color-background-hover); color: var(--color-foreground-default); }
230
+ .affix .trail-btn:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
231
+ .affix .trail-btn > i, .affix .trail-btn > svg,
232
+ .affix .trail-btn > svg { width: var(--icon-xs); height: var(--icon-xs); stroke-width: var(--icon-stroke); }
233
+
234
+
235
+ /* ----------------------------------------------------------------
236
+ 5. PREFIX / SUFFIX GROUP
237
+ ---------------------------------------------------------------- */
238
+ .group {
239
+ display: flex;
240
+ align-items: stretch;
241
+ width: 100%;
242
+ height: 40px;
243
+ border: 1px solid var(--color-border-default);
244
+ border-radius: var(--shape-control);
245
+ background: var(--color-background-surface);
246
+ overflow: hidden;
247
+ transition:
248
+ border-color var(--transition-fast),
249
+ box-shadow var(--transition-fast);
250
+ }
251
+ .group:focus-within {
252
+ border-color: var(--color-border-focus);
253
+ box-shadow: var(--shadow-focus);
254
+ }
255
+ .group .fix {
256
+ display: flex;
257
+ align-items: center;
258
+ gap: var(--space-2);
259
+ padding: 0 var(--space-4);
260
+ background: var(--color-background-subtle);
261
+ color: var(--color-foreground-muted);
262
+ font-family: var(--font-mono);
263
+ font-size: var(--fs-sm);
264
+ flex-shrink: 0;
265
+ }
266
+ .group .fix.l { border-right: 1px solid var(--color-border-default); }
267
+ .group .fix.r { border-left: 1px solid var(--color-border-default); }
268
+ .group > input {
269
+ flex: 1;
270
+ min-width: 0;
271
+ border: 0;
272
+ outline: none;
273
+ padding: 0 var(--space-4);
274
+ background: transparent;
275
+ color: var(--color-foreground-default);
276
+ font-family: var(--font-sans);
277
+ font-size: var(--fs-md);
278
+ }
279
+ .group > input::placeholder { color: var(--color-foreground-placeholder); }
280
+ .group.is-error { border-color: var(--color-border-danger); }
281
+ .group.is-error:focus-within { box-shadow: var(--shadow-focus-danger); }
282
+
283
+
284
+ /* ----------------------------------------------------------------
285
+ 6. PILL SEARCH (⌘K-style)
286
+ ---------------------------------------------------------------- */
287
+ .pill-search {
288
+ display: flex;
289
+ align-items: center;
290
+ gap: var(--space-3);
291
+ height: 40px;
292
+ padding: 0 var(--space-4);
293
+ border: 1px solid var(--color-border-default);
294
+ border-radius: var(--radius-pill);
295
+ background: var(--color-background-surface);
296
+ transition:
297
+ border-color var(--transition-fast),
298
+ box-shadow var(--transition-fast),
299
+ background var(--transition-fast);
300
+ }
301
+ .pill-search:hover { border-color: var(--color-border-strong); }
302
+ .pill-search:focus-within {
303
+ border-color: var(--color-border-focus);
304
+ box-shadow: var(--shadow-focus);
305
+ }
306
+ .pill-search > i, .pill-search > svg,
307
+ .pill-search > svg {
308
+ width: var(--icon-sm);
309
+ height: var(--icon-sm);
310
+ stroke-width: var(--icon-stroke);
311
+ color: var(--color-foreground-muted);
312
+ flex-shrink: 0;
313
+ }
314
+ .pill-search > input {
315
+ flex: 1;
316
+ min-width: 0;
317
+ border: 0;
318
+ outline: none;
319
+ background: transparent;
320
+ font-family: var(--font-sans);
321
+ font-size: var(--fs-md);
322
+ color: var(--color-foreground-default);
323
+ }
324
+ .pill-search > input::placeholder { color: var(--color-foreground-placeholder); }
325
+ .kbd {
326
+ display: inline-flex;
327
+ align-items: center;
328
+ font-family: var(--font-mono);
329
+ font-size: var(--fs-xxs);
330
+ font-weight: var(--w-semibold);
331
+ color: var(--color-foreground-muted);
332
+ background: var(--color-background-subtle);
333
+ border: 1px solid var(--color-border-default);
334
+ border-radius: var(--radius-2xs);
335
+ padding: 1px var(--space-2);
336
+ letter-spacing: var(--ls-caps);
337
+ }
338
+
339
+
340
+ /* ----------------------------------------------------------------
341
+ 7. UNDERLINE — quiet / ghost input
342
+ ---------------------------------------------------------------- */
343
+ .input.underline {
344
+ border: 0;
345
+ border-bottom: 1px solid var(--color-border-default);
346
+ border-radius: 0;
347
+ background: transparent;
348
+ padding: var(--space-2) 0;
349
+ }
350
+ .input.underline:focus,
351
+ .input.underline:focus-visible {
352
+ border-bottom-color: var(--color-border-focus);
353
+ box-shadow: none;
354
+ }
355
+ .input.underline.is-error { border-bottom-color: var(--color-border-danger); }
356
+
357
+
358
+ /* ----------------------------------------------------------------
359
+ 8. CHIPS — multi-select / token input
360
+ ---------------------------------------------------------------- */
361
+ .chips {
362
+ display: flex;
363
+ flex-wrap: wrap;
364
+ gap: 6px;
365
+ align-items: center;
366
+ min-height: 40px;
367
+ padding: 5px 8px;
368
+ border: 1px solid var(--color-border-default);
369
+ border-radius: var(--shape-control);
370
+ background: var(--color-background-surface);
371
+ transition:
372
+ border-color var(--transition-fast),
373
+ box-shadow var(--transition-fast);
374
+ }
375
+ .chips:hover { border-color: var(--color-border-strong); }
376
+ .chips:focus-within {
377
+ border-color: var(--color-border-focus);
378
+ box-shadow: var(--shadow-focus);
379
+ }
380
+ .chip {
381
+ display: inline-flex;
382
+ align-items: center;
383
+ gap: 4px;
384
+ height: 26px;
385
+ padding: 0 4px 0 10px;
386
+ background: var(--color-background-subtle);
387
+ color: var(--color-foreground-default);
388
+ border: 1px solid var(--color-border-default);
389
+ border-radius: var(--radius-xs);
390
+ font-family: var(--font-sans);
391
+ font-size: var(--fs-xs);
392
+ font-weight: var(--w-medium);
393
+ line-height: 1;
394
+ white-space: nowrap;
395
+ flex-shrink: 0;
396
+ transition: background var(--transition-fast), border-color var(--transition-fast);
397
+ }
398
+ .chip:hover { background: var(--color-background-canvas); border-color: var(--color-border-strong); }
399
+ .chip-x {
400
+ display: inline-flex;
401
+ align-items: center;
402
+ justify-content: center;
403
+ width: 18px;
404
+ height: 18px;
405
+ margin-left: 2px;
406
+ border: 0;
407
+ padding: 0;
408
+ background: transparent;
409
+ cursor: pointer;
410
+ border-radius: var(--radius-xs);
411
+ color: var(--color-foreground-muted);
412
+ transition: background var(--transition-fast), color var(--transition-fast);
413
+ }
414
+ .chip-x svg, .chip-x i { width: 11px; height: 11px; stroke-width: 2.25; }
415
+ .chip-x:hover { background: var(--color-border-default); color: var(--color-foreground-default); }
416
+ .chips > input {
417
+ flex: 1;
418
+ min-width: 80px;
419
+ height: 26px;
420
+ border: 0;
421
+ outline: none;
422
+ background: transparent;
423
+ font-family: var(--font-sans);
424
+ font-size: var(--fs-sm);
425
+ padding: 0 6px;
426
+ color: var(--color-foreground-default);
427
+ }
428
+ .chips > input::placeholder { color: var(--color-foreground-placeholder); }
429
+
430
+
431
+ /* ----------------------------------------------------------------
432
+ 9. SELECT (native)
433
+ ---------------------------------------------------------------- */
434
+ .select {
435
+ position: relative;
436
+ display: block;
437
+ }
438
+ .select > select.input {
439
+ appearance: none;
440
+ -webkit-appearance: none;
441
+ cursor: pointer;
442
+ padding-right: calc(var(--space-4) + var(--icon-sm) + var(--space-3));
443
+ background-image: none;
444
+ }
445
+ .select > .chev {
446
+ position: absolute;
447
+ top: 50%;
448
+ right: var(--space-4);
449
+ transform: translateY(-50%);
450
+ width: var(--icon-sm);
451
+ height: var(--icon-sm);
452
+ stroke-width: var(--icon-stroke);
453
+ color: var(--color-foreground-muted);
454
+ pointer-events: none;
455
+ }
456
+
457
+
458
+ /* (NUMBER INPUT moved to number-input.css — canonical single source) */
459
+
460
+ /* ----------------------------------------------------------------
461
+ 11. OTP — one-time password digit cells
462
+ ---------------------------------------------------------------- */
463
+ .otp { display: inline-flex; gap: var(--space-2); }
464
+ .otp > input {
465
+ width: 40px;
466
+ height: 48px;
467
+ text-align: center;
468
+ font-family: var(--font-mono);
469
+ font-size: var(--fs-xl);
470
+ font-weight: var(--w-semibold);
471
+ border: 1px solid var(--color-border-default);
472
+ border-radius: var(--shape-container);
473
+ outline: none;
474
+ background: var(--color-background-surface);
475
+ color: var(--color-foreground-default);
476
+ transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
477
+ }
478
+ .otp > input:focus { border-color: var(--color-border-focus); box-shadow: var(--shadow-focus); }
479
+ .otp > input.is-error { border-color: var(--color-border-danger); }
480
+
481
+
482
+ /* ----------------------------------------------------------------
483
+ 12. SWITCH (toggle)
484
+ ---------------------------------------------------------------- */
485
+ .switch {
486
+ display: inline-flex;
487
+ align-items: center;
488
+ gap: var(--space-3);
489
+ cursor: pointer;
490
+ user-select: none;
491
+ }
492
+ .switch-track {
493
+ position: relative;
494
+ width: 36px;
495
+ height: 20px;
496
+ border-radius: var(--radius-pill);
497
+ background: var(--color-neutral-300);
498
+ transition: background var(--transition-base);
499
+ flex-shrink: 0;
500
+ }
501
+ .switch-thumb {
502
+ position: absolute;
503
+ top: 2px;
504
+ left: 2px;
505
+ width: 16px;
506
+ height: 16px;
507
+ border-radius: var(--radius-pill);
508
+ background: var(--color-pure-white);
509
+ box-shadow: 0 1px 2px color-mix(in srgb, var(--color-pure-black) 18%, transparent);
510
+ transition: transform var(--transition-base);
511
+ }
512
+ .switch input { position: absolute; opacity: 0; pointer-events: none; }
513
+ .switch input:checked ~ .switch-track { background: var(--color-brand-solid); }
514
+ .switch input:checked ~ .switch-track .switch-thumb { transform: translateX(16px); }
515
+ .switch input:focus-visible ~ .switch-track { box-shadow: var(--shadow-focus); }
516
+ .switch input:disabled ~ .switch-track { opacity: 0.5; cursor: not-allowed; }
517
+ .switch-label {
518
+ font-family: var(--font-sans);
519
+ font-size: var(--fs-sm);
520
+ color: var(--color-foreground-default);
521
+ }
522
+
523
+
524
+ /* ----------------------------------------------------------------
525
+ 13. CHECKBOX
526
+ ---------------------------------------------------------------- */
527
+ .check {
528
+ display: inline-flex;
529
+ align-items: center;
530
+ gap: var(--space-3);
531
+ cursor: pointer;
532
+ user-select: none;
533
+ font-family: var(--font-sans);
534
+ font-size: var(--fs-sm);
535
+ color: var(--color-foreground-default);
536
+ }
537
+ .check input { position: absolute; opacity: 0; pointer-events: none; }
538
+ .check-box {
539
+ width: 18px;
540
+ height: 18px;
541
+ border: 1px solid var(--color-border-strong);
542
+ border-radius: var(--radius-xs);
543
+ background: var(--color-background-surface);
544
+ display: inline-flex;
545
+ align-items: center;
546
+ justify-content: center;
547
+ flex-shrink: 0;
548
+ color: var(--color-pure-white);
549
+ transition:
550
+ background var(--transition-fast),
551
+ border-color var(--transition-fast),
552
+ box-shadow var(--transition-fast);
553
+ }
554
+ .check-box svg { width: 14px; height: 14px; stroke-width: 3; opacity: 0; transform: scale(0.8); transition: opacity var(--transition-fast), transform var(--transition-fast); }
555
+ .check input:checked ~ .check-box {
556
+ background: var(--color-brand-solid);
557
+ border-color: var(--color-brand-solid);
558
+ }
559
+ .check input:checked ~ .check-box svg { opacity: 1; transform: scale(1); }
560
+ .check input:indeterminate ~ .check-box {
561
+ background: var(--color-brand-solid);
562
+ border-color: var(--color-brand-solid);
563
+ }
564
+ .check input:indeterminate ~ .check-box::after {
565
+ content: '';
566
+ width: 10px;
567
+ height: 2px;
568
+ background: var(--color-pure-white);
569
+ border-radius: 1px;
570
+ }
571
+ .check input:indeterminate ~ .check-box svg { display: none; }
572
+ .check input:focus-visible ~ .check-box { box-shadow: var(--shadow-focus); }
573
+ .check input:disabled ~ .check-box { opacity: 0.5; cursor: not-allowed; }
574
+ .check.is-error .check-box { border-color: var(--color-border-danger); }
575
+
576
+
577
+ /* ----------------------------------------------------------------
578
+ 14. RADIO
579
+ ---------------------------------------------------------------- */
580
+ .radio {
581
+ display: inline-flex;
582
+ align-items: center;
583
+ gap: var(--space-3);
584
+ cursor: pointer;
585
+ user-select: none;
586
+ font-family: var(--font-sans);
587
+ font-size: var(--fs-sm);
588
+ color: var(--color-foreground-default);
589
+ }
590
+ .radio input { position: absolute; opacity: 0; pointer-events: none; }
591
+ .radio-dot {
592
+ width: 18px;
593
+ height: 18px;
594
+ border: 1px solid var(--color-border-strong);
595
+ border-radius: var(--radius-pill);
596
+ background: var(--color-background-surface);
597
+ display: inline-flex;
598
+ align-items: center;
599
+ justify-content: center;
600
+ flex-shrink: 0;
601
+ transition:
602
+ border-color var(--transition-fast),
603
+ box-shadow var(--transition-fast);
604
+ }
605
+ .radio-dot::after {
606
+ content: '';
607
+ width: 8px;
608
+ height: 8px;
609
+ border-radius: var(--radius-pill);
610
+ background: var(--color-brand-solid);
611
+ transform: scale(0);
612
+ transition: transform var(--transition-fast);
613
+ }
614
+ .radio input:checked ~ .radio-dot { border-color: var(--color-brand-solid); }
615
+ .radio input:checked ~ .radio-dot::after { transform: scale(1); }
616
+ .radio input:focus-visible ~ .radio-dot { box-shadow: var(--shadow-focus); }
617
+ .radio input:disabled ~ .radio-dot { opacity: 0.5; cursor: not-allowed; }
618
+
619
+
620
+ /* ----------------------------------------------------------------
621
+ 15. DATE / TIME TRIGGER
622
+ ---------------------------------------------------------------- */
623
+ .date-trigger {
624
+ display: inline-flex;
625
+ align-items: center;
626
+ justify-content: space-between;
627
+ gap: var(--space-3);
628
+ width: 100%;
629
+ height: 40px;
630
+ padding: 0 var(--space-4);
631
+ border: 1px solid var(--color-border-default);
632
+ border-radius: var(--shape-control);
633
+ background: var(--color-background-surface);
634
+ color: var(--color-foreground-default);
635
+ font-family: var(--font-sans);
636
+ font-size: var(--fs-md);
637
+ cursor: pointer;
638
+ transition:
639
+ border-color var(--transition-fast),
640
+ box-shadow var(--transition-fast),
641
+ background var(--transition-fast);
642
+ }
643
+ .date-trigger:hover { border-color: var(--color-border-strong); }
644
+ .date-trigger:focus,
645
+ .date-trigger:focus-visible {
646
+ outline: none;
647
+ border-color: var(--color-border-focus);
648
+ box-shadow: var(--shadow-focus);
649
+ }
650
+ .date-trigger.is-error { border-color: var(--color-border-danger); }
651
+ .date-trigger.is-error:focus,
652
+ .date-trigger.is-error:focus-visible { box-shadow: var(--shadow-focus-danger); }
653
+ .date-trigger .placeholder { color: var(--color-foreground-placeholder); }
654
+ .date-trigger > i, .date-trigger > svg,
655
+ .date-trigger > svg {
656
+ width: var(--icon-sm);
657
+ height: var(--icon-sm);
658
+ stroke-width: var(--icon-stroke);
659
+ color: var(--color-foreground-muted);
660
+ flex-shrink: 0;
661
+ }
662
+
663
+
664
+ /* ----------------------------------------------------------------
665
+ 16. FILE DROPZONE
666
+ ---------------------------------------------------------------- */
667
+ .file-drop {
668
+ display: flex;
669
+ flex-direction: column;
670
+ align-items: center;
671
+ justify-content: center;
672
+ gap: var(--space-3);
673
+ padding: var(--space-7) var(--space-5);
674
+ border: 1.5px dashed var(--color-border-default);
675
+ border-radius: var(--radius-md);
676
+ background: var(--color-background-canvas);
677
+ color: var(--color-foreground-secondary);
678
+ text-align: center;
679
+ cursor: pointer;
680
+ transition:
681
+ border-color var(--transition-fast),
682
+ background var(--transition-fast);
683
+ }
684
+ .file-drop:hover {
685
+ border-color: var(--color-border-focus);
686
+ background: var(--color-background-selected);
687
+ }
688
+ .file-drop.is-dragging {
689
+ border-color: var(--color-border-focus);
690
+ background: var(--color-background-selected);
691
+ border-style: solid;
692
+ }
693
+ .file-drop > i, .file-drop > svg,
694
+ .file-drop > svg {
695
+ width: 28px;
696
+ height: 28px;
697
+ stroke-width: var(--icon-stroke);
698
+ color: var(--color-foreground-muted);
699
+ }
700
+ .file-drop .ttl { font-size: var(--fs-md); font-weight: var(--w-semibold); color: var(--color-foreground-default); }
701
+ .file-drop .sub { font-size: var(--fs-xs); color: var(--color-foreground-muted); }
702
+ .file-drop .anchor { color: var(--color-foreground-highlight); font-weight: var(--w-semibold); }
703
+
704
+ /* ----------------------------------------------------------------
705
+ 16b. FILE LIST (post-upload state)
706
+ ---------------------------------------------------------------- */
707
+ .file-list {
708
+ width: 100%;
709
+ background: var(--color-background-surface);
710
+ border: 1px solid var(--color-border-default);
711
+ border-radius: var(--radius-md);
712
+ overflow: hidden;
713
+ }
714
+ .file-list-head {
715
+ display: flex;
716
+ align-items: center;
717
+ justify-content: space-between;
718
+ padding: var(--space-3) var(--space-5);
719
+ background: var(--color-background-subtle);
720
+ border-bottom: 1px solid var(--color-border-subtle);
721
+ font-family: var(--font-mono);
722
+ font-size: var(--fs-xxs);
723
+ color: var(--color-foreground-muted);
724
+ text-transform: uppercase;
725
+ letter-spacing: var(--ls-caps);
726
+ }
727
+ .file-list-action {
728
+ display: inline-flex;
729
+ align-items: center;
730
+ gap: var(--space-2);
731
+ background: transparent;
732
+ border: 0;
733
+ padding: 0;
734
+ font-family: var(--font-mono);
735
+ font-size: var(--fs-xxs);
736
+ color: var(--color-foreground-highlight);
737
+ text-transform: uppercase;
738
+ letter-spacing: var(--ls-caps);
739
+ cursor: pointer;
740
+ transition: color var(--transition-fast);
741
+ }
742
+ .file-list-action:hover { color: var(--color-brand-text); }
743
+
744
+ .file-rows {
745
+ list-style: none;
746
+ margin: 0;
747
+ padding: 0;
748
+ }
749
+ .file-row {
750
+ display: grid;
751
+ grid-template-columns: auto 1fr auto auto;
752
+ align-items: center;
753
+ gap: var(--space-4);
754
+ padding: var(--space-4) var(--space-5);
755
+ border-bottom: 1px solid var(--color-border-subtle);
756
+ transition: background var(--transition-fast);
757
+ }
758
+ .file-row:last-child { border-bottom: 0; }
759
+ .file-row:hover { background: var(--color-background-canvas); }
760
+
761
+ .file-icon {
762
+ position: relative;
763
+ width: 40px;
764
+ height: 48px;
765
+ display: flex;
766
+ align-items: center;
767
+ justify-content: center;
768
+ flex-shrink: 0;
769
+ border-radius: var(--radius-xs);
770
+ background: var(--color-background-subtle);
771
+ color: var(--color-foreground-muted);
772
+ }
773
+ .file-icon[data-kind="pdf"] { background: color-mix(in srgb, var(--color-danger-500) 8%, var(--color-background-surface)); color: var(--color-feedback-danger-foreground); }
774
+ .file-icon[data-kind="img"] { background: color-mix(in srgb, var(--color-brand-solid) 8%, var(--color-background-surface)); color: var(--color-brand-text); }
775
+ .file-icon[data-kind="csv"] { background: color-mix(in srgb, var(--color-success-500) 8%, var(--color-background-surface)); color: var(--color-feedback-success-foreground); }
776
+ .file-icon[data-kind="doc"] { background: color-mix(in srgb, var(--color-brand-solid) 10%, var(--color-background-surface)); color: var(--color-brand-text); }
777
+
778
+ .file-icon-tag {
779
+ position: absolute;
780
+ bottom: 4px;
781
+ left: 50%;
782
+ transform: translateX(-50%);
783
+ font-family: var(--font-mono);
784
+ font-size: 8px;
785
+ font-weight: var(--w-bold);
786
+ letter-spacing: 0.04em;
787
+ line-height: 1;
788
+ color: currentColor;
789
+ background: var(--color-background-surface);
790
+ padding: 1px 3px;
791
+ border-radius: 2px;
792
+ }
793
+
794
+ .file-meta {
795
+ min-width: 0;
796
+ display: flex;
797
+ flex-direction: column;
798
+ gap: 2px;
799
+ }
800
+ .file-name {
801
+ font-family: var(--font-sans);
802
+ font-size: var(--fs-sm);
803
+ font-weight: var(--w-semibold);
804
+ color: var(--color-foreground-default);
805
+ white-space: nowrap;
806
+ overflow: hidden;
807
+ text-overflow: ellipsis;
808
+ }
809
+ .file-sub {
810
+ font-family: var(--font-mono);
811
+ font-size: var(--fs-xxs);
812
+ color: var(--color-foreground-muted);
813
+ }
814
+ .file-sub.err { color: var(--color-feedback-danger-foreground); }
815
+
816
+ .file-progress {
817
+ margin-top: 6px;
818
+ height: 3px;
819
+ background: var(--color-background-subtle);
820
+ border-radius: var(--radius-pill);
821
+ overflow: hidden;
822
+ }
823
+ .file-progress > span {
824
+ display: block;
825
+ height: 100%;
826
+ background: var(--color-brand-solid);
827
+ border-radius: inherit;
828
+ transition: width var(--transition-fast);
829
+ }
830
+
831
+ .file-status {
832
+ display: inline-flex;
833
+ align-items: center;
834
+ gap: 4px;
835
+ padding: 3px var(--space-2);
836
+ border-radius: var(--radius-pill);
837
+ font-family: var(--font-mono);
838
+ font-size: var(--fs-xxs);
839
+ font-weight: var(--w-semibold);
840
+ text-transform: uppercase;
841
+ letter-spacing: var(--ls-caps);
842
+ white-space: nowrap;
843
+ }
844
+ .file-status.ok { color: var(--color-feedback-success-foreground); background: var(--color-feedback-success-background); }
845
+ .file-status.pending { color: var(--color-brand-text); background: var(--color-brand-subtle); }
846
+ .file-status.err { color: var(--color-feedback-danger-foreground); background: var(--color-feedback-danger-background); cursor: pointer; }
847
+
848
+ .file-remove {
849
+ width: 28px;
850
+ height: 28px;
851
+ display: inline-flex;
852
+ align-items: center;
853
+ justify-content: center;
854
+ background: transparent;
855
+ border: 0;
856
+ border-radius: var(--radius-xs);
857
+ color: var(--color-foreground-muted);
858
+ cursor: pointer;
859
+ transition: background var(--transition-fast), color var(--transition-fast);
860
+ }
861
+ .file-remove:hover { background: var(--color-background-subtle); color: var(--color-foreground-default); }
862
+ .file-remove > svg, .file-remove > i { width: 14px; height: 14px; }
863
+
864
+
865
+ /* ----------------------------------------------------------------
866
+ 17. SLIDER (range)
867
+ ---------------------------------------------------------------- */
868
+ .slider {
869
+ -webkit-appearance: none;
870
+ appearance: none;
871
+ width: 100%;
872
+ height: 24px;
873
+ background: transparent;
874
+ cursor: pointer;
875
+ }
876
+ .slider::-webkit-slider-runnable-track {
877
+ height: 4px;
878
+ background: var(--color-border-default);
879
+ border-radius: var(--radius-pill);
880
+ }
881
+ .slider::-moz-range-track {
882
+ height: 4px;
883
+ background: var(--color-border-default);
884
+ border-radius: var(--radius-pill);
885
+ }
886
+ .slider::-webkit-slider-thumb {
887
+ -webkit-appearance: none;
888
+ appearance: none;
889
+ width: 18px;
890
+ height: 18px;
891
+ border-radius: var(--radius-pill);
892
+ background: var(--color-brand-solid);
893
+ border: 2px solid var(--color-pure-white);
894
+ box-shadow: 0 1px 4px color-mix(in srgb, var(--color-shadow-tint) 22%, transparent);
895
+ margin-top: -7px;
896
+ transition: transform var(--transition-fast);
897
+ }
898
+ .slider::-moz-range-thumb {
899
+ width: 18px;
900
+ height: 18px;
901
+ border-radius: var(--radius-pill);
902
+ background: var(--color-brand-solid);
903
+ border: 2px solid var(--color-pure-white);
904
+ box-shadow: 0 1px 4px color-mix(in srgb, var(--color-shadow-tint) 22%, transparent);
905
+ }
906
+ .slider:focus-visible::-webkit-slider-thumb {
907
+ box-shadow: var(--shadow-focus);
908
+ }
909
+ .slider::-webkit-slider-thumb:hover { transform: scale(1.1); }
910
+
911
+
912
+ /* ----------------------------------------------------------------
913
+ 18. ON INVERSE — dark surfaces
914
+ ---------------------------------------------------------------- */
915
+ .input.on-inverse,
916
+ .dark .input,
917
+ .dark .group,
918
+ .dark .pill-search,
919
+ .dark .chips,
920
+ .dark .number-input,
921
+ .dark .date-trigger {
922
+ background: color-mix(in srgb, var(--color-pure-white) 6%, transparent);
923
+ border-color: var(--color-border-inverse);
924
+ color: var(--color-foreground-inverse-default);
925
+ }
926
+ .input.on-inverse::placeholder,
927
+ .dark .input::placeholder,
928
+ .dark .group > input::placeholder,
929
+ .dark .pill-search > input::placeholder,
930
+ .dark .chips > input::placeholder {
931
+ color: var(--color-foreground-inverse-placeholder);
932
+ }
933
+ .dark .group > input,
934
+ .dark .pill-search > input,
935
+ .dark .chips > input,
936
+ .dark .number-input > input,
937
+ .dark .date-trigger { color: var(--color-foreground-inverse-default); }
938
+ .dark .group .fix {
939
+ background: color-mix(in srgb, var(--color-pure-white) 4%, transparent);
940
+ color: var(--color-foreground-inverse-secondary);
941
+ border-color: var(--color-border-inverse);
942
+ }
943
+ .dark .number-input button {
944
+ background: color-mix(in srgb, var(--color-pure-white) 4%, transparent);
945
+ color: var(--color-foreground-inverse-default);
946
+ border-color: var(--color-border-inverse);
947
+ }
948
+ .dark .number-input button:hover { background: color-mix(in srgb, var(--color-pure-white) 10%, transparent); }
949
+ .dark .input:focus,
950
+ .dark .group:focus-within,
951
+ .dark .pill-search:focus-within,
952
+ .dark .chips:focus-within,
953
+ .dark .number-input:focus-within,
954
+ .dark .date-trigger:focus-visible {
955
+ border-color: var(--color-brand-secondary-300);
956
+ box-shadow: var(--shadow-focus-sky);
957
+ }
958
+ .dark .field > label { color: var(--color-foreground-inverse-default); }
959
+ .dark .field > .help { color: var(--color-foreground-inverse-muted); }
960
+ .dark .kbd {
961
+ background: color-mix(in srgb, var(--color-pure-white) 8%, transparent);
962
+ color: var(--color-foreground-inverse-secondary);
963
+ border-color: var(--color-border-inverse);
964
+ }
965
+ .dark .file-drop {
966
+ background: color-mix(in srgb, var(--color-pure-white) 4%, transparent);
967
+ border-color: var(--color-border-inverse);
968
+ color: var(--color-foreground-inverse-muted);
969
+ }
970
+ .dark .file-drop .ttl { color: var(--color-foreground-inverse-default); }
971
+ .dark .check-box,
972
+ .dark .radio-dot {
973
+ background: color-mix(in srgb, var(--color-pure-white) 6%, transparent);
974
+ border-color: var(--color-border-inverse);
975
+ }