@24vlh/vds 0.1.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 (65) hide show
  1. package/LICENSE.txt +201 -0
  2. package/README.md +147 -0
  3. package/dist/components/accordion.css +170 -0
  4. package/dist/components/accordion.min.css +1 -0
  5. package/dist/components/authoring.css +332 -0
  6. package/dist/components/authoring.min.css +1 -0
  7. package/dist/components/buttons.css +683 -0
  8. package/dist/components/buttons.min.css +1 -0
  9. package/dist/components/charts.css +502 -0
  10. package/dist/components/charts.min.css +1 -0
  11. package/dist/components/command.css +521 -0
  12. package/dist/components/command.min.css +1 -0
  13. package/dist/components/content-blocks.css +944 -0
  14. package/dist/components/content-blocks.min.css +1 -0
  15. package/dist/components/doc-block.css +782 -0
  16. package/dist/components/doc-block.min.css +1 -0
  17. package/dist/components/feedback.css +657 -0
  18. package/dist/components/feedback.min.css +1 -0
  19. package/dist/components/flows.css +1101 -0
  20. package/dist/components/flows.min.css +1 -0
  21. package/dist/components/forms-advanced.css +462 -0
  22. package/dist/components/forms-advanced.min.css +1 -0
  23. package/dist/components/forms.css +1831 -0
  24. package/dist/components/forms.min.css +1 -0
  25. package/dist/components/header-footer.css +348 -0
  26. package/dist/components/header-footer.min.css +1 -0
  27. package/dist/components/hero.css +498 -0
  28. package/dist/components/hero.min.css +1 -0
  29. package/dist/components/icons.css +937 -0
  30. package/dist/components/icons.min.css +1 -0
  31. package/dist/components/navigation.css +900 -0
  32. package/dist/components/navigation.min.css +1 -0
  33. package/dist/components/overlays.css +498 -0
  34. package/dist/components/overlays.min.css +1 -0
  35. package/dist/components/sections.css +450 -0
  36. package/dist/components/sections.min.css +1 -0
  37. package/dist/components/skeleton.css +385 -0
  38. package/dist/components/skeleton.min.css +1 -0
  39. package/dist/components/tables.css +591 -0
  40. package/dist/components/tables.min.css +1 -0
  41. package/dist/components/tabs.css +307 -0
  42. package/dist/components/tabs.min.css +1 -0
  43. package/dist/components/toasts.css +421 -0
  44. package/dist/components/toasts.min.css +1 -0
  45. package/dist/components/tooltips-popovers.css +447 -0
  46. package/dist/components/tooltips-popovers.min.css +1 -0
  47. package/dist/components/typography.css +250 -0
  48. package/dist/components/typography.min.css +1 -0
  49. package/dist/components/utilities.css +3434 -0
  50. package/dist/components/utilities.min.css +1 -0
  51. package/dist/core.css +866 -0
  52. package/dist/core.min.css +1 -0
  53. package/dist/identity.css +266 -0
  54. package/dist/identity.min.css +1 -0
  55. package/dist/themes/carbon.css +658 -0
  56. package/dist/themes/carbon.min.css +1 -0
  57. package/dist/themes/graphite.css +658 -0
  58. package/dist/themes/graphite.min.css +1 -0
  59. package/dist/themes/navy.css +657 -0
  60. package/dist/themes/navy.min.css +1 -0
  61. package/dist/themes/slate.css +659 -0
  62. package/dist/themes/slate.min.css +1 -0
  63. package/dist/vds.css +20313 -0
  64. package/dist/vds.min.css +1 -0
  65. package/package.json +64 -0
