minora 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.
@@ -0,0 +1,700 @@
1
+ /* ============================================================
2
+ ELEGANT MINIMALIST UI KIT — Form Validation System
3
+ form-validation.css
4
+
5
+ Covers:
6
+ - Inline field validation (error/success/warning)
7
+ - Password strength indicator
8
+ - Form-level alert banner
9
+ - Form success state
10
+ - Validation message animations (slide + fade)
11
+ - Field highlight effects
12
+ ============================================================ */
13
+
14
+ /* ═══════════════════════════════════════════════════════════
15
+ FIELD ERROR / WARNING / SUCCESS MESSAGES
16
+ Animation: slide down + fade in on appear
17
+ ═══════════════════════════════════════════════════════════ */
18
+
19
+ .field-error-message,
20
+ .field-warning-message,
21
+ .field-success-message {
22
+ display: flex;
23
+ align-items: flex-start;
24
+ gap: var(--space-1);
25
+ margin-top: var(--space-1-5);
26
+ font-family: var(--font-sans);
27
+ font-size: var(--text-xs);
28
+ font-weight: var(--font-medium);
29
+ line-height: var(--leading-tight);
30
+ opacity: 0;
31
+ transform: translateY(-4px);
32
+ animation: field-msg-in var(--duration-normal) var(--ease-out) forwards;
33
+ }
34
+
35
+ @keyframes field-msg-in {
36
+ to {
37
+ opacity: 1;
38
+ transform: translateY(0);
39
+ }
40
+ }
41
+
42
+ .field-error-message.fade-out,
43
+ .field-warning-message.fade-out,
44
+ .field-success-message.fade-out {
45
+ animation: field-msg-out var(--duration-normal) var(--ease-in-out) forwards;
46
+ }
47
+
48
+ @keyframes field-msg-out {
49
+ to {
50
+ opacity: 0;
51
+ transform: translateY(-4px);
52
+ }
53
+ }
54
+
55
+ .field-error-message svg,
56
+ .field-warning-message svg,
57
+ .field-success-message svg {
58
+ width: var(--space-3);
59
+ height: var(--space-3);
60
+ flex-shrink: 0;
61
+ margin-top: var(--space-0-25);
62
+ }
63
+
64
+ /* Error */
65
+ .field-error-message {
66
+ color: var(--color-error);
67
+ }
68
+
69
+ .field-error-message svg {
70
+ color: var(--color-error);
71
+ }
72
+
73
+ /* Warning */
74
+ .field-warning-message {
75
+ color: var(--color-warning);
76
+ }
77
+
78
+ .field-warning-message svg {
79
+ color: var(--color-warning);
80
+ }
81
+
82
+ /* Success */
83
+ .field-success-message {
84
+ color: var(--color-success);
85
+ }
86
+
87
+ .field-success-message svg {
88
+ color: var(--color-success);
89
+ }
90
+
91
+ /* ═══════════════════════════════════════════════════════════
92
+ INPUT VALIDATION STATES
93
+ Applies to .input-wrapper from input.css
94
+ ═══════════════════════════════════════════════════════════ */
95
+
96
+ /* Error — override input.css defaults */
97
+ .input-wrapper.field-error {
98
+ border-color: var(--color-error);
99
+ }
100
+
101
+ .input-wrapper.field-error .input {
102
+ color: var(--input-text-color);
103
+ }
104
+
105
+ .input-wrapper.field-error:focus-within {
106
+ border-color: var(--color-error);
107
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--color-error-border);
108
+ }
109
+
110
+ /* Validation icon inside input (trailing position) */
111
+ .field-validation-icon {
112
+ display: none;
113
+ flex-shrink: 0;
114
+ width: var(--space-4);
115
+ height: var(--space-4);
116
+ margin-right: var(--space-3);
117
+ animation: field-msg-in var(--duration-normal) var(--ease-out) forwards;
118
+ }
119
+
120
+ .input-wrapper.field-error .field-validation-icon.icon-error {
121
+ display: inline-flex;
122
+ color: var(--color-error);
123
+ }
124
+
125
+ .input-wrapper.field-success .field-validation-icon.icon-success {
126
+ display: inline-flex;
127
+ color: var(--color-success);
128
+ }
129
+
130
+ .input-wrapper.field-warning .field-validation-icon.icon-warning {
131
+ display: inline-flex;
132
+ color: var(--color-warning);
133
+ }
134
+
135
+ /* Success state */
136
+ .input-wrapper.field-success {
137
+ border-color: var(--color-success);
138
+ }
139
+
140
+ .input-wrapper.field-success:focus-within {
141
+ border-color: var(--color-success);
142
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--color-success-border);
143
+ }
144
+
145
+ /* Warning state */
146
+ .input-wrapper.field-warning {
147
+ border-color: var(--color-warning);
148
+ }
149
+
150
+ .input-wrapper.field-warning:focus-within {
151
+ border-color: var(--color-warning);
152
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--color-warning-border);
153
+ }
154
+
155
+ /* ═══════════════════════════════════════════════════════════
156
+ SELECT VALIDATION STATES
157
+ ═══════════════════════════════════════════════════════════ */
158
+
159
+ .select.field-error .select-trigger {
160
+ border-color: var(--color-error);
161
+ }
162
+
163
+ .select.field-error.select-open .select-trigger {
164
+ border-color: var(--color-error);
165
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--color-error-border);
166
+ }
167
+
168
+ .select.field-success .select-trigger {
169
+ border-color: var(--color-success);
170
+ }
171
+
172
+ .select.field-success.select-open .select-trigger {
173
+ border-color: var(--color-success);
174
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--color-success-border);
175
+ }
176
+
177
+ .select.field-warning .select-trigger {
178
+ border-color: var(--color-warning);
179
+ }
180
+
181
+ .select.field-warning.select-open .select-trigger {
182
+ border-color: var(--color-warning);
183
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--color-warning-border);
184
+ }
185
+
186
+ /* ═══════════════════════════════════════════════════════════
187
+ TEXTAREA VALIDATION STATES
188
+ ═══════════════════════════════════════════════════════════ */
189
+
190
+ .textarea.field-error {
191
+ border-color: var(--color-error);
192
+ }
193
+
194
+ .textarea.field-error:focus {
195
+ border-color: var(--color-error);
196
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--color-error-border);
197
+ }
198
+
199
+ .textarea.field-success {
200
+ border-color: var(--color-success);
201
+ }
202
+
203
+ .textarea.field-success:focus {
204
+ border-color: var(--color-success);
205
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--color-success-border);
206
+ }
207
+
208
+ .textarea.field-warning {
209
+ border-color: var(--color-warning);
210
+ }
211
+
212
+ .textarea.field-warning:focus {
213
+ border-color: var(--color-warning);
214
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--color-warning-border);
215
+ }
216
+
217
+ /* ═══════════════════════════════════════════════════════════
218
+ CHECKBOX / RADIO VALIDATION
219
+ ═══════════════════════════════════════════════════════════ */
220
+
221
+ .checkbox.field-error .checkbox-box {
222
+ border-color: var(--color-error);
223
+ }
224
+
225
+ .checkbox.field-error .checkbox-native:checked ~ .checkbox-box {
226
+ background-color: var(--color-error);
227
+ border-color: var(--color-error);
228
+ }
229
+
230
+ .checkbox.field-error .checkbox-label {
231
+ color: var(--color-error);
232
+ }
233
+
234
+ .radio.field-error .radio-circle {
235
+ border-color: var(--color-error);
236
+ }
237
+
238
+ .radio.field-error .radio-native:checked ~ .radio-circle {
239
+ border-color: var(--color-error);
240
+ background-color: var(--color-error);
241
+ }
242
+
243
+ .radio.field-error .radio-label {
244
+ color: var(--color-error);
245
+ }
246
+
247
+ /* ═══════════════════════════════════════════════════════════
248
+ TOGGLE / SWITCH VALIDATION
249
+ ═══════════════════════════════════════════════════════════ */
250
+
251
+ .switch-card.field-error {
252
+ border-color: var(--color-error);
253
+ }
254
+
255
+ /* ═══════════════════════════════════════════════════════════
256
+ CHARACTER COUNTER — State colors
257
+ ═══════════════════════════════════════════════════════════ */
258
+
259
+ .input-counter.limit-near {
260
+ color: var(--color-warning);
261
+ font-weight: var(--font-medium);
262
+ }
263
+
264
+ .input-counter.limit-reached {
265
+ color: var(--color-error);
266
+ font-weight: var(--font-semibold);
267
+ }
268
+
269
+ /* ═══════════════════════════════════════════════════════════
270
+ PASSWORD STRENGTH INDICATOR
271
+ ═══════════════════════════════════════════════════════════ */
272
+
273
+ .password-strength {
274
+ margin-top: var(--space-2);
275
+ }
276
+
277
+ .password-strength-bar-track {
278
+ display: flex;
279
+ gap: var(--space-1);
280
+ margin-bottom: var(--space-1-5);
281
+ }
282
+
283
+ .password-strength-segment {
284
+ flex: 1;
285
+ height: var(--space-1);
286
+ border-radius: var(--radius-pill);
287
+ background-color: var(--color-neutral-200);
288
+ transition: background-color var(--duration-normal) var(--ease-in-out);
289
+ }
290
+
291
+ /* Strength levels */
292
+ .password-strength[data-strength="weak"] .password-strength-segment:nth-child(1) {
293
+ background-color: var(--color-error);
294
+ }
295
+
296
+ .password-strength[data-strength="fair"] .password-strength-segment:nth-child(-n+2) {
297
+ background-color: var(--color-warning);
298
+ }
299
+
300
+ .password-strength[data-strength="good"] .password-strength-segment:nth-child(-n+3) {
301
+ background-color: var(--color-accent-500);
302
+ }
303
+
304
+ .password-strength[data-strength="strong"] .password-strength-segment {
305
+ background-color: var(--color-success);
306
+ }
307
+
308
+ /* Strength label */
309
+ .password-strength-label {
310
+ font-family: var(--font-sans);
311
+ font-size: var(--text-xs);
312
+ font-weight: var(--font-medium);
313
+ line-height: var(--leading-tight);
314
+ color: var(--color-neutral-500);
315
+ transition: color var(--duration-fast) var(--ease-in-out);
316
+ }
317
+
318
+ .password-strength[data-strength="weak"] .password-strength-label {
319
+ color: var(--color-error);
320
+ }
321
+
322
+ .password-strength[data-strength="fair"] .password-strength-label {
323
+ color: var(--color-warning);
324
+ }
325
+
326
+ .password-strength[data-strength="good"] .password-strength-label {
327
+ color: var(--color-accent-600);
328
+ }
329
+
330
+ .password-strength[data-strength="strong"] .password-strength-label {
331
+ color: var(--color-success);
332
+ }
333
+
334
+ /* ═══════════════════════════════════════════════════════════
335
+ FORM-LEVEL ALERT BANNER
336
+ ═══════════════════════════════════════════════════════════ */
337
+
338
+ .form-alert {
339
+ display: flex;
340
+ align-items: flex-start;
341
+ gap: var(--space-3);
342
+ padding: var(--space-4);
343
+ border-radius: var(--radius-md);
344
+ margin-bottom: var(--space-6);
345
+ opacity: 0;
346
+ transform: translateY(-8px);
347
+ animation: form-alert-in var(--duration-normal) var(--ease-out) forwards;
348
+ }
349
+
350
+ @keyframes form-alert-in {
351
+ to {
352
+ opacity: 1;
353
+ transform: translateY(0);
354
+ }
355
+ }
356
+
357
+ .form-alert.fade-out {
358
+ animation: form-alert-out var(--duration-normal) var(--ease-in-out) forwards;
359
+ }
360
+
361
+ @keyframes form-alert-out {
362
+ to {
363
+ opacity: 0;
364
+ transform: translateY(-8px);
365
+ }
366
+ }
367
+
368
+ /* Error alert */
369
+ .form-alert-error {
370
+ background-color: var(--color-error-light);
371
+ border: var(--border-width) solid var(--color-error-border);
372
+ }
373
+
374
+ .form-alert-error .form-alert-icon {
375
+ color: var(--color-error);
376
+ }
377
+
378
+ .form-alert-error .form-alert-title {
379
+ color: var(--color-error-dark);
380
+ }
381
+
382
+ .form-alert-error .form-alert-list li {
383
+ color: var(--color-error-dark);
384
+ }
385
+
386
+ .form-alert-error .form-alert-list a {
387
+ color: var(--color-error);
388
+ }
389
+
390
+ /* Warning alert */
391
+ .form-alert-warning {
392
+ background-color: var(--color-warning-light);
393
+ border: var(--border-width) solid var(--color-warning-border);
394
+ }
395
+
396
+ .form-alert-warning .form-alert-icon {
397
+ color: var(--color-warning);
398
+ }
399
+
400
+ .form-alert-warning .form-alert-title {
401
+ color: var(--color-warning-dark);
402
+ }
403
+
404
+ .form-alert-warning .form-alert-list li {
405
+ color: var(--color-warning-dark);
406
+ }
407
+
408
+ .form-alert-warning .form-alert-list a {
409
+ color: var(--color-warning);
410
+ }
411
+
412
+ /* Success alert */
413
+ .form-alert-success {
414
+ background-color: var(--color-success-light);
415
+ border: var(--border-width) solid var(--color-success-border);
416
+ }
417
+
418
+ .form-alert-success .form-alert-icon {
419
+ color: var(--color-success);
420
+ }
421
+
422
+ .form-alert-success .form-alert-title {
423
+ color: var(--color-success-dark);
424
+ }
425
+
426
+ .form-alert-success .form-alert-list li {
427
+ color: var(--color-success-dark);
428
+ }
429
+
430
+ /* Alert content */
431
+ .form-alert-icon {
432
+ flex-shrink: 0;
433
+ width: var(--space-5);
434
+ height: var(--space-5);
435
+ margin-top: var(--space-0-5);
436
+ }
437
+
438
+ .form-alert-body {
439
+ flex: 1;
440
+ min-width: 0;
441
+ }
442
+
443
+ .form-alert-title {
444
+ font-family: var(--font-sans);
445
+ font-size: var(--text-sm);
446
+ font-weight: var(--font-semibold);
447
+ line-height: var(--leading-tight);
448
+ margin-bottom: var(--space-1);
449
+ }
450
+
451
+ .form-alert-list {
452
+ margin: 0;
453
+ padding-left: var(--space-4);
454
+ font-size: var(--text-xs);
455
+ line-height: var(--leading-relaxed);
456
+ }
457
+
458
+ .form-alert-list li {
459
+ margin-bottom: var(--space-0-5);
460
+ }
461
+
462
+ .form-alert-list a {
463
+ text-decoration: underline;
464
+ text-underline-offset: 2px;
465
+ cursor: pointer;
466
+ font-weight: var(--font-medium);
467
+ }
468
+
469
+ .form-alert-list a:hover {
470
+ text-decoration-thickness: 2px;
471
+ }
472
+
473
+ /* Dismiss button */
474
+ .form-alert-dismiss {
475
+ flex-shrink: 0;
476
+ display: inline-flex;
477
+ align-items: center;
478
+ justify-content: center;
479
+ width: var(--space-5);
480
+ height: var(--space-5);
481
+ border: none;
482
+ border-radius: var(--radius-sm);
483
+ background: transparent;
484
+ color: var(--color-neutral-500);
485
+ cursor: pointer;
486
+ padding: 0;
487
+ transition: color var(--duration-fast) var(--ease-in-out),
488
+ background-color var(--duration-fast) var(--ease-in-out);
489
+ }
490
+
491
+ .form-alert-dismiss:hover {
492
+ background-color: rgba(0, 0, 0, 0.06);
493
+ color: var(--color-neutral-700);
494
+ }
495
+
496
+ .form-alert-dismiss svg {
497
+ width: var(--space-4);
498
+ height: var(--space-4);
499
+ }
500
+
501
+ /* ═══════════════════════════════════════════════════════════
502
+ FORM SUCCESS STATE
503
+ ═══════════════════════════════════════════════════════════ */
504
+
505
+ .form-success-state {
506
+ display: none;
507
+ flex-direction: column;
508
+ align-items: center;
509
+ justify-content: center;
510
+ text-align: center;
511
+ padding: var(--space-12) var(--space-8);
512
+ gap: var(--space-4);
513
+ animation: form-success-in var(--duration-slow) var(--ease-out) forwards;
514
+ }
515
+
516
+ .form-success-state.is-visible {
517
+ display: flex;
518
+ }
519
+
520
+ @keyframes form-success-in {
521
+ from {
522
+ opacity: 0;
523
+ transform: scale(0.95);
524
+ }
525
+ to {
526
+ opacity: 1;
527
+ transform: scale(1);
528
+ }
529
+ }
530
+
531
+ .form-success-icon {
532
+ width: var(--space-16);
533
+ height: var(--space-16);
534
+ border-radius: var(--radius-pill);
535
+ background-color: var(--color-success-light);
536
+ display: inline-flex;
537
+ align-items: center;
538
+ justify-content: center;
539
+ margin-bottom: var(--space-2);
540
+ }
541
+
542
+ .form-success-icon svg {
543
+ width: var(--space-8);
544
+ height: var(--space-8);
545
+ color: var(--color-success);
546
+ stroke-dasharray: 48;
547
+ stroke-dashoffset: 48;
548
+ animation: success-check-draw var(--duration-slow) var(--ease-out) var(--anim-check-draw-delay) forwards;
549
+ }
550
+
551
+ @keyframes success-check-draw {
552
+ to {
553
+ stroke-dashoffset: 0;
554
+ }
555
+ }
556
+
557
+ .form-success-title {
558
+ font-family: var(--font-serif);
559
+ font-size: var(--text-2xl);
560
+ font-weight: var(--font-semibold);
561
+ color: var(--color-neutral-900);
562
+ line-height: var(--leading-tight);
563
+ }
564
+
565
+ .form-success-desc {
566
+ font-size: var(--text-sm);
567
+ color: var(--color-neutral-500);
568
+ line-height: var(--leading-relaxed);
569
+ max-width: 360px;
570
+ }
571
+
572
+ /* ═══════════════════════════════════════════════════════════
573
+ FORM LOADING / SUBMITTING STATE
574
+ ═══════════════════════════════════════════════════════════ */
575
+
576
+ .form.is-submitting {
577
+ opacity: 0.6;
578
+ pointer-events: none;
579
+ }
580
+
581
+ .form.is-submitting .btn-submit-text {
582
+ opacity: 0;
583
+ }
584
+
585
+ .form.is-submitting .btn-submit-spinner {
586
+ display: inline-flex;
587
+ }
588
+
589
+ .btn-submit-spinner {
590
+ display: none;
591
+ width: var(--space-4);
592
+ height: var(--space-4);
593
+ position: absolute;
594
+ animation: btn-spin var(--anim-spinner-fast) linear infinite;
595
+ }
596
+
597
+ .btn-submit-spinner .spinner-circle {
598
+ stroke: currentColor;
599
+ stroke-dasharray: 20;
600
+ stroke-dashoffset: 15;
601
+ stroke-linecap: round;
602
+ }
603
+
604
+ @keyframes btn-spin {
605
+ 0% { transform: rotate(0deg); }
606
+ 100% { transform: rotate(360deg); }
607
+ }
608
+
609
+ /* ═══════════════════════════════════════════════════════════
610
+ VALIDATING STATE — Inline indicator
611
+ ═══════════════════════════════════════════════════════════ */
612
+
613
+ .field-validating-indicator {
614
+ display: none;
615
+ align-items: center;
616
+ gap: var(--space-1-5);
617
+ margin-top: var(--space-1-5);
618
+ font-size: var(--text-xs);
619
+ color: var(--color-neutral-500);
620
+ }
621
+
622
+ .field-validating-indicator.is-visible {
623
+ display: inline-flex;
624
+ }
625
+
626
+ .field-validating-indicator .validating-spinner {
627
+ width: var(--space-3);
628
+ height: var(--space-3);
629
+ animation: btn-spin var(--anim-spin-duration) linear infinite;
630
+ }
631
+
632
+ .field-validating-indicator .validating-spinner .spinner-circle {
633
+ stroke: currentColor;
634
+ stroke-dasharray: 12;
635
+ stroke-dashoffset: 9;
636
+ stroke-linecap: round;
637
+ }
638
+
639
+ /* ═══════════════════════════════════════════════════════════
640
+ FORM — Hide/Show transitions
641
+ ═══════════════════════════════════════════════════════════ */
642
+
643
+ .form-contents {
644
+ transition: opacity var(--duration-normal) var(--ease-in-out);
645
+ }
646
+
647
+ .form-contents.is-hidden {
648
+ display: none;
649
+ }
650
+
651
+ /* ═══════════════════════════════════════════════════════════
652
+ UTILITY: Helper for field spacing with validation
653
+ ═══════════════════════════════════════════════════════════ */
654
+
655
+ .field-group {
656
+ display: flex;
657
+ flex-direction: column;
658
+ gap: var(--space-1-5);
659
+ }
660
+
661
+ /* ═══════════════════════════════════════════════════════════
662
+ CONFIRM PASSWORD MATCH INDICATOR
663
+ ═══════════════════════════════════════════════════════════ */
664
+
665
+ .password-match-message {
666
+ display: none;
667
+ align-items: flex-start;
668
+ gap: var(--space-1);
669
+ margin-top: var(--space-1-5);
670
+ font-size: var(--text-xs);
671
+ font-weight: var(--font-medium);
672
+ line-height: var(--leading-tight);
673
+ }
674
+
675
+ .password-match-message.is-visible {
676
+ display: flex;
677
+ animation: field-msg-in var(--duration-normal) var(--ease-out) forwards;
678
+ }
679
+
680
+ .password-match-message.is-error {
681
+ color: var(--color-error);
682
+ }
683
+
684
+ .password-match-message.is-error svg {
685
+ color: var(--color-error);
686
+ width: var(--space-3);
687
+ height: var(--space-3);
688
+ flex-shrink: 0;
689
+ }
690
+
691
+ .password-match-message.is-success {
692
+ color: var(--color-success);
693
+ }
694
+
695
+ .password-match-message.is-success svg {
696
+ color: var(--color-success);
697
+ width: var(--space-3);
698
+ height: var(--space-3);
699
+ flex-shrink: 0;
700
+ }