@@ -0,0 +1,1831 @@
1
+ /************************************************************
2
+ * VLAH DESIGN SYSTEM (VDS) - Forms
3
+ *
4
+ * Responsibilities:
5
+ * - Provide two parallel form architectures:
6
+ * A) Legacy VDS form controls: input, textarea, select,
7
+ * segmented controls, toggles, switches, radio/checkbox, input groups
8
+ * B) UFAL (Unified Form Abstraction Layer): form-control,
9
+ * wrapper elements, adaptive surfaces, loading/error states,
10
+ * prefix/suffix architecture, file/drop zones, and layout primitives
11
+ *
12
+ * - Supply semantic/interactive states:
13
+ * focus, hover, disabled, readonly, error, success, warning, info,
14
+ * dirty, loading, validated, invalidated
15
+ *
16
+ * - Define full visual contract for:
17
+ * control sizing tokens, label/caption hierarchy,
18
+ * density modes, inline/stack layouts, and responsive adaptations
19
+ *
20
+ * System Notes:
21
+ * - 100% token-driven: spacing, radii, borders, typography, motion
22
+ * - No JS assumptions; all behaviours (loading shimmer, validation highlights)
23
+ * are CSS-based
24
+ * - Legacy and UFAL architectures MUST co-exist in v1; no cross-overwrites
25
+ ************************************************************/
26
+
27
+ /* ---------------------------------------------------------
28
+ 1. FORM TOKEN DEFINITIONS
29
+ --------------------------------------------------------- */
30
+
31
+ [data-vds-form],
32
+ .vds-form {
33
+ --form-flow-gap-xs: var(--space-1);
34
+ --form-flow-textarea-min-height: 5rem;
35
+
36
+ --size-9: 2.75rem;
37
+ --size-10: 3.00rem;
38
+ --size-11: 3.25rem;
39
+
40
+ --control-min-height: var(--size-10);
41
+
42
+ --control-height-md: 40px;
43
+ }
44
+
45
+ [data-vds-form] .form--a .form-control,
46
+ .vds-form .form--a .form-control {
47
+ --control-min-height: var(--size-11);
48
+ }
49
+
50
+ [data-vds-form] .form--c .form-control,
51
+ .vds-form .form--c .form-control {
52
+ --control-min-height: var(--size-9);
53
+ }
54
+
55
+ /* ---------------------------------------------------------
56
+ 2. BASE FORM RESET
57
+ --------------------------------------------------------- */
58
+
59
+ input,
60
+ select,
61
+ textarea,
62
+ button {
63
+ font-family: inherit;
64
+ font-size: 100%;
65
+ line-height: inherit;
66
+ color: inherit;
67
+ }
68
+
69
+ input,
70
+ select,
71
+ textarea {
72
+ background-clip: padding-box;
73
+ }
74
+
75
+ input:focus,
76
+ select:focus,
77
+ textarea:focus {
78
+ outline: none;
79
+ }
80
+
81
+ /* ---------------------------------------------------------
82
+ 3. DENSITY LAYERS (A/B/C)
83
+ --------------------------------------------------------- */
84
+
85
+ .form--a .input,
86
+ .form--a .select,
87
+ .form--a .textarea {
88
+ padding: var(--space-4);
89
+ font-size: var(--text-md);
90
+ }
91
+
92
+ .form--a .form-check {
93
+ font-size: var(--text-md);
94
+ }
95
+
96
+ .form--a .segmented__option {
97
+ padding: var(--space-3) var(--space-5);
98
+ font-size: var(--text-md);
99
+ }
100
+
101
+ .form--a .file-upload__control {
102
+ padding: var(--space-5);
103
+ }
104
+
105
+ .form--c .input,
106
+ .form--c .select,
107
+ .form--c .textarea {
108
+ padding: var(--space-2);
109
+ font-size: var(--text-xs);
110
+ }
111
+
112
+ .form--c .form-check {
113
+ font-size: var(--text-xs);
114
+ }
115
+
116
+ .form--c .segmented__option {
117
+ padding: var(--space-1) var(--space-3);
118
+ font-size: var(--text-xs);
119
+ }
120
+
121
+ .form--c .file-upload__control {
122
+ padding: var(--space-3);
123
+ }
124
+
125
+ /* ---------------------------------------------------------
126
+ 4. FIELD WRAPPER
127
+ --------------------------------------------------------- */
128
+
129
+ .form-field {
130
+ display: flex;
131
+ flex-direction: column;
132
+ gap: var(--form-flow-gap-xs);
133
+ width: 100%;
134
+ }
135
+
136
+ .form-field--disabled {
137
+ opacity: 0.7;
138
+ pointer-events: none;
139
+ }
140
+
141
+ .form-label {
142
+ font-weight: 500;
143
+ color: var(--color-text);
144
+ }
145
+
146
+ .form-label--required::after {
147
+ content: " *";
148
+ color: var(--color-danger);
149
+ font-weight: 600;
150
+ }
151
+
152
+ input[type="search"]::-webkit-search-decoration,
153
+ input[type="search"]::-webkit-search-results-button,
154
+ input[type="search"]::-webkit-search-cancel-button {
155
+ -webkit-appearance: none;
156
+ appearance: none;
157
+ }
158
+
159
+ .form-label--sr-only {
160
+ position: absolute;
161
+ width: 1px;
162
+ height: 1px;
163
+ padding: 0;
164
+ margin: -1px;
165
+ overflow: hidden;
166
+ clip: rect(0, 0, 0, 0);
167
+ border: 0;
168
+ }
169
+
170
+ .form-help {
171
+ font-size: var(--text-xs);
172
+ color: var(--color-text-muted);
173
+ }
174
+
175
+ .form-error {
176
+ font-size: var(--text-xs);
177
+ color: var(--color-danger);
178
+ }
179
+
180
+ .form-field--error .form-label {
181
+ color: var(--color-danger);
182
+ }
183
+
184
+ .form-field--error .input,
185
+ .form-field--error .select,
186
+ .form-field--error .textarea {
187
+ border-color: var(--color-danger);
188
+ }
189
+
190
+ .form-field--error .input-group {
191
+ border-color: var(--color-danger);
192
+ }
193
+
194
+ .form-field--error .segmented {
195
+ border-color: var(--color-danger);
196
+ }
197
+
198
+ .form-field--error .slider {
199
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-danger-soft);
200
+ }
201
+
202
+ .form-field--error .file-upload__control {
203
+ border-color: var(--color-danger);
204
+ background-color: var(--color-danger-soft);
205
+ }
206
+
207
+ /* ---------------------------------------------------------
208
+ 5. BASE INPUT
209
+ --------------------------------------------------------- */
210
+
211
+ .input {
212
+ width: 100%;
213
+ padding: var(--space-3) var(--space-3);
214
+
215
+ border: var(--border-width) solid var(--color-border-subtle);
216
+ border-radius: var(--radius-md);
217
+ background-color: var(--color-surface);
218
+ color: var(--color-text);
219
+
220
+ transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s;
221
+ }
222
+
223
+ .input:focus {
224
+ border-color: var(--color-accent);
225
+ }
226
+
227
+ .input:focus-visible {
228
+ border-color: var(--focus-ring-color);
229
+ box-shadow: 0 0 0 var(--border-width-strong) var(--focus-ring-color);
230
+ }
231
+
232
+ .input:hover {
233
+ border-color: var(--color-border-strong);
234
+ }
235
+
236
+ .input:disabled,
237
+ .input--disabled {
238
+ background-color: var(--color-muted-bg);
239
+ color: var(--color-text-muted);
240
+ cursor: not-allowed;
241
+ }
242
+
243
+ .input[readonly],
244
+ .input--readonly {
245
+ background-color: var(--color-surface-subtle);
246
+ color: var(--color-text-muted);
247
+ border-style: dashed;
248
+ }
249
+
250
+ .input::-moz-placeholder {
251
+ color: var(--color-placeholder);
252
+ opacity: 1;
253
+ }
254
+
255
+ .input::placeholder {
256
+ color: var(--color-placeholder);
257
+ opacity: 1;
258
+ }
259
+
260
+ /* ---------------------------------------------------------
261
+ 5A. INPUT WITH ICONS
262
+ Pattern:
263
+ <div class="input-icon input-icon--left">
264
+ <span class="input-icon__icon">...</span>
265
+ <input class="input">
266
+ </div>
267
+ --------------------------------------------------------- */
268
+
269
+ .input-icon {
270
+ position: relative;
271
+ display: flex;
272
+ align-items: center;
273
+ width: 100%;
274
+ }
275
+
276
+ .input-icon .input {
277
+ width: 100%;
278
+ }
279
+
280
+ .input-icon--left .input {
281
+ padding-left: var(--space-8);
282
+ }
283
+
284
+ .input-icon--right .input {
285
+ padding-right: var(--space-8);
286
+ }
287
+
288
+ .input-icon--both .input {
289
+ padding-left: var(--space-8);
290
+ padding-right: var(--space-8);
291
+ }
292
+
293
+ .input-icon__icon {
294
+ position: absolute;
295
+ top: 50%;
296
+ transform: translateY(-50%);
297
+ display: inline-flex;
298
+ align-items: center;
299
+ justify-content: center;
300
+ width: var(--icon-sm);
301
+ height: var(--icon-sm);
302
+ color: var(--color-text-muted);
303
+ }
304
+
305
+ .input-icon--left .input-icon__icon {
306
+ left: var(--space-3);
307
+ }
308
+
309
+ .input-icon--right .input-icon__icon {
310
+ right: var(--space-3);
311
+ }
312
+
313
+ /* ---------------------------------------------------------
314
+ 6. TEXTAREA
315
+ --------------------------------------------------------- */
316
+
317
+ .textarea {
318
+ width: 100%;
319
+ resize: vertical;
320
+ min-height: var(--form-flow-textarea-min-height);
321
+ padding: var(--space-3);
322
+
323
+ border: var(--border-width) solid var(--color-border-subtle);
324
+ border-radius: var(--radius-md);
325
+ background-color: var(--color-surface);
326
+ color: var(--color-text);
327
+
328
+ transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s;
329
+ }
330
+
331
+ .textarea:focus {
332
+ border-color: var(--color-accent);
333
+ }
334
+
335
+ .textarea:focus-visible {
336
+ border-color: var(--focus-ring-color);
337
+ box-shadow: 0 0 0 var(--border-width-strong) var(--focus-ring-color);
338
+ }
339
+
340
+ .textarea:hover {
341
+ border-color: var(--color-border-strong);
342
+ }
343
+
344
+ .textarea:disabled,
345
+ .textarea--disabled {
346
+ background-color: var(--color-muted-bg);
347
+ color: var(--color-text-muted);
348
+ cursor: not-allowed;
349
+ }
350
+
351
+ .textarea[readonly],
352
+ .textarea--readonly {
353
+ background-color: var(--color-surface-subtle);
354
+ color: var(--color-text-muted);
355
+ border-style: dashed;
356
+ }
357
+
358
+ .textarea::-moz-placeholder {
359
+ color: var(--color-placeholder);
360
+ opacity: 1;
361
+ }
362
+
363
+ .textarea::placeholder {
364
+ color: var(--color-placeholder);
365
+ opacity: 1;
366
+ }
367
+
368
+ /* ---------------------------------------------------------
369
+ 7. SELECT (NATIVE + CUSTOM DROPDOWN ICON)
370
+ --------------------------------------------------------- */
371
+
372
+ .select {
373
+ width: 100%;
374
+ padding: var(--space-3) var(--space-4) var(--space-3) var(--space-3);
375
+
376
+ -webkit-appearance: none;
377
+
378
+ -moz-appearance: none;
379
+
380
+ appearance: none;
381
+ background-color: var(--color-surface);
382
+ color: var(--color-text);
383
+
384
+ border: var(--border-width) solid var(--color-border-subtle);
385
+ border-radius: var(--radius-md);
386
+
387
+ position: relative;
388
+ transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s;
389
+
390
+ background-image: linear-gradient(45deg, transparent 50%, var(--color-text-muted) 50%),
391
+ linear-gradient(135deg, var(--color-text-muted) 50%, transparent 50%);
392
+ background-position: calc(100% - var(--space-3)) center,
393
+ calc(100% - var(--space-2)) center;
394
+ background-size: 0.4rem 0.4rem;
395
+ background-repeat: no-repeat;
396
+ padding-right: var(--space-6);
397
+ }
398
+
399
+ .select:focus {
400
+ border-color: var(--color-accent);
401
+ }
402
+
403
+ .select:focus-visible {
404
+ border-color: var(--focus-ring-color);
405
+ box-shadow: 0 0 0 var(--border-width-strong) var(--focus-ring-color);
406
+ }
407
+
408
+ .select:hover {
409
+ border-color: var(--color-border-strong);
410
+ }
411
+
412
+ .select:disabled,
413
+ .select--disabled {
414
+ background-color: var(--color-muted-bg);
415
+ color: var(--color-text-muted);
416
+ cursor: not-allowed;
417
+ background-image: linear-gradient(45deg, transparent 50%, var(--color-text-muted) 50%),
418
+ linear-gradient(135deg, var(--color-text-muted) 50%, transparent 50%);
419
+ }
420
+
421
+ /* ---------------------------------------------------------
422
+ 8. CHECKBOXES & RADIOS
423
+ --------------------------------------------------------- */
424
+
425
+ .form-check {
426
+ display: flex;
427
+ align-items: center;
428
+ gap: var(--space-2);
429
+ margin-bottom: var(--space-3);
430
+ cursor: pointer;
431
+ font-size: var(--text-sm);
432
+ }
433
+
434
+ .form-check-group .form-check:last-child {
435
+ margin-bottom: 0;
436
+ }
437
+
438
+ .form-check--disabled {
439
+ opacity: 0.7;
440
+ cursor: not-allowed;
441
+ }
442
+
443
+ .form-check input {
444
+ width: 1.15rem;
445
+ height: 1.15rem;
446
+ cursor: pointer;
447
+ }
448
+
449
+ .checkbox {
450
+ -webkit-appearance: none;
451
+ -moz-appearance: none;
452
+ appearance: none;
453
+ border: var(--border-width) solid var(--color-border-subtle);
454
+ border-radius: var(--radius-sm);
455
+ background-color: var(--color-surface);
456
+ cursor: pointer;
457
+ position: relative;
458
+ transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s;
459
+ }
460
+
461
+ .checkbox:hover {
462
+ border-color: var(--color-border-strong);
463
+ }
464
+
465
+ .checkbox:focus-visible {
466
+ box-shadow: 0 0 0 var(--border-width-strong) var(--focus-ring-color);
467
+ outline: none;
468
+ }
469
+
470
+ .checkbox:checked {
471
+ border-color: var(--color-accent);
472
+ background-color: var(--color-accent-soft);
473
+ }
474
+
475
+ .checkbox:checked::after {
476
+ content: "";
477
+ position: absolute;
478
+ top: 50%;
479
+ left: 50%;
480
+ width: 0.55rem;
481
+ height: 0.55rem;
482
+ transform: translate(-50%, -50%);
483
+ background-color: var(--color-accent);
484
+ -webkit-mask-image: url("data:image/svg+xml,%3Csvg width='16' height='16' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolyline points='3 8 7 12 13 4'/%3E%3C/svg%3E");
485
+ mask-image: url("data:image/svg+xml,%3Csvg width='16' height='16' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolyline points='3 8 7 12 13 4'/%3E%3C/svg%3E");
486
+ -webkit-mask-size: cover;
487
+ mask-size: cover;
488
+ }
489
+
490
+ .checkbox:disabled {
491
+ background-color: var(--color-muted-bg);
492
+ border-color: var(--color-muted-border);
493
+ cursor: not-allowed;
494
+ }
495
+
496
+ .checkbox--error {
497
+ border-color: var(--color-danger);
498
+ }
499
+
500
+ .checkbox--warning {
501
+ border-color: var(--color-warning);
502
+ }
503
+
504
+ .checkbox--success {
505
+ border-color: var(--color-success);
506
+ }
507
+
508
+ .checkbox--info {
509
+ border-color: var(--color-info);
510
+ }
511
+
512
+ .radio {
513
+ -webkit-appearance: none;
514
+ -moz-appearance: none;
515
+ appearance: none;
516
+ border: var(--border-width) solid var(--color-border-subtle);
517
+ border-radius: 50%;
518
+ background-color: var(--color-surface);
519
+ cursor: pointer;
520
+ position: relative;
521
+ transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s;
522
+ }
523
+
524
+ .radio:hover {
525
+ border-color: var(--color-border-strong);
526
+ }
527
+
528
+ .radio:focus-visible {
529
+ box-shadow: 0 0 0 var(--border-width-strong) var(--focus-ring-color);
530
+ outline: none;
531
+ }
532
+
533
+ .radio:checked {
534
+ border-color: var(--color-accent);
535
+ background-color: var(--color-accent-soft);
536
+ }
537
+
538
+ .radio:checked::after {
539
+ content: "";
540
+ position: absolute;
541
+ top: 50%;
542
+ left: 50%;
543
+ width: 0.55rem;
544
+ height: 0.55rem;
545
+ background-color: var(--color-accent);
546
+ border-radius: 50%;
547
+ transform: translate(-50%, -50%);
548
+ }
549
+
550
+ .radio:disabled {
551
+ background-color: var(--color-muted-bg);
552
+ border-color: var(--color-muted-border);
553
+ cursor: not-allowed;
554
+ }
555
+
556
+ .radio--error {
557
+ border-color: var(--color-danger);
558
+ }
559
+
560
+ .radio--warning {
561
+ border-color: var(--color-warning);
562
+ }
563
+
564
+ .radio--success {
565
+ border-color: var(--color-success);
566
+ }
567
+
568
+ .radio--info {
569
+ border-color: var(--color-info);
570
+ }
571
+
572
+ /* ---------------------------------------------------------
573
+ 9. SWITCHES
574
+ Pattern: <input type="checkbox" class="switch">
575
+ --------------------------------------------------------- */
576
+
577
+ .switch {
578
+ -webkit-appearance: none;
579
+ -moz-appearance: none;
580
+ appearance: none;
581
+ border: var(--border-width) solid var(--color-border-subtle);
582
+ border-radius: 50%;
583
+ background-color: var(--color-surface);
584
+ cursor: pointer;
585
+ position: relative;
586
+ transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s;
587
+ width: 1.15rem;
588
+ height: 1.15rem;
589
+ }
590
+
591
+ .switch::after {
592
+ content: "";
593
+ position: absolute;
594
+ top: 22%;
595
+ left: 22%;
596
+ width: 0.55rem;
597
+ height: 0.55rem;
598
+ background-color: var(--color-accent);
599
+ border-radius: 50%;
600
+ transform: translate(-50%, -50%);
601
+ opacity: 0;
602
+ }
603
+
604
+ .switch:checked {
605
+ background-color: var(--color-accent-strong);
606
+ border: var(--border-width) solid var(--color-accent);
607
+ }
608
+
609
+ .switch:checked::after {
610
+ opacity: 1;
611
+ transform: scale(1);
612
+ background-color: var(--color-accent);
613
+ }
614
+
615
+ .switch:disabled {
616
+ opacity: 0.5;
617
+ cursor: not-allowed;
618
+ }
619
+
620
+ .switch:focus-visible {
621
+ outline: none;
622
+ box-shadow: 0 0 0 var(--border-width-strong) var(--focus-ring-color);
623
+ }
624
+
625
+ .switch--error {
626
+ background-color: var(--color-danger-soft);
627
+ }
628
+
629
+ .switch--warning {
630
+ background-color: var(--color-warning-soft);
631
+ }
632
+
633
+ .switch--success {
634
+ background-color: var(--color-success-soft);
635
+ }
636
+
637
+ .switch--info {
638
+ background-color: var(--color-info-soft);
639
+ }
640
+
641
+ .switch--error:checked {
642
+ background-color: var(--color-danger);
643
+ }
644
+
645
+ .switch--warning:checked {
646
+ background-color: var(--color-warning);
647
+ }
648
+
649
+ .switch--success:checked {
650
+ background-color: var(--color-success);
651
+ }
652
+
653
+ .switch--info:checked {
654
+ background-color: var(--color-info);
655
+ }
656
+
657
+ /* ---------------------------------------------------------
658
+ 10. INPUT GROUPS (ICONS + ADDONS)
659
+ --------------------------------------------------------- */
660
+
661
+ .input-group {
662
+ display: flex;
663
+ align-items: center;
664
+ border: var(--border-width) solid var(--color-border-subtle);
665
+ border-radius: var(--radius-md);
666
+ background-color: var(--color-surface);
667
+ overflow: hidden;
668
+ }
669
+
670
+ .input-group .input {
671
+ border: none;
672
+ flex: 1;
673
+ box-shadow: none;
674
+ }
675
+
676
+ .input-group-addon {
677
+ padding: 0 var(--space-3);
678
+ display: flex;
679
+ align-items: center;
680
+ color: var(--color-text-muted);
681
+ background-color: var(--color-surface);
682
+ border-right: var(--border-width) solid var(--color-border-subtle);
683
+ }
684
+
685
+ .input-group-addon + .input {
686
+ padding-left: var(--space-2);
687
+ }
688
+
689
+ .input-group-icon {
690
+ display: flex;
691
+ align-items: center;
692
+ padding: 0 var(--space-3);
693
+ color: var(--color-text-muted);
694
+ }
695
+
696
+ .input-group-icon .icon {
697
+ width: var(--icon-sm);
698
+ height: var(--icon-sm);
699
+ }
700
+
701
+ .input-group--error {
702
+ border-color: var(--color-danger);
703
+ }
704
+
705
+ .input-group--warning {
706
+ border-color: var(--color-warning);
707
+ }
708
+
709
+ .input-group--success {
710
+ border-color: var(--color-success);
711
+ }
712
+
713
+ .input-group--info {
714
+ border-color: var(--color-info);
715
+ }
716
+
717
+ .input-group--disabled {
718
+ opacity: 0.7;
719
+ pointer-events: none;
720
+ }
721
+
722
+ .input-group:focus-within {
723
+ border-color: var(--focus-ring-color);
724
+ box-shadow: 0 0 0 var(--border-width-strong) var(--focus-ring-color);
725
+ }
726
+
727
+ .input-group:hover {
728
+ border-color: var(--color-border-strong);
729
+ }
730
+
731
+ /* ---------------------------------------------------------
732
+ 11. SEGMENTED CONTROL
733
+ --------------------------------------------------------- */
734
+
735
+ .segmented {
736
+ display: flex;
737
+ width: 100%;
738
+ border: var(--border-width) solid var(--color-border-subtle);
739
+ border-radius: var(--radius-md);
740
+ overflow: hidden;
741
+ height: 2.5rem;
742
+ height: var(--control-height-md, 2.5rem);
743
+ background-color: var(--color-surface);
744
+ }
745
+
746
+ .segmented__option {
747
+ flex: 1 1 0;
748
+ text-align: center;
749
+ -webkit-appearance: none;
750
+ -moz-appearance: none;
751
+ appearance: none;
752
+ border: none;
753
+ font: inherit;
754
+ line-height: inherit;
755
+ padding: var(--space-2) var(--space-4);
756
+ cursor: pointer;
757
+ -webkit-user-select: none;
758
+ -moz-user-select: none;
759
+ user-select: none;
760
+ display: inline-flex;
761
+ align-items: center;
762
+ justify-content: center;
763
+ color: var(--color-text-muted);
764
+ background: var(--color-surface);
765
+ height: 100%;
766
+ transition: background-color 0.2s, color 0.2s;
767
+ }
768
+
769
+ .segmented__option:not(:last-child) {
770
+ border-right: var(--border-width) solid var(--color-border-subtle);
771
+ }
772
+
773
+ .segmented__option:hover {
774
+ background-color: var(--color-surface-subtle);
775
+ color: var(--color-text);
776
+ }
777
+
778
+ .segmented__option:focus-visible {
779
+ outline: none;
780
+ box-shadow: inset 0 0 0 var(--border-width-strong) var(--focus-ring-color);
781
+ }
782
+
783
+ .segmented__option--active {
784
+ background-color: var(--color-accent);
785
+ color: var(--color-on-accent);
786
+ font-weight: 600;
787
+ position: relative;
788
+ z-index: 1;
789
+ }
790
+
791
+ .segmented__option--active + .segmented__option {
792
+ border-left-color: transparent;
793
+ }
794
+
795
+ .segmented--disabled {
796
+ opacity: 0.6;
797
+ pointer-events: none;
798
+ }
799
+
800
+ .segmented__option--disabled {
801
+ cursor: not-allowed;
802
+ opacity: 0.7;
803
+ }
804
+
805
+ .segmented__option-icon {
806
+ width: var(--icon-sm);
807
+ height: var(--icon-sm);
808
+ margin-right: var(--space-2);
809
+ }
810
+
811
+ .segmented--error {
812
+ border-color: var(--color-danger);
813
+ }
814
+
815
+ .segmented--warning {
816
+ border-color: var(--color-warning);
817
+ }
818
+
819
+ .segmented--success {
820
+ border-color: var(--color-success);
821
+ }
822
+
823
+ .segmented--info {
824
+ border-color: var(--color-info);
825
+ }
826
+
827
+ .segmented--loading .segmented__option {
828
+ position: relative;
829
+ overflow: hidden;
830
+ }
831
+
832
+ .segmented--loading .segmented__option::after {
833
+ content: "";
834
+ position: absolute;
835
+ top: 0;
836
+ right: 0;
837
+ bottom: 0;
838
+ left: 0;
839
+ background-image: linear-gradient(
840
+ 90deg,
841
+ var(--color-muted-bg),
842
+ var(--color-surface),
843
+ var(--color-muted-bg)
844
+ );
845
+ background-size: 200% 100%;
846
+ animation: input-loading-shimmer 1.5s infinite;
847
+ }
848
+
849
+ /* ---------------------------------------------------------
850
+ 12. SLIDER
851
+ --------------------------------------------------------- */
852
+
853
+ .slider {
854
+ width: 100%;
855
+ -webkit-appearance: none;
856
+ -moz-appearance: none;
857
+ appearance: none;
858
+ height: var(--border-width-strong);
859
+ background-color: var(--slider-track-bg);
860
+ border-radius: var(--radius-sm);
861
+ cursor: pointer;
862
+ }
863
+
864
+ .slider:focus-visible {
865
+ outline: none;
866
+ box-shadow: 0 0 0 var(--border-width-strong) var(--focus-ring-color);
867
+ }
868
+
869
+ .slider:disabled {
870
+ cursor: not-allowed;
871
+ opacity: 0.7;
872
+ }
873
+
874
+ .slider::-webkit-slider-thumb {
875
+ -webkit-appearance: none;
876
+ appearance: none;
877
+ width: 1rem;
878
+ height: 1rem;
879
+ background: var(--slider-thumb-bg);
880
+ border-radius: 50%;
881
+ cursor: pointer;
882
+ }
883
+
884
+ .slider::-moz-range-thumb {
885
+ width: 1rem;
886
+ height: 1rem;
887
+ background: var(--slider-thumb-bg);
888
+ border-radius: 50%;
889
+ cursor: pointer;
890
+ }
891
+
892
+ .slider--error {
893
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-danger-soft);
894
+ }
895
+
896
+ .slider--error:focus-visible {
897
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-danger);
898
+ outline: none;
899
+ }
900
+
901
+ .slider--warning {
902
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-warning-soft);
903
+ }
904
+
905
+ .slider--warning:focus-visible {
906
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-warning);
907
+ outline: none;
908
+ }
909
+
910
+ .slider--success {
911
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-success-soft);
912
+ }
913
+
914
+ .slider--success:focus-visible {
915
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-success);
916
+ outline: none;
917
+ }
918
+
919
+ .slider--info {
920
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-info-soft);
921
+ }
922
+
923
+ .slider--info:focus-visible {
924
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-info);
925
+ outline: none;
926
+ }
927
+
928
+ /* ---------------------------------------------------------
929
+ 13. FILE UPLOAD (CUSTOM)
930
+ --------------------------------------------------------- */
931
+
932
+ .file-upload {
933
+ display: flex;
934
+ flex-direction: column;
935
+ gap: var(--space-2);
936
+ }
937
+
938
+ .file-upload input {
939
+ position: absolute;
940
+ width: 1px;
941
+ height: 1px;
942
+ padding: 0;
943
+ margin: -1px;
944
+ overflow: hidden;
945
+ clip: rect(0, 0, 0, 0);
946
+ white-space: nowrap;
947
+ border: 0;
948
+ }
949
+
950
+ .file-upload__control {
951
+ border: var(--border-width) dashed var(--color-border-subtle);
952
+ border-radius: var(--radius-md);
953
+ padding: var(--space-4);
954
+ text-align: center;
955
+ color: var(--color-text-soft);
956
+ cursor: pointer;
957
+ background-color: var(--color-surface);
958
+ transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s;
959
+ }
960
+
961
+ .file-upload__control:hover {
962
+ border-color: var(--color-border-strong);
963
+ background-color: var(--color-surface-subtle);
964
+ }
965
+
966
+ .file-upload__control:focus-visible {
967
+ outline: none;
968
+ box-shadow: 0 0 0 var(--border-width-strong) var(--focus-ring-color);
969
+ }
970
+
971
+ .file-upload__control--dragover {
972
+ border-color: var(--color-accent);
973
+ background-color: var(--color-accent-soft);
974
+ }
975
+
976
+ .file-upload__control--disabled {
977
+ opacity: 0.7;
978
+ cursor: not-allowed;
979
+ }
980
+
981
+ .file-upload__control--error {
982
+ border-color: var(--color-danger);
983
+ background-color: var(--color-danger-soft);
984
+ color: var(--color-danger-strong);
985
+ }
986
+
987
+ .file-upload__control--warning {
988
+ border-color: var(--color-warning);
989
+ background-color: var(--color-warning-soft);
990
+ color: var(--color-warning-strong);
991
+ }
992
+
993
+ .file-upload__control--success {
994
+ border-color: var(--color-success);
995
+ background-color: var(--color-success-soft);
996
+ color: var(--color-success-strong);
997
+ }
998
+
999
+ .file-upload__control--info {
1000
+ border-color: var(--color-info);
1001
+ background-color: var(--color-info-soft);
1002
+ color: var(--color-info-strong);
1003
+ }
1004
+
1005
+ .file-upload__control--loading {
1006
+ background-image: linear-gradient(
1007
+ 90deg,
1008
+ var(--color-muted-bg),
1009
+ var(--color-surface),
1010
+ var(--color-muted-bg)
1011
+ );
1012
+ background-size: 200% 100%;
1013
+ animation: input-loading-shimmer 1.5s infinite;
1014
+ }
1015
+
1016
+ /* ---------------------------------------------------------
1017
+ 14. FORM GRID / FORM ROWS
1018
+ --------------------------------------------------------- */
1019
+
1020
+ .form-row {
1021
+ display: flex;
1022
+ flex-wrap: wrap;
1023
+ gap: var(--space-4);
1024
+ }
1025
+
1026
+ .form-row--two {
1027
+ display: grid;
1028
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1029
+ grid-gap: var(--space-4);
1030
+ gap: var(--space-4);
1031
+ }
1032
+
1033
+ .form-grid {
1034
+ display: grid;
1035
+ grid-gap: var(--space-4);
1036
+ gap: var(--space-4);
1037
+ }
1038
+
1039
+ .form-grid--two {
1040
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1041
+ }
1042
+
1043
+ .form-grid--three {
1044
+ grid-template-columns: repeat(3, minmax(0, 1fr));
1045
+ }
1046
+
1047
+ .form-grid--four {
1048
+ grid-template-columns: repeat(4, minmax(0, 1fr));
1049
+ }
1050
+
1051
+ @media (max-width: 768px) {
1052
+ .form-grid--two,
1053
+ .form-grid--three,
1054
+ .form-grid--four {
1055
+ grid-template-columns: 1fr;
1056
+ }
1057
+ }
1058
+
1059
+ /* ---------------------------------------------------------
1060
+ 15. VALIDATION STATES (INPUT / SELECT / TEXTAREA)
1061
+ --------------------------------------------------------- */
1062
+
1063
+ .input--error,
1064
+ .select--error,
1065
+ .textarea--error {
1066
+ border-color: var(--color-danger);
1067
+ }
1068
+
1069
+ .input--error:focus-visible,
1070
+ .select--error:focus-visible,
1071
+ .textarea--error:focus-visible {
1072
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-danger-soft);
1073
+ }
1074
+
1075
+ .input--success,
1076
+ .select--success,
1077
+ .textarea--success {
1078
+ border-color: var(--color-success);
1079
+ }
1080
+
1081
+ .input--success:focus-visible,
1082
+ .select--success:focus-visible,
1083
+ .textarea--success:focus-visible {
1084
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-success-soft);
1085
+ }
1086
+
1087
+ .input--warning,
1088
+ .select--warning,
1089
+ .textarea--warning {
1090
+ border-color: var(--color-warning);
1091
+ }
1092
+
1093
+ .input--warning:focus-visible,
1094
+ .select--warning:focus-visible,
1095
+ .textarea--warning:focus-visible {
1096
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-warning-soft);
1097
+ }
1098
+
1099
+ .input--info,
1100
+ .select--info,
1101
+ .textarea--info {
1102
+ border-color: var(--color-info);
1103
+ }
1104
+
1105
+ .input--info:focus-visible,
1106
+ .select--info:focus-visible,
1107
+ .textarea--info:focus-visible {
1108
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-info-soft);
1109
+ }
1110
+
1111
+ /* ---------------------------------------------------------
1112
+ 16. FIELD META (HELP, ERROR, COUNTER, ICONS, LAYOUT)
1113
+ --------------------------------------------------------- */
1114
+
1115
+ .form-meta {
1116
+ display: flex;
1117
+ align-items: flex-start;
1118
+ justify-content: space-between;
1119
+ gap: var(--form-flow-gap-xs);
1120
+ margin-top: var(--space-1);
1121
+ }
1122
+
1123
+ .form-meta--stacked {
1124
+ flex-direction: column;
1125
+ align-items: flex-start;
1126
+ }
1127
+
1128
+ .form-meta--inline {
1129
+ flex-direction: row;
1130
+ align-items: center;
1131
+ }
1132
+
1133
+ .form-meta__messages {
1134
+ display: flex;
1135
+ flex-direction: column;
1136
+ gap: var(--space-1);
1137
+ min-width: 0;
1138
+ }
1139
+
1140
+ .form-counter {
1141
+ margin-left: auto;
1142
+ font-size: var(--text-xs);
1143
+ font-family: var(--font-family-mono), monospace;
1144
+ color: var(--color-text-muted);
1145
+ white-space: nowrap;
1146
+ }
1147
+
1148
+ .form-counter--warning {
1149
+ color: var(--color-warning);
1150
+ }
1151
+
1152
+ .form-counter--danger {
1153
+ color: var(--color-danger);
1154
+ }
1155
+
1156
+ .form-field--error .form-counter {
1157
+ color: var(--color-danger);
1158
+ }
1159
+
1160
+ .form-control-with-icon {
1161
+ position: relative;
1162
+ display: inline-flex;
1163
+ width: 100%;
1164
+ }
1165
+
1166
+ .form-control-with-icon .input,
1167
+ .form-control-with-icon .select,
1168
+ .form-control-with-icon .textarea {
1169
+ width: 100%;
1170
+ padding-right: calc(var(--space-8) + var(--space-1));
1171
+ }
1172
+
1173
+ .form-status-icon {
1174
+ position: absolute;
1175
+ right: var(--space-3);
1176
+ top: 50%;
1177
+ transform: translateY(-50%);
1178
+ display: inline-flex;
1179
+ align-items: center;
1180
+ justify-content: center;
1181
+ width: var(--icon-sm);
1182
+ height: var(--icon-sm);
1183
+ color: var(--color-text-muted);
1184
+ pointer-events: none;
1185
+ }
1186
+
1187
+ .form-field--error .form-status-icon {
1188
+ color: var(--color-danger);
1189
+ }
1190
+
1191
+ .form-field--success .form-status-icon {
1192
+ color: var(--color-success);
1193
+ }
1194
+
1195
+ .form-field--warning .form-status-icon {
1196
+ color: var(--color-warning);
1197
+ }
1198
+
1199
+ .form-field--info .form-status-icon {
1200
+ color: var(--color-info);
1201
+ }
1202
+
1203
+ .form-field--success .form-label {
1204
+ color: var(--color-success);
1205
+ }
1206
+
1207
+ .form-field--success .input,
1208
+ .form-field--success .select,
1209
+ .form-field--success .textarea,
1210
+ .form-field--success .input-group {
1211
+ border-color: var(--color-success);
1212
+ }
1213
+
1214
+ .form-field--warning .form-label {
1215
+ color: var(--color-warning);
1216
+ }
1217
+
1218
+ .form-field--warning .input,
1219
+ .form-field--warning .select,
1220
+ .form-field--warning .textarea,
1221
+ .form-field--warning .input-group {
1222
+ border-color: var(--color-warning);
1223
+ }
1224
+
1225
+ .form-field--info .form-label {
1226
+ color: var(--color-info);
1227
+ }
1228
+
1229
+ .form-field--info .input,
1230
+ .form-field--info .select,
1231
+ .form-field--info .textarea,
1232
+ .form-field--info .input-group {
1233
+ border-color: var(--color-info);
1234
+ }
1235
+
1236
+ .form-field--horizontal {
1237
+ display: grid;
1238
+ grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
1239
+ grid-column-gap: var(--space-4);
1240
+ -moz-column-gap: var(--space-4);
1241
+ column-gap: var(--space-4);
1242
+ align-items: flex-start;
1243
+ }
1244
+
1245
+ .form-field__label {
1246
+ padding-top: var(--space-1);
1247
+ }
1248
+
1249
+ .form-field__control {
1250
+ display: flex;
1251
+ flex-direction: column;
1252
+ gap: var(--form-flow-gap-xs);
1253
+ }
1254
+
1255
+ @media (max-width: 768px) {
1256
+ .form-field--horizontal {
1257
+ grid-template-columns: 1fr;
1258
+ }
1259
+
1260
+ .form-field__label {
1261
+ padding-top: 0;
1262
+ }
1263
+ }
1264
+
1265
+ .input--loading,
1266
+ .select--loading,
1267
+ .textarea--loading {
1268
+ background-image: linear-gradient(
1269
+ 90deg,
1270
+ var(--color-muted-bg),
1271
+ var(--color-surface),
1272
+ var(--color-muted-bg)
1273
+ );
1274
+ background-size: 200% 100%;
1275
+ animation: input-loading-shimmer 1.5s infinite;
1276
+ }
1277
+
1278
+ @keyframes input-loading-shimmer {
1279
+ 0% {
1280
+ background-position: -150% 0;
1281
+ }
1282
+ 100% {
1283
+ background-position: 150% 0;
1284
+ }
1285
+ }
1286
+
1287
+ /* ---------------------------------------------------------
1288
+ 17. FORMS INSIDE MODALS / PANELS
1289
+ --------------------------------------------------------- */
1290
+
1291
+ .modal .form-field {
1292
+ margin-bottom: var(--space-3);
1293
+ }
1294
+
1295
+ /* ---------------------------------------------------------
1296
+ 18. FORM-LEVEL MESSAGES (top of form)
1297
+ --------------------------------------------------------- */
1298
+
1299
+ .form-message {
1300
+ width: 100%;
1301
+ padding: var(--space-4) var(--space-6);
1302
+ border-radius: var(--radius-md);
1303
+ border: var(--border-width) solid var(--color-border-subtle);
1304
+ background-color: var(--color-surface-subtle);
1305
+ font-size: var(--text-sm);
1306
+ display: flex;
1307
+ align-items: flex-start;
1308
+ gap: var(--space-3);
1309
+ }
1310
+
1311
+ .form-message__icon {
1312
+ width: 1.25rem;
1313
+ height: 1.25rem;
1314
+ flex-shrink: 0;
1315
+ stroke: currentColor;
1316
+ fill: none;
1317
+ }
1318
+
1319
+ .form-message__content {
1320
+ display: flex;
1321
+ flex-direction: column;
1322
+ gap: var(--space-1);
1323
+ }
1324
+
1325
+ .form-message--neutral {
1326
+ border-color: var(--color-muted-border);
1327
+ background-color: var(--color-muted-bg);
1328
+ color: var(--color-text-muted);
1329
+ }
1330
+
1331
+ .form-message--error {
1332
+ background-color: var(--semantic-error-bg-strong, var(--color-danger-soft));
1333
+ border-color: var(--semantic-error-border-strong, var(--color-danger));
1334
+ color: var(--semantic-error-text-strong, var(--color-danger-strong));
1335
+ }
1336
+
1337
+ .form-message--info {
1338
+ background-color: var(--semantic-info-bg-strong, var(--color-info-soft));
1339
+ border-color: var(--semantic-info-border-strong, var(--color-info));
1340
+ color: var(--semantic-info-text-strong, var(--color-info-strong));
1341
+ }
1342
+
1343
+ .form-message--success {
1344
+ background-color: var(--semantic-success-bg-strong, var(--color-success-soft));
1345
+ border-color: var(--semantic-success-border-strong, var(--color-success));
1346
+ color: var(--semantic-success-text-strong, var(--color-success-strong));
1347
+ }
1348
+
1349
+ .form-message--warning {
1350
+ background-color: var(--semantic-warning-bg-strong, var(--color-warning-soft));
1351
+ border-color: var(--semantic-warning-border-strong, var(--color-warning));
1352
+ color: var(--semantic-warning-text-strong, var(--color-warning-strong));
1353
+ }
1354
+
1355
+ /* ---------------------------------------------------------
1356
+ 19. FIELD-LEVEL STATE MESSAGES (below inputs)
1357
+ --------------------------------------------------------- */
1358
+
1359
+ .form-field-message {
1360
+ font-size: var(--text-xs);
1361
+ margin-top: var(--space-1);
1362
+ display: flex;
1363
+ align-items: center;
1364
+ gap: var(--space-1);
1365
+ }
1366
+
1367
+ .form-field-message--neutral {
1368
+ color: var(--color-text-muted);
1369
+ }
1370
+
1371
+ .form-field-message--error {
1372
+ color: var(--semantic-error-text-strong, var(--color-danger-strong));
1373
+ }
1374
+
1375
+ .form-field-message--warning {
1376
+ color: var(--semantic-warning-text-strong, var(--color-warning-strong));
1377
+ }
1378
+
1379
+ .form-field-message--info {
1380
+ color: var(--semantic-info-text-strong, var(--color-info-strong));
1381
+ }
1382
+
1383
+ .form-field-message--success {
1384
+ color: var(--semantic-success-text-strong, var(--color-success-strong));
1385
+ }
1386
+
1387
+ .form-field-message__icon {
1388
+ width: 1rem;
1389
+ height: 1rem;
1390
+ stroke: currentColor;
1391
+ fill: none;
1392
+ flex-shrink: 0;
1393
+ }
1394
+
1395
+ /* ---------------------------------------------------------
1396
+ 20. HORIZONTAL CHECKBOXES / RADIOS
1397
+ --------------------------------------------------------- */
1398
+
1399
+ .form-check-inline {
1400
+ display: inline-flex;
1401
+ align-items: center;
1402
+ gap: var(--space-2);
1403
+ margin-right: var(--space-6);
1404
+ cursor: pointer;
1405
+ }
1406
+
1407
+ .form-check-group {
1408
+ display: flex;
1409
+ flex-direction: column;
1410
+ gap: var(--space-1);
1411
+ align-items: flex-start;
1412
+ }
1413
+
1414
+ .form-check-group--horizontal {
1415
+ flex-direction: row;
1416
+ flex-wrap: wrap;
1417
+ gap: var(--space-6);
1418
+ align-items: center;
1419
+ }
1420
+
1421
+ .form-check-group--horizontal .form-check {
1422
+ margin-right: var(--space-6);
1423
+ margin-bottom: var(--space-2);
1424
+ }
1425
+
1426
+ /* -----------------------------------------------
1427
+ 21. FORM SECTION STATES
1428
+ Add semantic state styling for entire sections.
1429
+ Intended for wrapping form-row or form-grid.
1430
+ ------------------------------------------------ */
1431
+
1432
+ .form-section--error {
1433
+ padding: var(--space-3);
1434
+ border-left: var(--border-width-strong) solid var(--semantic-error-border-strong, var(--color-danger));
1435
+ background-color: transparent;
1436
+ background-color: var(--semantic-error-bg-strong, transparent);
1437
+ }
1438
+
1439
+ .form-section--warning {
1440
+ padding: var(--space-3);
1441
+ border-left: var(--border-width-strong) solid var(--semantic-warning-border-strong, var(--color-warning));
1442
+ background-color: transparent;
1443
+ background-color: var(--semantic-warning-bg-strong, transparent);
1444
+ }
1445
+
1446
+ .form-section--success {
1447
+ padding: var(--space-3);
1448
+ border-left: var(--border-width-strong) solid var(--semantic-success-border-strong, var(--color-success));
1449
+ background-color: transparent;
1450
+ background-color: var(--semantic-success-bg-strong, transparent);
1451
+ }
1452
+
1453
+ .form-section--info {
1454
+ padding: var(--space-3);
1455
+ border-left: var(--border-width-strong) solid var(--semantic-info-border-strong, var(--color-info));
1456
+ background-color: transparent;
1457
+ background-color: var(--semantic-info-bg-strong, transparent);
1458
+ }
1459
+
1460
+ .form-section--error:not(:last-child),
1461
+ .form-section--warning:not(:last-child),
1462
+ .form-section--success:not(:last-child),
1463
+ .form-section--info:not(:last-child) {
1464
+ margin-bottom: var(--space-4);
1465
+ }
1466
+
1467
+ /* -----------------------------------------------
1468
+ 22. ARIA hooks for validation
1469
+ ------------------------------------------------ */
1470
+
1471
+ .input[aria-invalid="true"],
1472
+ .select[aria-invalid="true"],
1473
+ .textarea[aria-invalid="true"] {
1474
+ border-color: var(--color-danger);
1475
+ }
1476
+
1477
+ .input[aria-invalid="true"]:focus-visible,
1478
+ .select[aria-invalid="true"]:focus-visible,
1479
+ .textarea[aria-invalid="true"]:focus-visible {
1480
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-danger-soft);
1481
+ }
1482
+
1483
+ /* ----------------------------------------------------------
1484
+ 23. Base form control primitive (UFAL)
1485
+ ---------------------------------------------------------- */
1486
+
1487
+ .form-control {
1488
+ display: block;
1489
+ width: 100%;
1490
+ min-height: var(--control-min-height);
1491
+
1492
+ margin: 0;
1493
+ box-sizing: border-box;
1494
+ }
1495
+
1496
+ .form-control-wrapper {
1497
+ position: relative;
1498
+ width: 100%;
1499
+ display: flex;
1500
+ align-items: center;
1501
+ }
1502
+
1503
+ .form-control-wrapper > .form-control {
1504
+ flex: 1 1 auto;
1505
+ }
1506
+
1507
+ /* ----------------------------------------------------------
1508
+ 23A. State modifiers
1509
+ ---------------------------------------------------------- */
1510
+
1511
+ .form-control--loading {
1512
+ cursor: progress;
1513
+ opacity: 0.55;
1514
+ pointer-events: none;
1515
+ }
1516
+
1517
+ .form-control--disabled {
1518
+ opacity: 0.45;
1519
+ pointer-events: none;
1520
+ }
1521
+
1522
+ .form-control--readonly {
1523
+ opacity: 0.75;
1524
+ cursor: default;
1525
+ }
1526
+
1527
+ .form-control--error {
1528
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-danger);
1529
+ }
1530
+
1531
+ .form-control--warning {
1532
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-warning);
1533
+ }
1534
+
1535
+ .form-control--success {
1536
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-success);
1537
+ }
1538
+
1539
+ .form-control--info {
1540
+ box-shadow: 0 0 0 var(--border-width-strong) var(--color-info);
1541
+ }
1542
+
1543
+ .form-control--password {
1544
+ padding-right: calc(var(--space-8) + var(--space-2));
1545
+ }
1546
+
1547
+ .form-control-wrapper[data-icon="right"] .form-control--password {
1548
+ padding-right: calc(var(--space-8) + var(--space-2));
1549
+ }
1550
+
1551
+ .form-control--password:focus {
1552
+ border-color: var(--color-accent);
1553
+ }
1554
+
1555
+ .form-control--password::-moz-placeholder {
1556
+ color: var(--color-placeholder);
1557
+ }
1558
+
1559
+ .form-control--password::placeholder {
1560
+ color: var(--color-placeholder);
1561
+ }
1562
+
1563
+ /* ----------------------------------------------------------
1564
+ 23B. Icon-inside-input patterns
1565
+ ---------------------------------------------------------- */
1566
+
1567
+ .form-control-wrapper[data-icon="left"] .form-control {
1568
+ padding-left: calc(var(--space-7) + var(--space-2));
1569
+ }
1570
+
1571
+ .form-control-wrapper[data-icon="left"] .form-control-icon {
1572
+ position: absolute;
1573
+ left: var(--space-2);
1574
+ display: flex;
1575
+ align-items: center;
1576
+ }
1577
+
1578
+ .form-control-wrapper[data-icon="right"] .form-control {
1579
+ padding-right: calc(var(--space-7) + var(--space-2));
1580
+ }
1581
+
1582
+ .form-control-wrapper[data-icon="right"] .form-control-icon {
1583
+ position: absolute;
1584
+ right: var(--space-2);
1585
+ display: flex;
1586
+ align-items: center;
1587
+ }
1588
+
1589
+ .form-control-icon {
1590
+ font-size: var(--text-md);
1591
+ color: var(--color-text-muted);
1592
+ pointer-events: none;
1593
+ }
1594
+
1595
+ /* ----------------------------------------------------------
1596
+ 23C. Loading overlay animation
1597
+ ---------------------------------------------------------- */
1598
+
1599
+ .form-control--loading::after {
1600
+ content: "";
1601
+ position: absolute;
1602
+ top: 0;
1603
+ right: 0;
1604
+ bottom: 0;
1605
+ left: 0;
1606
+ border-radius: inherit;
1607
+ background: var(--color-surface-subtle);
1608
+ animation: formControlLoading 1.5s ease-in-out infinite;
1609
+ }
1610
+
1611
+ @keyframes formControlLoading {
1612
+ 0% {
1613
+ opacity: .35;
1614
+ }
1615
+ 50% {
1616
+ opacity: .6;
1617
+ }
1618
+ 100% {
1619
+ opacity: .35;
1620
+ }
1621
+ }
1622
+
1623
+ /* ----------------------------------------------------------
1624
+ 23D. File upload primitives (UFAL)
1625
+ ---------------------------------------------------------- */
1626
+
1627
+ /* Base dashed file control (rarely exposed directly; internal primitive) */
1628
+
1629
+ .form-control--file {
1630
+ position: relative;
1631
+ padding: var(--space-3);
1632
+ border: var(--border-width) dashed var(--color-border-subtle);
1633
+ border-radius: var(--radius-md);
1634
+ background-color: var(--color-surface);
1635
+ color: var(--color-text-muted);
1636
+ cursor: pointer;
1637
+ transition: border-color .2s, background-color .2s;
1638
+ }
1639
+
1640
+ .form-control--file[type="file"] {
1641
+ padding: 0;
1642
+ border: none;
1643
+ background: none;
1644
+ position: static;
1645
+ opacity: 1;
1646
+ }
1647
+
1648
+ /* ----------------------------------------------------------
1649
+ 23E. UFAL Drop Surface (corrected)
1650
+ ---------------------------------------------------------- */
1651
+
1652
+ .form-control-file-surface {
1653
+ position: relative; /* ★ FIX: contain absolute input */
1654
+ display: flex;
1655
+ flex-direction: column;
1656
+ gap: var(--space-2);
1657
+ align-items: center;
1658
+ justify-content: center;
1659
+ padding: var(--space-6);
1660
+
1661
+ border: var(--border-width) dashed var(--color-border-subtle);
1662
+ border-radius: var(--radius-md);
1663
+ background-color: var(--color-surface);
1664
+ cursor: pointer;
1665
+
1666
+ transition: border-color .2s, background-color .2s;
1667
+ }
1668
+
1669
+ .form-control-file-surface input[type="file"] {
1670
+ position: absolute;
1671
+ top: 0;
1672
+ right: 0;
1673
+ bottom: 0;
1674
+ left: 0;
1675
+ opacity: 0;
1676
+ cursor: pointer;
1677
+ }
1678
+
1679
+ .form-control-file-surface:hover {
1680
+ border-color: var(--color-border-strong);
1681
+ background-color: var(--color-surface-subtle);
1682
+ }
1683
+
1684
+ .form-control-file-surface--dragover {
1685
+ border-color: var(--color-accent);
1686
+ background-color: var(--color-accent-soft);
1687
+ }
1688
+
1689
+ .form-control-file-surface--disabled {
1690
+ opacity: .65;
1691
+ cursor: not-allowed;
1692
+ }
1693
+
1694
+ .form-control-file-surface--error {
1695
+ border-color: var(--color-danger);
1696
+ background-color: var(--color-danger-soft);
1697
+ }
1698
+
1699
+ .form-control-file-surface--warning {
1700
+ border-color: var(--color-warning);
1701
+ background-color: var(--color-warning-soft);
1702
+ }
1703
+
1704
+ .form-control-file-surface--success {
1705
+ border-color: var(--color-success);
1706
+ background-color: var(--color-success-soft);
1707
+ }
1708
+
1709
+ .form-control-file-surface--info {
1710
+ border-color: var(--color-info);
1711
+ background-color: var(--color-info-soft);
1712
+ }
1713
+
1714
+ /* ----------------------------------------------------------
1715
+ 23F. Inline “button-as-trigger” upload
1716
+ ---------------------------------------------------------- */
1717
+
1718
+ .file-upload-inline {
1719
+ display: inline-flex;
1720
+ align-items: center;
1721
+ gap: var(--space-2);
1722
+ }
1723
+
1724
+ .file-upload-inline__input {
1725
+ position: absolute;
1726
+ width: 1px;
1727
+ height: 1px;
1728
+ padding: 0;
1729
+ margin: -1px;
1730
+ overflow: hidden;
1731
+ clip: rect(0, 0, 0, 0);
1732
+ white-space: nowrap;
1733
+ border: 0;
1734
+ }
1735
+
1736
+ .file-upload-inline__label {
1737
+ cursor: pointer;
1738
+ display: inline-flex;
1739
+ align-items: center;
1740
+ justify-content: center;
1741
+ }
1742
+
1743
+ /* ----------------------------------------------------------
1744
+ 23G. Shared inner patterns
1745
+ ---------------------------------------------------------- */
1746
+
1747
+ .file-upload,
1748
+ .file-upload * {
1749
+ box-sizing: border-box;
1750
+ }
1751
+
1752
+ .file-upload {
1753
+ display: flex;
1754
+ flex-direction: column;
1755
+ gap: var(--space-2);
1756
+ width: 100%;
1757
+ }
1758
+
1759
+ /* Loading shimmer on drop surface */
1760
+
1761
+ .form-control-file-surface.form-control--loading::after {
1762
+ content: "";
1763
+ position: absolute;
1764
+ top: 0;
1765
+ right: 0;
1766
+ bottom: 0;
1767
+ left: 0;
1768
+ border-radius: inherit;
1769
+ background-image: linear-gradient(
1770
+ 90deg,
1771
+ var(--color-muted-bg),
1772
+ var(--color-surface),
1773
+ var(--color-muted-bg)
1774
+ );
1775
+ background-size: 200% 100%;
1776
+ animation: input-loading-shimmer 1.5s infinite;
1777
+ }
1778
+
1779
+ .form-control-file-icon {
1780
+ font-size: var(--text-lg);
1781
+ color: var(--color-text-muted);
1782
+ }
1783
+
1784
+ .form-control-file-label {
1785
+ font-size: var(--text-sm);
1786
+ color: var(--color-text);
1787
+ }
1788
+
1789
+ .form-control-file-hint {
1790
+ font-size: var(--text-xs);
1791
+ color: var(--color-text-muted);
1792
+ }
1793
+
1794
+ .slider--error:focus-visible,
1795
+ .input[aria-invalid="true"]:focus-visible,
1796
+ .select[aria-invalid="true"]:focus-visible,
1797
+ .textarea[aria-invalid="true"]:focus-visible,
1798
+ .form-control--error:focus-visible {
1799
+ box-shadow: 0 0 0 var(--border-width-strong) var(--semantic-error-border-strong, var(--color-danger));
1800
+ }
1801
+
1802
+ .checkbox:checked,
1803
+ .radio:checked,
1804
+ .switch:checked {
1805
+ background-color: var(--accent-soft-surface, var(--color-accent-soft));
1806
+ border-color: var(--accent-soft-border, var(--color-accent));
1807
+ box-shadow: 0 0 0 1px transparent;
1808
+ box-shadow: 0 0 0 1px var(--accent-soft-shadow, transparent);
1809
+ color: var(--accent-soft-on, var(--color-on-accent));
1810
+ }
1811
+
1812
+ .checkbox:checked::after,
1813
+ .radio:checked::after,
1814
+ .switch:checked::after {
1815
+ background-color: var(--accent-soft-border, var(--color-accent));
1816
+ }
1817
+
1818
+ .checkbox:checked:hover,
1819
+ .radio:checked:hover,
1820
+ .switch:checked:hover {
1821
+ background-color: var(--accent-soft-surface-strong, var(--accent-soft-surface));
1822
+ border-color: var(--accent-soft-border, var(--color-accent));
1823
+ }
1824
+
1825
+ .checkbox:checked:disabled,
1826
+ .radio:checked:disabled,
1827
+ .switch:checked:disabled {
1828
+ background-color: var(--color-surface-subtle);
1829
+ border-color: var(--color-border-subtle);
1830
+ opacity: 0.6;
1831
+ }