@geosdi/ngx-ui 0.0.0-stage → 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.
package/styles/ui.scss ADDED
@@ -0,0 +1,2175 @@
1
+ // ---- pulsante ------------------------------------------------------------
2
+
3
+ .ml-button {
4
+ --ml-bg: var(--ml-primary);
5
+ --ml-bg-hover: var(--ml-primary-hover);
6
+ --ml-fg: var(--ml-on-primary);
7
+ --ml-soft: var(--ml-selection-background);
8
+
9
+ display: inline-flex;
10
+ align-items: center;
11
+ justify-content: center;
12
+ gap: 0.5rem;
13
+ min-height: var(--ml-control-height);
14
+ padding: var(--ml-button-padding);
15
+ border: 1px solid var(--ml-bg);
16
+ border-radius: var(--ml-radius);
17
+ background: var(--ml-bg);
18
+ color: var(--ml-fg);
19
+ font: inherit;
20
+ font-family: var(--ml-font-family);
21
+ font-weight: 600;
22
+ line-height: 1.2;
23
+ text-decoration: none;
24
+ cursor: pointer;
25
+ transition:
26
+ background-color 0.15s,
27
+ border-color 0.15s,
28
+ color 0.15s;
29
+
30
+ &:focus-visible {
31
+ outline: 2px solid var(--ml-focus-color);
32
+ outline-offset: 2px;
33
+ }
34
+
35
+ &:disabled,
36
+ &[aria-disabled="true"] {
37
+ opacity: 0.6;
38
+ cursor: default;
39
+ pointer-events: none;
40
+ }
41
+
42
+ &[data-severity="secondary"] {
43
+ --ml-bg: var(--ml-text-secondary);
44
+ --ml-bg-hover: var(--ml-secondary-hover);
45
+ --ml-soft: var(--ml-secondary-subtle);
46
+ }
47
+
48
+ &[data-severity="success"] {
49
+ --ml-bg: var(--ml-success);
50
+ --ml-bg-hover: var(--ml-success-hover);
51
+ --ml-soft: var(--ml-success-subtle);
52
+ }
53
+
54
+ &[data-severity="info"] {
55
+ --ml-bg: var(--ml-info);
56
+ --ml-bg-hover: var(--ml-info-hover);
57
+ }
58
+
59
+ &[data-severity="warn"] {
60
+ --ml-bg: var(--ml-warning);
61
+ --ml-bg-hover: var(--ml-warning-hover);
62
+ --ml-soft: var(--ml-warning-subtle);
63
+ }
64
+
65
+ &[data-severity="danger"] {
66
+ --ml-bg: var(--ml-danger);
67
+ --ml-bg-hover: var(--ml-danger-hover);
68
+ --ml-soft: var(--ml-danger-subtle);
69
+ }
70
+
71
+ // Solo il bordo, o niente : il colore passa al testo.
72
+ &.ml-button--outlined,
73
+ &.ml-button--text {
74
+ background: transparent;
75
+ color: var(--ml-bg);
76
+ }
77
+
78
+ &.ml-button--text {
79
+ border-color: transparent;
80
+ }
81
+
82
+ &.ml-button--small {
83
+ min-height: var(--ml-control-height-small);
84
+ padding: var(--ml-button-padding-small);
85
+ font-size: var(--ml-control-font-size-small);
86
+ }
87
+
88
+ &.ml-button--icon-only {
89
+ width: var(--ml-control-height);
90
+ min-width: var(--ml-control-height);
91
+ padding: 0;
92
+
93
+ &.ml-button--small {
94
+ width: var(--ml-control-height-small);
95
+ min-width: var(--ml-control-height-small);
96
+ }
97
+ }
98
+
99
+ &.ml-button--rounded {
100
+ border-radius: 999px;
101
+ }
102
+ }
103
+
104
+ @media (hover: hover) and (pointer: fine) {
105
+ .ml-button:hover {
106
+ border-color: var(--ml-bg-hover);
107
+ background: var(--ml-bg-hover);
108
+ }
109
+
110
+ .ml-button.ml-button--outlined:hover,
111
+ .ml-button.ml-button--text:hover {
112
+ background: var(--ml-soft);
113
+ color: var(--ml-bg-hover);
114
+ }
115
+
116
+ .ml-button.ml-button--text:hover {
117
+ border-color: transparent;
118
+ }
119
+ }
120
+
121
+ // ---- campo di testo -------------------------------------------------------
122
+
123
+ .ml-input {
124
+ width: auto;
125
+ min-height: var(--ml-control-height);
126
+ padding: var(--ml-input-padding);
127
+ border: 1px solid var(--ml-control-border);
128
+ border-radius: var(--ml-radius);
129
+ background: var(--ml-surface);
130
+ color: var(--ml-text);
131
+ font: inherit;
132
+ font-family: var(--ml-font-family);
133
+ transition:
134
+ border-color 0.15s,
135
+ box-shadow 0.15s;
136
+
137
+ &::placeholder {
138
+ color: var(--ml-text-muted);
139
+ }
140
+
141
+ &:focus {
142
+ border-color: var(--ml-primary);
143
+ outline: none;
144
+ box-shadow: 0 0 0 2px var(--ml-focus-shadow-color);
145
+ }
146
+
147
+ &:disabled {
148
+ background: var(--ml-surface-muted);
149
+ color: var(--ml-text-muted);
150
+ cursor: default;
151
+ }
152
+
153
+ &.ng-invalid.ng-touched,
154
+ &.ng-invalid.ng-dirty {
155
+ border-color: var(--ml-danger);
156
+ }
157
+ }
158
+
159
+ // ---- casella --------------------------------------------------------------
160
+
161
+ .ml-checkbox {
162
+ position: relative;
163
+ display: inline-flex;
164
+ flex: none;
165
+ width: 1.25rem;
166
+ height: 1.25rem;
167
+ vertical-align: middle;
168
+ }
169
+
170
+ // La casella vera, sopra il disegno e trasparente : prende il clic, la
171
+ // tastiera e il lettore di schermo.
172
+ .ml-checkbox__input {
173
+ position: absolute;
174
+ inset: 0;
175
+ z-index: 1;
176
+ margin: 0;
177
+ opacity: 0;
178
+ cursor: pointer;
179
+
180
+ &:disabled {
181
+ cursor: default;
182
+ }
183
+ }
184
+
185
+ .ml-checkbox__box {
186
+ display: inline-flex;
187
+ align-items: center;
188
+ justify-content: center;
189
+ width: 100%;
190
+ height: 100%;
191
+ border: 1px solid var(--ml-control-border);
192
+ border-radius: var(--ml-radius);
193
+ background: var(--ml-surface);
194
+ transition:
195
+ background-color 0.15s,
196
+ border-color 0.15s;
197
+
198
+ svg {
199
+ width: 0.875rem;
200
+ height: 0.875rem;
201
+ fill: none;
202
+ stroke: var(--ml-on-primary);
203
+ stroke-width: 2;
204
+ stroke-linecap: round;
205
+ stroke-linejoin: round;
206
+ visibility: hidden;
207
+ }
208
+ }
209
+
210
+ .ml-checkbox--checked .ml-checkbox__box {
211
+ border-color: var(--ml-primary);
212
+ background: var(--ml-primary);
213
+
214
+ svg {
215
+ visibility: visible;
216
+ }
217
+ }
218
+
219
+ .ml-checkbox__input:focus-visible + .ml-checkbox__box {
220
+ outline: 2px solid var(--ml-focus-color);
221
+ outline-offset: 2px;
222
+ }
223
+
224
+ .ml-checkbox--disabled .ml-checkbox__box {
225
+ opacity: 0.6;
226
+ }
227
+
228
+ @media (hover: hover) and (pointer: fine) {
229
+ .ml-checkbox:not(.ml-checkbox--disabled, .ml-checkbox--checked):hover
230
+ .ml-checkbox__box {
231
+ border-color: var(--ml-primary);
232
+ }
233
+ }
234
+
235
+ // ---- suggerimento ---------------------------------------------------------
236
+
237
+ .cdk-overlay-container {
238
+ z-index: var(--ml-overlay-z-index);
239
+ }
240
+
241
+ .ml-tooltip {
242
+ display: block;
243
+ max-width: 20rem;
244
+ padding: 0.5rem 0.75rem;
245
+ border-radius: var(--ml-radius);
246
+ background: var(--ml-tooltip-background);
247
+ color: var(--ml-on-primary);
248
+ font-family: var(--ml-font-family);
249
+ font-size: 0.875rem;
250
+ line-height: 1.35;
251
+ overflow-wrap: anywhere;
252
+ box-shadow: var(--ml-shadow);
253
+ pointer-events: none;
254
+ }
255
+
256
+ // ---- finestra -------------------------------------------------------------
257
+
258
+ // La maschera della finestra scritta nel template (`ml-dialog`) : sta sul
259
+ // posto, fissa sulla pagina. Quella delle finestre aperte da codice è lo
260
+ // sfondo dell'overlay del CDK, qui sotto.
261
+ .ml-dialog-mask {
262
+ position: fixed;
263
+ inset: 0;
264
+ z-index: 1100;
265
+ display: flex;
266
+ align-items: center;
267
+ justify-content: center;
268
+ padding: 1rem;
269
+ pointer-events: none;
270
+
271
+ > .ml-dialog {
272
+ pointer-events: auto;
273
+ }
274
+ }
275
+
276
+ .ml-dialog-mask--modal,
277
+ .ml-dialog-backdrop {
278
+ background: rgb(0 0 0 / 50%);
279
+ pointer-events: auto;
280
+ }
281
+
282
+ .ml-dialog {
283
+ display: flex;
284
+ flex-direction: column;
285
+ min-width: 300px;
286
+ max-width: 100%;
287
+ max-height: 90%;
288
+ border: 1px solid var(--ml-divider);
289
+ border-radius: 12px;
290
+ background: var(--ml-surface);
291
+ color: var(--ml-text);
292
+ box-shadow:
293
+ 0 20px 25px -5px rgb(0 0 0 / 10%),
294
+ 0 8px 10px -6px rgb(0 0 0 / 10%);
295
+ outline: none;
296
+ }
297
+
298
+ // Nell'overlay il riquadro è il pannello del CDK, e la finestra lo riempie.
299
+ .ml-dialog--overlay {
300
+ width: 100%;
301
+ height: 100%;
302
+ max-height: inherit;
303
+ }
304
+
305
+ .ml-dialog-pane {
306
+ max-height: 90vh;
307
+ }
308
+
309
+ .ml-dialog__header {
310
+ display: flex;
311
+ flex: none;
312
+ align-items: center;
313
+ justify-content: space-between;
314
+ gap: 0.5rem;
315
+ padding: 1.25rem;
316
+ }
317
+
318
+ .ml-dialog__title {
319
+ margin: 0;
320
+ color: var(--ml-text-heading);
321
+ font-size: 1.25rem;
322
+ font-weight: 600;
323
+ }
324
+
325
+ .ml-dialog__close {
326
+ display: inline-flex;
327
+ flex: none;
328
+ align-items: center;
329
+ justify-content: center;
330
+ width: 2.5rem;
331
+ height: 2.5rem;
332
+ margin-left: auto;
333
+ border: 0;
334
+ border-radius: 50%;
335
+ background: transparent;
336
+ color: var(--ml-text-secondary);
337
+ cursor: pointer;
338
+
339
+ &:focus-visible {
340
+ outline: 2px solid var(--ml-focus-color);
341
+ outline-offset: 2px;
342
+ }
343
+ }
344
+
345
+ .ml-dialog__content {
346
+ flex: 1 1 auto;
347
+ min-height: 0;
348
+ padding: 0 1.25rem 1.25rem;
349
+ overflow-y: auto;
350
+ }
351
+
352
+ .ml-dialog__footer {
353
+ display: flex;
354
+ flex: none;
355
+ justify-content: flex-end;
356
+ gap: 0.5rem;
357
+ padding: 0 1.25rem 1.25rem;
358
+ }
359
+
360
+ @media (hover: hover) and (pointer: fine) {
361
+ .ml-dialog__close:hover {
362
+ background: var(--ml-surface-muted);
363
+ color: var(--ml-text-heading);
364
+ }
365
+ }
366
+
367
+ // ---- conferma -------------------------------------------------------------
368
+
369
+ .ml-confirm__message {
370
+ margin: 0 0 1.25rem;
371
+ line-height: 1.5;
372
+ white-space: pre-line;
373
+ }
374
+
375
+ .ml-confirm__actions {
376
+ display: flex;
377
+ justify-content: flex-end;
378
+ gap: 0.5rem;
379
+ }
380
+
381
+ // ---- avvisi ---------------------------------------------------------------
382
+
383
+ // In alto a destra, con il livello configurabile dal tema.
384
+ .ml-toast-stack {
385
+ position: fixed;
386
+ top: calc(1rem + env(safe-area-inset-top, 0px));
387
+ right: max(1rem, env(safe-area-inset-right, 0px));
388
+ z-index: var(--ml-toast-z-index);
389
+ display: flex;
390
+ flex-direction: column;
391
+ gap: 0.75rem;
392
+ width: min(25rem, calc(100vw - 2rem));
393
+ pointer-events: none;
394
+ }
395
+
396
+ @keyframes ml-toast-enter {
397
+ from {
398
+ opacity: 0;
399
+ transform: translateY(-8px);
400
+ }
401
+
402
+ to {
403
+ opacity: 1;
404
+ transform: translateY(0);
405
+ }
406
+ }
407
+
408
+ .ml-toast {
409
+ --ml-toast: var(--ml-primary);
410
+
411
+ display: flex;
412
+ align-items: flex-start;
413
+ gap: 0.75rem;
414
+ padding: 1rem;
415
+ border: 1px solid color-mix(in srgb, var(--ml-toast) 35%, transparent);
416
+ border-radius: 8px;
417
+ background: color-mix(
418
+ in srgb,
419
+ color-mix(in srgb, var(--ml-toast) 10%, var(--ml-surface)) 90%,
420
+ transparent
421
+ );
422
+ color: color-mix(in srgb, var(--ml-toast) 75%, var(--ml-text));
423
+ box-shadow: 0 4px 12px rgb(0 0 0 / 8%);
424
+ backdrop-filter: blur(8px);
425
+ pointer-events: auto;
426
+ animation: ml-toast-enter var(--ml-toast-enter-duration) ease-out;
427
+
428
+ @media (prefers-reduced-motion: reduce) {
429
+ animation: none;
430
+ }
431
+
432
+ > .ml-icon {
433
+ margin-top: 0.15rem;
434
+ color: var(--ml-toast);
435
+ font-size: 1.4rem;
436
+ }
437
+
438
+ &[data-severity="success"] {
439
+ --ml-toast: var(--ml-success);
440
+ }
441
+
442
+ &[data-severity="warn"] {
443
+ --ml-toast: var(--ml-warning);
444
+ }
445
+
446
+ &[data-severity="error"] {
447
+ --ml-toast: var(--ml-danger);
448
+ }
449
+ }
450
+
451
+ .ml-toast__text {
452
+ flex: 1 1 auto;
453
+ min-width: 0;
454
+ line-height: 1.4;
455
+ font-weight: 500;
456
+ overflow-wrap: anywhere;
457
+ }
458
+
459
+ .ml-toast__close {
460
+ display: inline-flex;
461
+ flex: none;
462
+ align-items: center;
463
+ justify-content: center;
464
+ width: 1.75rem;
465
+ height: 1.75rem;
466
+ border: 0;
467
+ border-radius: 50%;
468
+ background: transparent;
469
+ color: inherit;
470
+ cursor: pointer;
471
+
472
+ &:hover {
473
+ background: color-mix(in srgb, var(--ml-toast) 12%, transparent);
474
+ }
475
+
476
+ &:focus-visible {
477
+ outline: 2px solid var(--ml-focus-color);
478
+ }
479
+ }
480
+
481
+ // ---- tendina --------------------------------------------------------------
482
+
483
+ .ml-select {
484
+ position: relative;
485
+ display: inline-flex;
486
+ min-width: 0;
487
+ vertical-align: middle;
488
+ }
489
+
490
+ .ml-select--fluid {
491
+ width: 100%;
492
+ }
493
+
494
+ .ml-select__trigger {
495
+ display: flex;
496
+ align-items: center;
497
+ width: 100%;
498
+ min-height: 2.5rem;
499
+ border: 1px solid var(--ml-control-border);
500
+ border-radius: var(--ml-radius);
501
+ background: var(--ml-surface);
502
+ color: var(--ml-text);
503
+ cursor: pointer;
504
+ transition:
505
+ border-color 0.15s,
506
+ box-shadow 0.15s;
507
+ }
508
+
509
+ .ml-select__label {
510
+ flex: 1 1 auto;
511
+ min-width: 0;
512
+ padding: 0.5rem 0.75rem;
513
+ overflow: hidden;
514
+ text-overflow: ellipsis;
515
+ white-space: nowrap;
516
+ outline: none;
517
+ }
518
+
519
+ // Con il testo libero il campo è un `input` vero, senza bordo suo : il bordo
520
+ // è quello del riquadro.
521
+ .ml-select__input {
522
+ border: 0;
523
+ background: transparent;
524
+ color: inherit;
525
+ font: inherit;
526
+ cursor: text;
527
+
528
+ &::placeholder {
529
+ color: var(--ml-text-muted);
530
+ }
531
+ }
532
+
533
+ .ml-select__placeholder {
534
+ color: var(--ml-text-muted);
535
+ }
536
+
537
+ .ml-select__clear,
538
+ .ml-select__arrow {
539
+ display: inline-flex;
540
+ flex: none;
541
+ align-items: center;
542
+ justify-content: center;
543
+ width: 2rem;
544
+ color: var(--ml-text-muted);
545
+ }
546
+
547
+ .ml-select__clear {
548
+ height: 2rem;
549
+ padding: 0;
550
+ border: 0;
551
+ border-radius: 50%;
552
+ background: transparent;
553
+ cursor: pointer;
554
+ }
555
+
556
+ .ml-select__arrow {
557
+ width: 2.5rem;
558
+ font-size: 0.875rem;
559
+ }
560
+
561
+ .ml-select--focus .ml-select__trigger {
562
+ border-color: var(--ml-primary);
563
+ box-shadow: 0 0 0 2px var(--ml-focus-shadow-color);
564
+ }
565
+
566
+ .ml-select--disabled .ml-select__trigger {
567
+ background: var(--ml-surface-muted);
568
+ color: var(--ml-text-muted);
569
+ cursor: default;
570
+ }
571
+
572
+ .ml-select--small .ml-select__trigger {
573
+ min-height: 2rem;
574
+ font-size: 0.875rem;
575
+ }
576
+
577
+ .ml-select--small .ml-select__label {
578
+ padding: 0.375rem 0.625rem;
579
+ }
580
+
581
+ .ml-select.ng-invalid.ng-touched .ml-select__trigger {
582
+ border-color: var(--ml-danger);
583
+ }
584
+
585
+ // Il pannello riempie il riquadro dell'overlay, che il CDK fa largo almeno
586
+ // quanto il campo : il riquadro è un flex in riga, e da solo il pannello
587
+ // resterebbe largo quanto le sue voci.
588
+ .ml-select__panel {
589
+ display: flex;
590
+ flex: 1 1 auto;
591
+ flex-direction: column;
592
+ max-width: calc(100vw - 1rem);
593
+ border: 1px solid var(--ml-divider);
594
+ border-radius: var(--ml-radius);
595
+ background: var(--ml-surface);
596
+ color: var(--ml-text);
597
+ box-shadow:
598
+ 0 4px 6px -1px rgb(0 0 0 / 10%),
599
+ 0 2px 4px -2px rgb(0 0 0 / 10%);
600
+ font-family: var(--ml-font-family);
601
+ font-size: 1rem;
602
+ }
603
+
604
+ .ml-select__search {
605
+ position: relative;
606
+ padding: 0.5rem 0.5rem 0.25rem;
607
+
608
+ .ml-input {
609
+ width: 100%;
610
+ padding-right: 2rem;
611
+ }
612
+
613
+ > .ml-icon {
614
+ position: absolute;
615
+ top: 50%;
616
+ right: 1.25rem;
617
+ margin-top: 0.125rem;
618
+ color: var(--ml-text-muted);
619
+ transform: translateY(-50%);
620
+ }
621
+ }
622
+
623
+ .ml-select__list {
624
+ max-height: 15rem;
625
+ margin: 0;
626
+ padding: 0.25rem;
627
+ overflow-y: auto;
628
+ list-style: none;
629
+ }
630
+
631
+ .ml-select__option {
632
+ display: flex;
633
+ align-items: center;
634
+ gap: 0.5rem;
635
+ padding: 0.5rem 0.75rem;
636
+ border-radius: calc(var(--ml-radius) - 1px);
637
+ cursor: pointer;
638
+ }
639
+
640
+ // La voce attiva (sotto il mouse o scelta con le frecce) e quella scelta
641
+ // hanno la barra blu a sinistra e il fondo azzurro, come nel menu a cascata
642
+ // e nella ricerca indirizzi (richiesta di Vito).
643
+ .ml-select__option--active,
644
+ .ml-select__option--selected {
645
+ background: var(--ml-selection-background);
646
+ color: var(--ml-primary-hover);
647
+ box-shadow: inset 3px 0 0 var(--ml-primary);
648
+ }
649
+
650
+ .ml-select__option--selected {
651
+ font-weight: 600;
652
+ }
653
+
654
+ .ml-select__check {
655
+ display: inline-flex;
656
+ flex: none;
657
+ align-items: center;
658
+ justify-content: center;
659
+ width: 1.125rem;
660
+ height: 1.125rem;
661
+ border: 1px solid var(--ml-control-border);
662
+ border-radius: 4px;
663
+ background: var(--ml-surface);
664
+ color: var(--ml-on-primary);
665
+ font-size: 0.7rem;
666
+
667
+ .ml-icon {
668
+ visibility: hidden;
669
+ }
670
+ }
671
+
672
+ .ml-select__option--selected .ml-select__check {
673
+ border-color: var(--ml-primary);
674
+ background: var(--ml-primary);
675
+
676
+ .ml-icon {
677
+ visibility: visible;
678
+ }
679
+ }
680
+
681
+ .ml-select__group {
682
+ padding: 0.6rem 0.75rem 0.3rem;
683
+ color: var(--ml-text-secondary);
684
+ font-size: 0.8rem;
685
+ font-weight: 600;
686
+ }
687
+
688
+ .ml-select__empty {
689
+ padding: 0.5rem 0.75rem;
690
+ color: var(--ml-text-muted);
691
+ }
692
+
693
+ // ---- campo con le proposte -----------------------------------------------
694
+
695
+ // Ha il disegno della tendina : qui solo quello che cambia. Si scrive, quindi
696
+ // il cursore è quello del testo, e la freccia è un pulsante.
697
+ .ml-autocomplete .ml-select__trigger {
698
+ cursor: text;
699
+ }
700
+
701
+ .ml-autocomplete__dropdown {
702
+ align-self: stretch;
703
+ padding: 0;
704
+ border: 0;
705
+ border-left: 1px solid var(--ml-divider);
706
+ background: transparent;
707
+ cursor: pointer;
708
+
709
+ &:disabled {
710
+ cursor: default;
711
+ }
712
+ }
713
+
714
+ // ---- etichetta sul campo --------------------------------------------------
715
+
716
+ // I campi che la fanno salire : quelli con un valore (`ml-input--filled`,
717
+ // `ml-select--filled`), col fuoco, o con un segnaposto da non coprire.
718
+
719
+ .ml-floatlabel {
720
+ position: relative;
721
+ display: block;
722
+
723
+ > label {
724
+ position: absolute;
725
+ top: 50%;
726
+ left: 0.75rem;
727
+ margin: 0;
728
+ color: var(--ml-text-muted);
729
+ font-size: 1rem;
730
+ font-weight: 500;
731
+ line-height: 1;
732
+ pointer-events: none;
733
+ transform: translateY(-50%);
734
+ transition: all 0.2s ease;
735
+ }
736
+
737
+ &:has(textarea) > label {
738
+ top: 0.5rem;
739
+ transform: none;
740
+ }
741
+
742
+ &:has(
743
+ input:focus,
744
+ textarea:focus,
745
+ input:-webkit-autofill,
746
+ .ml-input--filled,
747
+ .ml-select--filled,
748
+ .ml-select--focus,
749
+ input[placeholder]:not([placeholder=""]),
750
+ textarea[placeholder]:not([placeholder=""])
751
+ )
752
+ > label {
753
+ top: -1.25rem;
754
+ transform: none;
755
+ color: var(--ml-text-secondary);
756
+ font-size: 0.75rem;
757
+ font-weight: 400;
758
+ }
759
+
760
+ &:has(input:focus, textarea:focus, .ml-select--focus) > label {
761
+ color: var(--ml-primary);
762
+ }
763
+ }
764
+
765
+ // Sul bordo del campo : il fondo del campo sotto l'etichetta copre la riga.
766
+ .ml-floatlabel--on:has(
767
+ input:focus,
768
+ textarea:focus,
769
+ input:-webkit-autofill,
770
+ .ml-input--filled,
771
+ .ml-select--filled,
772
+ .ml-select--focus,
773
+ input[placeholder]:not([placeholder=""]),
774
+ textarea[placeholder]:not([placeholder=""])
775
+ )
776
+ > label {
777
+ top: 0;
778
+ padding: 0 0.125rem;
779
+ border-radius: 2px;
780
+ background: var(--ml-surface);
781
+ transform: translateY(-50%);
782
+ }
783
+
784
+ .ml-floatlabel:has(.ml-select--fluid, .w-full) {
785
+ width: 100%;
786
+ }
787
+
788
+ // ---- campo numerico -------------------------------------------------------
789
+
790
+ .ml-inputnumber {
791
+ position: relative;
792
+ display: inline-flex;
793
+ min-width: 0;
794
+ vertical-align: middle;
795
+
796
+ > .ml-input {
797
+ flex: 1 1 auto;
798
+ width: 100%;
799
+ min-width: 0;
800
+ }
801
+ }
802
+
803
+ .ml-inputnumber--buttons > .ml-input {
804
+ padding-right: 2rem;
805
+ }
806
+
807
+ .ml-inputnumber__buttons {
808
+ position: absolute;
809
+ top: 1px;
810
+ right: 1px;
811
+ bottom: 1px;
812
+ display: flex;
813
+ flex-direction: column;
814
+ width: 1.75rem;
815
+
816
+ button {
817
+ display: flex;
818
+ flex: 1 1 0;
819
+ align-items: center;
820
+ justify-content: center;
821
+ padding: 0;
822
+ border: 0;
823
+ background: transparent;
824
+ color: var(--ml-text-muted);
825
+ font-size: 0.75rem;
826
+ cursor: pointer;
827
+
828
+ &:disabled {
829
+ cursor: default;
830
+ opacity: 0.6;
831
+ }
832
+ }
833
+ }
834
+
835
+ // ---- interruttore ---------------------------------------------------------
836
+
837
+ .ml-switch {
838
+ position: relative;
839
+ display: inline-flex;
840
+ flex: none;
841
+ width: 2.5rem;
842
+ height: 1.5rem;
843
+ vertical-align: middle;
844
+ }
845
+
846
+ .ml-switch__input {
847
+ position: absolute;
848
+ inset: 0;
849
+ z-index: 1;
850
+ margin: 0;
851
+ opacity: 0;
852
+ cursor: pointer;
853
+
854
+ &:disabled {
855
+ cursor: default;
856
+ }
857
+ }
858
+
859
+ .ml-switch__track {
860
+ position: relative;
861
+ width: 100%;
862
+ height: 100%;
863
+ border-radius: 999px;
864
+ background: var(--ml-control-border);
865
+ transition: background-color 0.15s;
866
+ }
867
+
868
+ .ml-switch__handle {
869
+ position: absolute;
870
+ top: 0.25rem;
871
+ left: 0.25rem;
872
+ width: 1rem;
873
+ height: 1rem;
874
+ border-radius: 50%;
875
+ background: var(--ml-surface);
876
+ box-shadow: 0 1px 2px rgb(0 0 0 / 20%);
877
+ transition: transform 0.15s;
878
+ }
879
+
880
+ .ml-switch--on .ml-switch__track {
881
+ background: var(--ml-primary);
882
+ }
883
+
884
+ .ml-switch--on .ml-switch__handle {
885
+ transform: translateX(1rem);
886
+ }
887
+
888
+ .ml-switch--disabled {
889
+ opacity: 0.6;
890
+ }
891
+
892
+ .ml-switch__input:focus-visible + .ml-switch__track {
893
+ outline: 2px solid var(--ml-focus-color);
894
+ outline-offset: 2px;
895
+ }
896
+
897
+ // ---- cursore --------------------------------------------------------------
898
+
899
+ .ml-slider {
900
+ display: block;
901
+ min-width: 6rem;
902
+ }
903
+
904
+ // La pista è piena fino al pollice : la parte piena la scrive il componente
905
+ // in `--ml-slider-fill`.
906
+ .ml-slider__input {
907
+ width: 100%;
908
+ height: 1.25rem;
909
+ margin: 0;
910
+ background: transparent;
911
+ cursor: pointer;
912
+ appearance: none;
913
+
914
+ &::-webkit-slider-runnable-track {
915
+ height: 0.25rem;
916
+ border-radius: 999px;
917
+ background: linear-gradient(
918
+ to right,
919
+ var(--ml-primary) var(--ml-slider-fill, 0%),
920
+ var(--ml-control-border) var(--ml-slider-fill, 0%)
921
+ );
922
+ }
923
+
924
+ &::-moz-range-track {
925
+ height: 0.25rem;
926
+ border-radius: 999px;
927
+ background: var(--ml-control-border);
928
+ }
929
+
930
+ &::-moz-range-progress {
931
+ height: 0.25rem;
932
+ border-radius: 999px;
933
+ background: var(--ml-primary);
934
+ }
935
+
936
+ &::-webkit-slider-thumb {
937
+ width: 1.1rem;
938
+ height: 1.1rem;
939
+ margin-top: -0.425rem;
940
+ border: 2px solid var(--ml-primary);
941
+ border-radius: 50%;
942
+ background: var(--ml-surface);
943
+ appearance: none;
944
+ }
945
+
946
+ &::-moz-range-thumb {
947
+ width: 1rem;
948
+ height: 1rem;
949
+ border: 2px solid var(--ml-primary);
950
+ border-radius: 50%;
951
+ background: var(--ml-surface);
952
+ }
953
+
954
+ &:focus-visible {
955
+ outline: 2px solid var(--ml-focus-color);
956
+ outline-offset: 2px;
957
+ }
958
+
959
+ &:disabled {
960
+ cursor: default;
961
+ opacity: 0.6;
962
+ }
963
+ }
964
+
965
+ // ---- scelta a bottoni -----------------------------------------------------
966
+
967
+ .ml-selectbutton {
968
+ display: inline-flex;
969
+ flex-wrap: wrap;
970
+ }
971
+
972
+ .ml-selectbutton__option {
973
+ min-height: 2.25rem;
974
+ padding: 0.4rem 0.85rem;
975
+ border: 1px solid var(--ml-control-border);
976
+ background: var(--ml-surface);
977
+ color: var(--ml-text);
978
+ font: inherit;
979
+ cursor: pointer;
980
+
981
+ & + & {
982
+ margin-left: -1px;
983
+ }
984
+
985
+ &:first-child {
986
+ border-radius: var(--ml-radius) 0 0 var(--ml-radius);
987
+ }
988
+
989
+ &:last-child {
990
+ border-radius: 0 var(--ml-radius) var(--ml-radius) 0;
991
+ }
992
+
993
+ &:focus-visible {
994
+ position: relative;
995
+ z-index: 1;
996
+ outline: 2px solid var(--ml-focus-color);
997
+ outline-offset: 1px;
998
+ }
999
+ }
1000
+
1001
+ .ml-selectbutton__option--on {
1002
+ position: relative;
1003
+ border-color: var(--ml-primary);
1004
+ background: var(--ml-primary);
1005
+ color: var(--ml-on-primary);
1006
+ }
1007
+
1008
+ // ---- radio ----------------------------------------------------------------
1009
+
1010
+ .ml-radio {
1011
+ position: relative;
1012
+ display: inline-flex;
1013
+ flex: none;
1014
+ width: 1.25rem;
1015
+ height: 1.25rem;
1016
+ vertical-align: middle;
1017
+ }
1018
+
1019
+ .ml-radio__input {
1020
+ position: absolute;
1021
+ inset: 0;
1022
+ z-index: 1;
1023
+ margin: 0;
1024
+ opacity: 0;
1025
+ cursor: pointer;
1026
+ }
1027
+
1028
+ .ml-radio__dot {
1029
+ width: 100%;
1030
+ height: 100%;
1031
+ border: 1px solid var(--ml-control-border);
1032
+ border-radius: 50%;
1033
+ background: var(--ml-surface);
1034
+ }
1035
+
1036
+ .ml-radio--checked .ml-radio__dot {
1037
+ border: 6px solid var(--ml-primary);
1038
+ }
1039
+
1040
+ .ml-radio__input:focus-visible + .ml-radio__dot {
1041
+ outline: 2px solid var(--ml-focus-color);
1042
+ outline-offset: 2px;
1043
+ }
1044
+
1045
+ .ml-radio--disabled {
1046
+ opacity: 0.6;
1047
+ }
1048
+
1049
+ // ---- popover --------------------------------------------------------------
1050
+
1051
+ .ml-popover {
1052
+ padding: 0.75rem;
1053
+ border: 1px solid var(--ml-divider);
1054
+ border-radius: var(--ml-radius);
1055
+ background: var(--ml-surface);
1056
+ color: var(--ml-text);
1057
+ box-shadow:
1058
+ 0 4px 6px -1px rgb(0 0 0 / 10%),
1059
+ 0 2px 4px -2px rgb(0 0 0 / 10%);
1060
+ font-family: var(--ml-font-family);
1061
+ }
1062
+
1063
+ // ---- cassetto -------------------------------------------------------------
1064
+
1065
+ .ml-drawer-mask {
1066
+ position: fixed;
1067
+ inset: 0;
1068
+ z-index: 1100;
1069
+ background: rgb(0 0 0 / 50%);
1070
+ }
1071
+
1072
+ .ml-drawer {
1073
+ position: fixed;
1074
+ top: 0;
1075
+ bottom: 0;
1076
+ z-index: 1101;
1077
+ display: flex;
1078
+ flex-direction: column;
1079
+ width: min(20rem, 100vw);
1080
+ background: var(--ml-surface);
1081
+ color: var(--ml-text);
1082
+ box-shadow: var(--ml-shadow);
1083
+ outline: none;
1084
+
1085
+ &[data-position="left"] {
1086
+ left: 0;
1087
+ }
1088
+
1089
+ &[data-position="right"] {
1090
+ right: 0;
1091
+ }
1092
+ }
1093
+
1094
+ .ml-drawer__close {
1095
+ align-self: flex-end;
1096
+ margin: 0.5rem;
1097
+ }
1098
+
1099
+ .ml-drawer__content {
1100
+ flex: 1 1 auto;
1101
+ min-height: 0;
1102
+ padding: 0 1.25rem 1.25rem;
1103
+ overflow-y: auto;
1104
+ }
1105
+
1106
+ // ---- rotella --------------------------------------------------------------
1107
+
1108
+ .ml-spinner {
1109
+ display: inline-block;
1110
+ width: 2rem;
1111
+ height: 2rem;
1112
+
1113
+ svg {
1114
+ width: 100%;
1115
+ height: 100%;
1116
+ animation: ml-spin 1.4s linear infinite;
1117
+ }
1118
+
1119
+ circle {
1120
+ stroke: var(--ml-primary);
1121
+ stroke-dasharray: 90 150;
1122
+ stroke-linecap: round;
1123
+ }
1124
+ }
1125
+
1126
+ @keyframes ml-spin {
1127
+ to {
1128
+ transform: rotate(360deg);
1129
+ }
1130
+ }
1131
+
1132
+ @media (prefers-reduced-motion: reduce) {
1133
+ .ml-spinner svg {
1134
+ animation-duration: 4s;
1135
+ }
1136
+ }
1137
+
1138
+ // ---- solo css : separatore, segnaposto, etichette, campo con icona --------
1139
+
1140
+ .ml-divider {
1141
+ height: 0;
1142
+ margin: 1rem 0;
1143
+ border: 0;
1144
+ border-top: 1px solid var(--ml-divider);
1145
+ }
1146
+
1147
+ // Il segnaposto di qualcosa che sta arrivando : quadrato, della misura che
1148
+ // gli si dà.
1149
+ .ml-skeleton {
1150
+ display: inline-block;
1151
+ width: 2rem;
1152
+ height: 2rem;
1153
+ border-radius: var(--ml-radius);
1154
+ background: linear-gradient(
1155
+ 90deg,
1156
+ var(--ml-surface-muted) 25%,
1157
+ var(--ml-divider) 50%,
1158
+ var(--ml-surface-muted) 75%
1159
+ );
1160
+ background-size: 200% 100%;
1161
+ animation: ml-skeleton 1.2s ease-in-out infinite;
1162
+ }
1163
+
1164
+ @keyframes ml-skeleton {
1165
+ to {
1166
+ background-position: -200% 0;
1167
+ }
1168
+ }
1169
+
1170
+ // Un chip che si clicca porta `role="button"` : il cursore lo dice.
1171
+ .ml-chip[role="button"] {
1172
+ cursor: pointer;
1173
+ }
1174
+
1175
+ .ml-chip {
1176
+ display: inline-flex;
1177
+ align-items: center;
1178
+ gap: 0.35rem;
1179
+ padding: 0.3rem 0.75rem;
1180
+ border-radius: 999px;
1181
+ background: var(--ml-surface-muted);
1182
+ color: var(--ml-text);
1183
+ font-size: 0.875rem;
1184
+ }
1185
+
1186
+ .ml-badge {
1187
+ display: inline-flex;
1188
+ align-items: center;
1189
+ justify-content: center;
1190
+ min-width: 1.5rem;
1191
+ height: 1.5rem;
1192
+ padding: 0 0.4rem;
1193
+ border-radius: 999px;
1194
+ background: var(--ml-primary);
1195
+ color: var(--ml-on-primary);
1196
+ font-size: 0.75rem;
1197
+ font-weight: 700;
1198
+
1199
+ &[data-severity="secondary"] {
1200
+ background: var(--ml-surface-muted);
1201
+ color: var(--ml-text);
1202
+ }
1203
+ }
1204
+
1205
+ // Un campo con l'icona dentro, a sinistra.
1206
+ .ml-iconfield {
1207
+ position: relative;
1208
+ display: inline-flex;
1209
+
1210
+ > .ml-input {
1211
+ width: 100%;
1212
+ padding-left: 2.5rem;
1213
+ }
1214
+ }
1215
+
1216
+ .ml-inputicon {
1217
+ position: absolute;
1218
+ top: 50%;
1219
+ left: 0.85rem;
1220
+ color: var(--ml-text-muted);
1221
+ pointer-events: none;
1222
+ transform: translateY(-50%);
1223
+ }
1224
+
1225
+ // ---- schede ---------------------------------------------------------------
1226
+
1227
+ .ml-tabs {
1228
+ display: block;
1229
+ }
1230
+
1231
+ .ml-tablist {
1232
+ display: flex;
1233
+ overflow-x: auto;
1234
+ border-bottom: 1px solid var(--ml-divider);
1235
+ scrollbar-width: thin;
1236
+ }
1237
+
1238
+ .ml-tab {
1239
+ flex: none;
1240
+ margin-bottom: -1px;
1241
+ padding: 0.75rem 1rem;
1242
+ border-bottom: 2px solid transparent;
1243
+ color: var(--ml-text-secondary);
1244
+ font-weight: 600;
1245
+ white-space: nowrap;
1246
+ cursor: pointer;
1247
+ user-select: none;
1248
+ transition:
1249
+ color 0.15s,
1250
+ border-color 0.15s;
1251
+
1252
+ &:focus-visible {
1253
+ outline: 2px solid var(--ml-focus-color);
1254
+ outline-offset: -2px;
1255
+ }
1256
+ }
1257
+
1258
+ .ml-tab--active {
1259
+ border-bottom-color: var(--ml-primary);
1260
+ color: var(--ml-primary);
1261
+ }
1262
+
1263
+ .ml-tabpanels {
1264
+ display: block;
1265
+ padding-top: 0.75rem;
1266
+ }
1267
+
1268
+ .ml-tabpanel {
1269
+ display: block;
1270
+
1271
+ &[hidden] {
1272
+ display: none;
1273
+ }
1274
+ }
1275
+
1276
+ @media (hover: hover) and (pointer: fine) {
1277
+ .ml-tab:not(.ml-tab--active):hover {
1278
+ color: var(--ml-text-heading);
1279
+ }
1280
+ }
1281
+
1282
+ // ---- fisarmonica ----------------------------------------------------------
1283
+
1284
+ .ml-accordion {
1285
+ display: block;
1286
+ }
1287
+
1288
+ .ml-accordion-panel {
1289
+ display: block;
1290
+ border-bottom: 1px solid var(--ml-divider);
1291
+ }
1292
+
1293
+ .ml-accordion-header {
1294
+ display: flex;
1295
+ align-items: center;
1296
+ justify-content: space-between;
1297
+ gap: 0.5rem;
1298
+ padding: 1rem 1.125rem;
1299
+ color: var(--ml-text-secondary);
1300
+ font-weight: 600;
1301
+ cursor: pointer;
1302
+ user-select: none;
1303
+
1304
+ &:focus-visible {
1305
+ outline: 2px solid var(--ml-focus-color);
1306
+ outline-offset: -2px;
1307
+ }
1308
+ }
1309
+
1310
+ .ml-accordion-header__title {
1311
+ flex: 1 1 auto;
1312
+ min-width: 0;
1313
+ }
1314
+
1315
+ .ml-accordion-header__icon {
1316
+ flex: none;
1317
+ font-size: 0.75rem;
1318
+ transition: transform 0.15s;
1319
+ }
1320
+
1321
+ .ml-accordion-panel--active > .ml-accordion-header {
1322
+ color: var(--ml-text-heading);
1323
+ }
1324
+
1325
+ .ml-accordion-panel--active > .ml-accordion-header .ml-accordion-header__icon {
1326
+ transform: rotate(180deg);
1327
+ }
1328
+
1329
+ // L'apertura si anima : la riga della griglia passa da `0fr` a `1fr`, cioè
1330
+ // dall'altezza zero a quella del contenuto, che con `height: auto` non si
1331
+ // potrebbe animare. `visibility` cambia subito all'apertura e alla fine della
1332
+ // chiusura, così il contenuto si vede mentre scende e sparisce dopo.
1333
+ .ml-accordion-content {
1334
+ display: grid;
1335
+ grid-template-rows: 0fr;
1336
+ visibility: hidden;
1337
+ transition:
1338
+ grid-template-rows 0.2s ease,
1339
+ visibility 0s linear 0.2s;
1340
+ }
1341
+
1342
+ .ml-accordion-content--open {
1343
+ grid-template-rows: 1fr;
1344
+ visibility: visible;
1345
+ transition:
1346
+ grid-template-rows 0.2s ease,
1347
+ visibility 0s linear 0s;
1348
+ }
1349
+
1350
+ .ml-accordion-content__clip {
1351
+ min-height: 0;
1352
+ overflow: hidden;
1353
+ }
1354
+
1355
+ @media (prefers-reduced-motion: reduce) {
1356
+ .ml-accordion-content,
1357
+ .ml-accordion-content--open {
1358
+ transition: none;
1359
+ }
1360
+ }
1361
+
1362
+ .ml-accordion-content__inner {
1363
+ padding: 0 1.125rem 1.125rem;
1364
+ }
1365
+
1366
+ // ---- paginatore -----------------------------------------------------------
1367
+
1368
+ .ml-paginator {
1369
+ display: flex;
1370
+ flex-wrap: wrap;
1371
+ align-items: center;
1372
+ justify-content: center;
1373
+ gap: 0.25rem;
1374
+ padding: 0.5rem 0;
1375
+ }
1376
+
1377
+ .ml-paginator__pages {
1378
+ display: inline-flex;
1379
+ gap: 0.25rem;
1380
+ }
1381
+
1382
+ .ml-paginator__button {
1383
+ display: inline-flex;
1384
+ align-items: center;
1385
+ justify-content: center;
1386
+ min-width: 2.25rem;
1387
+ height: 2.25rem;
1388
+ padding: 0 0.5rem;
1389
+ border: 0;
1390
+ border-radius: var(--ml-radius);
1391
+ background: transparent;
1392
+ color: var(--ml-text-secondary);
1393
+ font: inherit;
1394
+ cursor: pointer;
1395
+
1396
+ &:disabled {
1397
+ color: var(--ml-text-muted);
1398
+ cursor: default;
1399
+ opacity: 0.5;
1400
+ }
1401
+
1402
+ &:focus-visible {
1403
+ outline: 2px solid var(--ml-primary);
1404
+ outline-offset: 1px;
1405
+ }
1406
+ }
1407
+
1408
+ .ml-paginator__button--current {
1409
+ background: var(--ml-selection-background);
1410
+ color: var(--ml-primary-hover);
1411
+ font-weight: 600;
1412
+ }
1413
+
1414
+ @media (hover: hover) and (pointer: fine) {
1415
+ .ml-paginator__button:not(:disabled, .ml-paginator__button--current):hover {
1416
+ background: var(--ml-surface-muted);
1417
+ color: var(--ml-text-heading);
1418
+ }
1419
+ }
1420
+
1421
+ // Il conto «3 / 12» al posto dei numeri, dove i numeri non ci stanno.
1422
+ .ml-paginator__count {
1423
+ display: none;
1424
+ padding: 0 0.5rem;
1425
+ color: var(--ml-text-secondary);
1426
+ font-variant-numeric: tabular-nums;
1427
+ }
1428
+
1429
+ @media (max-width: 480px) {
1430
+ .ml-paginator__pages {
1431
+ display: none;
1432
+ }
1433
+
1434
+ .ml-paginator__count {
1435
+ display: inline;
1436
+ }
1437
+ }
1438
+
1439
+ // ---- tendina a più livelli -------------------------------------------------
1440
+
1441
+ // Le colonne stanno una di fianco all'altra, ognuna una card allineata alla
1442
+ // voce del gruppo da cui parte : il riquadro dell'overlay non ha fondo suo.
1443
+ .ml-cascadeselect__columns {
1444
+ display: flex;
1445
+ align-items: flex-start;
1446
+ gap: 0.375rem;
1447
+ }
1448
+
1449
+ // Verso sinistra la prima colonna sta a destra, sotto il campo.
1450
+ .ml-cascadeselect__columns--to-left {
1451
+ flex-direction: row-reverse;
1452
+ }
1453
+
1454
+ .ml-cascadeselect__column {
1455
+ flex: none;
1456
+ min-width: 12rem;
1457
+ max-width: min(20rem, calc(100vw - 1rem));
1458
+ overflow: hidden;
1459
+ border: 0;
1460
+ border-radius: 10px;
1461
+ box-shadow:
1462
+ 0 10px 28px rgb(15 23 42 / 16%),
1463
+ 0 0 0 1px rgb(15 23 42 / 6%);
1464
+ animation: ml-cascade-in 0.14s ease-out;
1465
+
1466
+ .ml-select__list {
1467
+ max-height: min(22rem, 70dvh);
1468
+ padding: 0.375rem;
1469
+ }
1470
+
1471
+ .ml-select__option {
1472
+ min-height: 2.5rem;
1473
+ padding: 0.5rem 0.625rem 0.5rem 0.75rem;
1474
+ border-radius: 6px;
1475
+ }
1476
+ }
1477
+
1478
+ // Una colonna nuova entra spostandosi di poco dal lato da cui si apre.
1479
+ @keyframes ml-cascade-in {
1480
+ from {
1481
+ opacity: 0;
1482
+ transform: translateX(-0.25rem);
1483
+ }
1484
+ }
1485
+
1486
+ .ml-cascadeselect__columns--to-left .ml-cascadeselect__column {
1487
+ animation-name: ml-cascade-in-left;
1488
+ }
1489
+
1490
+ @keyframes ml-cascade-in-left {
1491
+ from {
1492
+ opacity: 0;
1493
+ transform: translateX(0.25rem);
1494
+ }
1495
+ }
1496
+
1497
+ @media (prefers-reduced-motion: reduce) {
1498
+ .ml-cascadeselect__column {
1499
+ animation: none;
1500
+ }
1501
+ }
1502
+
1503
+ // In cima a una colonna, il nome del gruppo da cui viene.
1504
+ .ml-cascadeselect__title {
1505
+ padding: 0.375rem 0.75rem 0.5rem;
1506
+ margin-bottom: 0.25rem;
1507
+ border-bottom: 1px solid var(--ml-divider);
1508
+ color: var(--ml-text-muted);
1509
+ font-size: 0.75rem;
1510
+ font-weight: 600;
1511
+ letter-spacing: 0.04em;
1512
+ text-transform: uppercase;
1513
+ }
1514
+
1515
+ .ml-cascadeselect__text {
1516
+ flex: 1 1 auto;
1517
+ min-width: 0;
1518
+ overflow: hidden;
1519
+ text-overflow: ellipsis;
1520
+ white-space: nowrap;
1521
+ }
1522
+
1523
+ .ml-cascadeselect__column .ml-icon-chevron-right {
1524
+ flex: none;
1525
+ color: var(--ml-text-muted);
1526
+ font-size: 0.75rem;
1527
+ transition:
1528
+ color 0.15s,
1529
+ transform 0.15s;
1530
+ }
1531
+
1532
+ // La voce sotto il mouse, o scelta da tastiera, ha la barra blu e il fondo
1533
+ // azzurro del gruppo aperto, in qualunque colonna (richiesta di Vito).
1534
+ .ml-cascadeselect__column
1535
+ .ml-select__option--active:not(.ml-cascadeselect__option--disabled) {
1536
+ background: var(--ml-selection-background);
1537
+ color: var(--ml-primary-hover);
1538
+ box-shadow: inset 3px 0 0 var(--ml-primary);
1539
+ }
1540
+
1541
+ .ml-cascadeselect__columns--to-left
1542
+ .ml-select__option--active:not(.ml-cascadeselect__option--disabled) {
1543
+ box-shadow: inset -3px 0 0 var(--ml-primary);
1544
+ }
1545
+
1546
+ // Il gruppo aperto : la barra blu a sinistra, come le schede del builder, e
1547
+ // la freccia nel colore del tema spostata verso la sua colonna.
1548
+ .ml-cascadeselect__option--open {
1549
+ background: var(--ml-selection-background);
1550
+ color: var(--ml-primary-hover);
1551
+ font-weight: 600;
1552
+ box-shadow: inset 3px 0 0 var(--ml-primary);
1553
+
1554
+ .ml-icon-chevron-right {
1555
+ color: var(--ml-primary);
1556
+ transform: translateX(2px);
1557
+ }
1558
+ }
1559
+
1560
+ .ml-cascadeselect__columns--to-left .ml-cascadeselect__option--open {
1561
+ box-shadow: inset -3px 0 0 var(--ml-primary);
1562
+ }
1563
+
1564
+ // Una voce spenta non prende la barra né il fondo, nemmeno sotto il mouse.
1565
+ .ml-cascadeselect__option--disabled.ml-select__option--active {
1566
+ background: transparent;
1567
+ color: var(--ml-text-muted);
1568
+ box-shadow: none;
1569
+ }
1570
+
1571
+ .ml-cascadeselect__option--disabled {
1572
+ color: var(--ml-text-muted);
1573
+ cursor: not-allowed;
1574
+ opacity: 0.55;
1575
+ }
1576
+
1577
+ .ml-cascadeselect__back {
1578
+ margin-bottom: 0.25rem;
1579
+ border-bottom: 1px solid var(--ml-divider);
1580
+ border-radius: 0;
1581
+ color: var(--ml-text-secondary);
1582
+ font-weight: 600;
1583
+
1584
+ .ml-icon {
1585
+ color: var(--ml-primary);
1586
+ font-size: 0.75rem;
1587
+ }
1588
+ }
1589
+
1590
+ // ---- calendario -----------------------------------------------------------
1591
+
1592
+ .ml-datepicker {
1593
+ position: relative;
1594
+ display: inline-flex;
1595
+ min-width: 0;
1596
+ vertical-align: middle;
1597
+ }
1598
+
1599
+ .ml-datepicker__field {
1600
+ position: relative;
1601
+ display: flex;
1602
+ align-items: center;
1603
+ width: 100%;
1604
+ }
1605
+
1606
+ // Il campo non si scrive : il cursore è quello di un pulsante, e lo spazio a
1607
+ // destra è per la X e l'icona.
1608
+ .ml-datepicker__input {
1609
+ width: 100%;
1610
+ min-width: 10rem;
1611
+ padding-right: 4.25rem;
1612
+ cursor: pointer;
1613
+
1614
+ &:disabled {
1615
+ cursor: default;
1616
+ }
1617
+ }
1618
+
1619
+ .ml-datepicker__clear,
1620
+ .ml-datepicker__icon {
1621
+ position: absolute;
1622
+ top: 50%;
1623
+ display: inline-flex;
1624
+ align-items: center;
1625
+ justify-content: center;
1626
+ width: 2rem;
1627
+ height: 2rem;
1628
+ padding: 0;
1629
+ border: 0;
1630
+ border-radius: 50%;
1631
+ background: transparent;
1632
+ color: var(--ml-text-muted);
1633
+ cursor: pointer;
1634
+ transform: translateY(-50%);
1635
+
1636
+ &:disabled {
1637
+ cursor: default;
1638
+ }
1639
+ }
1640
+
1641
+ .ml-datepicker__icon {
1642
+ right: 0.25rem;
1643
+ color: var(--ml-primary);
1644
+ }
1645
+
1646
+ .ml-datepicker__clear {
1647
+ right: 2.25rem;
1648
+ }
1649
+
1650
+ .ml-datepicker:not(:has(.ml-datepicker__icon)) .ml-datepicker__clear {
1651
+ right: 0.25rem;
1652
+ }
1653
+
1654
+ .ml-datepicker__panel {
1655
+ width: 20rem;
1656
+ max-width: calc(100vw - 1rem);
1657
+ padding: 0.75rem;
1658
+ border-radius: 10px;
1659
+ background: var(--ml-surface);
1660
+ color: var(--ml-text);
1661
+ box-shadow:
1662
+ 0 10px 28px rgb(15 23 42 / 16%),
1663
+ 0 0 0 1px rgb(15 23 42 / 6%);
1664
+ font-family: var(--ml-font-family);
1665
+ }
1666
+
1667
+ // Al centro dello schermo, sul telefono : un po' più largo, e i giorni più
1668
+ // grandi da toccare (le misure stanno in fondo, con le altre per il tocco).
1669
+ .ml-datepicker__panel--sheet {
1670
+ width: min(24rem, calc(100vw - 2rem));
1671
+ }
1672
+
1673
+ .ml-datepicker__head {
1674
+ display: flex;
1675
+ align-items: center;
1676
+ gap: 0.125rem;
1677
+ margin-bottom: 0.5rem;
1678
+ }
1679
+
1680
+ .ml-datepicker__title {
1681
+ flex: 1 1 auto;
1682
+ color: var(--ml-text-heading);
1683
+ font-weight: 600;
1684
+ text-align: center;
1685
+ text-transform: capitalize;
1686
+ }
1687
+
1688
+ .ml-datepicker__nav {
1689
+ display: inline-flex;
1690
+ flex: none;
1691
+ align-items: center;
1692
+ justify-content: center;
1693
+ width: 2rem;
1694
+ height: 2rem;
1695
+ padding: 0;
1696
+ border: 0;
1697
+ border-radius: 6px;
1698
+ background: transparent;
1699
+ color: var(--ml-text-secondary);
1700
+ cursor: pointer;
1701
+ }
1702
+
1703
+ .ml-datepicker__grid {
1704
+ display: grid;
1705
+ grid-template-columns: repeat(7, 1fr);
1706
+ gap: 0.125rem;
1707
+ }
1708
+
1709
+ .ml-datepicker__weekday {
1710
+ padding: 0.25rem 0;
1711
+ color: var(--ml-text-muted);
1712
+ font-size: 0.75rem;
1713
+ font-weight: 600;
1714
+ text-align: center;
1715
+ text-transform: capitalize;
1716
+ }
1717
+
1718
+ .ml-datepicker__day {
1719
+ aspect-ratio: 1;
1720
+ display: inline-flex;
1721
+ align-items: center;
1722
+ justify-content: center;
1723
+ min-width: 0;
1724
+ padding: 0;
1725
+ border: 0;
1726
+ border-radius: 8px;
1727
+ background: transparent;
1728
+ color: var(--ml-text);
1729
+ font: inherit;
1730
+ font-size: 0.9rem;
1731
+ cursor: pointer;
1732
+ }
1733
+
1734
+ .ml-datepicker__day--other {
1735
+ color: var(--ml-text-muted);
1736
+ opacity: 0.6;
1737
+ }
1738
+
1739
+ .ml-datepicker__day--today {
1740
+ box-shadow: inset 0 0 0 1px var(--ml-primary);
1741
+ color: var(--ml-primary-hover);
1742
+ font-weight: 600;
1743
+ }
1744
+
1745
+ .ml-datepicker__day--in-range {
1746
+ border-radius: 0;
1747
+ background: var(--ml-selection-background);
1748
+ color: var(--ml-primary-hover);
1749
+ }
1750
+
1751
+ .ml-datepicker__day--selected {
1752
+ background: var(--ml-primary);
1753
+ color: var(--ml-on-primary);
1754
+ font-weight: 600;
1755
+ opacity: 1;
1756
+ }
1757
+
1758
+ .ml-datepicker__day:focus-visible,
1759
+ .ml-datepicker__nav:focus-visible,
1760
+ .ml-datepicker__link:focus-visible {
1761
+ outline: 2px solid var(--ml-primary);
1762
+ outline-offset: 1px;
1763
+ }
1764
+
1765
+ @media (hover: hover) and (pointer: fine) {
1766
+ .ml-datepicker__day:not(.ml-datepicker__day--selected):hover,
1767
+ .ml-datepicker__nav:hover {
1768
+ background: var(--ml-surface-muted);
1769
+ }
1770
+
1771
+ .ml-datepicker__link:hover {
1772
+ background: var(--ml-selection-background);
1773
+ }
1774
+ }
1775
+
1776
+ .ml-datepicker__time {
1777
+ display: flex;
1778
+ align-items: center;
1779
+ justify-content: space-between;
1780
+ gap: 0.75rem;
1781
+ margin: 0.75rem 0 0;
1782
+ padding-top: 0.75rem;
1783
+ border-top: 1px solid var(--ml-divider);
1784
+ color: var(--ml-text-secondary);
1785
+ font-weight: 600;
1786
+ }
1787
+
1788
+ .ml-datepicker__foot {
1789
+ display: flex;
1790
+ justify-content: space-between;
1791
+ gap: 0.5rem;
1792
+ margin-top: 0.75rem;
1793
+ padding-top: 0.5rem;
1794
+ border-top: 1px solid var(--ml-divider);
1795
+ }
1796
+
1797
+ .ml-datepicker__link {
1798
+ min-height: 2rem;
1799
+ padding: 0.25rem 0.625rem;
1800
+ border: 0;
1801
+ border-radius: 6px;
1802
+ background: transparent;
1803
+ color: var(--ml-primary);
1804
+ font: inherit;
1805
+ font-weight: 600;
1806
+ cursor: pointer;
1807
+ }
1808
+
1809
+ .ml-datepicker__link--done {
1810
+ margin-left: auto;
1811
+ }
1812
+
1813
+ // ---- tree ----------------------------------------------------------------
1814
+
1815
+ .ml-tree {
1816
+ display: block;
1817
+ }
1818
+
1819
+ .ml-tree__list,
1820
+ .ml-tree__children {
1821
+ margin: 0;
1822
+ padding: 0;
1823
+ list-style: none;
1824
+ }
1825
+
1826
+ // Ogni livello rientra della larghezza della freccia, così le righe figlie
1827
+ // stanno sotto l'etichetta del padre.
1828
+ .ml-tree__children {
1829
+ padding-left: 1.5rem;
1830
+ }
1831
+
1832
+ .ml-tree__row {
1833
+ display: flex;
1834
+ align-items: center;
1835
+ gap: 0.25rem;
1836
+ min-height: 2.25rem;
1837
+ padding: 0.125rem 0.25rem;
1838
+ border-radius: 6px;
1839
+ }
1840
+
1841
+ .ml-tree__toggle,
1842
+ .ml-tree__spacer {
1843
+ display: inline-flex;
1844
+ flex: none;
1845
+ align-items: center;
1846
+ justify-content: center;
1847
+ width: 1.75rem;
1848
+ height: 1.75rem;
1849
+ }
1850
+
1851
+ .ml-tree__toggle {
1852
+ padding: 0;
1853
+ border: 0;
1854
+ border-radius: 50%;
1855
+ background: transparent;
1856
+ color: var(--ml-text-muted);
1857
+ cursor: pointer;
1858
+
1859
+ .ml-icon {
1860
+ font-size: 0.75rem;
1861
+ transition: transform 0.15s;
1862
+ }
1863
+
1864
+ &:focus-visible {
1865
+ outline: 2px solid var(--ml-primary);
1866
+ outline-offset: 1px;
1867
+ }
1868
+ }
1869
+
1870
+ .ml-tree__toggle--open .ml-icon {
1871
+ transform: rotate(90deg);
1872
+ }
1873
+
1874
+ @media (hover: hover) and (pointer: fine) {
1875
+ .ml-tree__toggle:hover {
1876
+ background: var(--ml-surface-muted);
1877
+ color: var(--ml-text-heading);
1878
+ }
1879
+ }
1880
+
1881
+ @media (prefers-reduced-motion: reduce) {
1882
+ .ml-tree__toggle .ml-icon {
1883
+ transition: none;
1884
+ }
1885
+ }
1886
+
1887
+ .ml-tree__content {
1888
+ flex: 0 1 auto;
1889
+ min-width: 0;
1890
+ }
1891
+
1892
+ // ---- tabella --------------------------------------------------------------
1893
+
1894
+ // L'aspetto deciso per la tabella delle feature e per quella WMS (10 novembre
1895
+ // 2026, richieste di Vito) : intestazioni piccole, maiuscole e in grassetto su
1896
+ // fondo grigio, righe alterne bianco e azzurro, il passaggio del mouse più
1897
+ // azzurro, la riga scelta ancora di più con la barra blu a sinistra, come le
1898
+ // voci scelte delle tendine. Le righe le scrivono i modelli di chi usa la
1899
+ // tabella : la riga scelta si riconosce dalla casella spuntata.
1900
+ .ml-table {
1901
+ display: flex;
1902
+ flex-direction: column;
1903
+ min-width: 0;
1904
+ color: var(--ml-text);
1905
+ }
1906
+
1907
+ // `flex` : la tabella riempie l'altezza del suo contenitore e scorre dentro.
1908
+ .ml-table--flex {
1909
+ flex: 1 1 0;
1910
+ min-height: 0;
1911
+ }
1912
+
1913
+ .ml-table__caption {
1914
+ padding: 0.5rem 0.75rem;
1915
+ border-bottom: 1px solid var(--ml-focus-shadow-color);
1916
+ }
1917
+
1918
+ .ml-table__container {
1919
+ position: relative;
1920
+ overflow: auto;
1921
+ min-height: 0;
1922
+ }
1923
+
1924
+ .ml-table--flex .ml-table__container {
1925
+ flex: 1 1 0;
1926
+ }
1927
+
1928
+ .ml-table__table {
1929
+ width: 100%;
1930
+ border-collapse: separate;
1931
+ border-spacing: 0;
1932
+ font-size: 0.875rem;
1933
+ }
1934
+
1935
+ .ml-table__table th,
1936
+ .ml-table__table td {
1937
+ padding: 0.6rem 0.75rem;
1938
+ border-bottom: 1px solid var(--ml-focus-shadow-color);
1939
+ text-align: start;
1940
+ }
1941
+
1942
+ .ml-table--small .ml-table__table th,
1943
+ .ml-table--small .ml-table__table td {
1944
+ padding: 0.375rem 0.5rem;
1945
+ }
1946
+
1947
+ // Le intestazioni restano ferme mentre la tabella scorre. Ferma è tutta
1948
+ // l'intestazione e non le singole celle : con due righe (i titoli e i filtri
1949
+ // per colonna) le celle si fermavano tutte in cima, e i filtri coprivano i
1950
+ // titoli.
1951
+ .ml-table__thead {
1952
+ position: sticky;
1953
+ z-index: 1;
1954
+ top: 0;
1955
+ }
1956
+
1957
+ .ml-table__thead th {
1958
+ background: var(--ml-surface-muted);
1959
+ color: var(--ml-text-heading);
1960
+ font-size: 0.72rem;
1961
+ font-weight: 700;
1962
+ letter-spacing: 0.04em;
1963
+ text-transform: uppercase;
1964
+ white-space: nowrap;
1965
+ }
1966
+
1967
+ .ml-table__thead tr:last-child th {
1968
+ border-bottom-width: 2px;
1969
+ }
1970
+
1971
+ .ml-table__tbody > tr > td {
1972
+ background: var(--ml-surface);
1973
+ }
1974
+
1975
+ .ml-table--striped .ml-table__tbody > tr:nth-child(even) > td {
1976
+ background: color-mix(in srgb, var(--ml-primary) 7%, var(--ml-surface));
1977
+ }
1978
+
1979
+ @media (hover: hover) and (pointer: fine) {
1980
+ .ml-table--hover .ml-table__tbody > tr:not(.table-empty):hover > td {
1981
+ background: color-mix(
1982
+ in srgb,
1983
+ var(--ml-primary) 12%,
1984
+ var(--ml-surface)
1985
+ );
1986
+ }
1987
+ }
1988
+
1989
+ .ml-table__tbody > tr:has(.ml-checkbox--checked) > td {
1990
+ background: color-mix(in srgb, var(--ml-primary) 18%, var(--ml-surface));
1991
+ color: var(--ml-text-heading);
1992
+ }
1993
+
1994
+ .ml-table__tbody > tr:has(.ml-checkbox--checked) > td:first-child {
1995
+ box-shadow: inset 3px 0 0 var(--ml-primary);
1996
+ }
1997
+
1998
+ // Il messaggio della tabella vuota : una riga `table-empty` scritta da chi la
1999
+ // usa, su tutta la larghezza, centrata e senza il fondo delle righe di dati.
2000
+ .ml-table__tbody > tr.table-empty > td {
2001
+ padding: 2.5rem 1rem;
2002
+ border-bottom: 0;
2003
+ background: var(--ml-surface);
2004
+ color: var(--ml-text-muted);
2005
+ font-size: 0.9rem;
2006
+ text-align: center;
2007
+ }
2008
+
2009
+ .ml-table__tbody > tr.table-empty .ml-icon {
2010
+ display: block;
2011
+ margin-bottom: 0.5rem;
2012
+ color: var(--ml-text-secondary);
2013
+ font-size: 1.75rem;
2014
+ opacity: 0.5;
2015
+ }
2016
+
2017
+ .ml-table__tfoot td {
2018
+ border-bottom: 0;
2019
+ }
2020
+
2021
+ .ml-table__loading {
2022
+ position: absolute;
2023
+ inset: 0;
2024
+ display: flex;
2025
+ align-items: center;
2026
+ justify-content: center;
2027
+ background: rgb(255 255 255 / 60%);
2028
+ }
2029
+
2030
+ .ml-table .ml-paginator {
2031
+ border-top: 1px solid var(--ml-focus-shadow-color);
2032
+ }
2033
+
2034
+ // La maniglia per allargare una colonna, sul bordo destro dell'intestazione.
2035
+ .ml-table__resizable {
2036
+ position: relative;
2037
+ }
2038
+
2039
+ .ml-table__resizer {
2040
+ position: absolute;
2041
+ top: 0;
2042
+ right: 0;
2043
+ bottom: 0;
2044
+ width: 0.5rem;
2045
+ cursor: col-resize;
2046
+ touch-action: none;
2047
+ }
2048
+
2049
+ @media (hover: hover) and (pointer: fine) {
2050
+ .ml-table__resizer:hover {
2051
+ box-shadow: inset -2px 0 0 var(--ml-primary);
2052
+ }
2053
+ }
2054
+
2055
+ // Il filtro di una colonna, nella riga sotto le intestazioni : largo quanto
2056
+ // la colonna, e la riga resta bianca e non maiuscola.
2057
+ .ml-table__thead tr.filter-row th {
2058
+ background: var(--ml-surface);
2059
+ font-weight: 400;
2060
+ text-transform: none;
2061
+ letter-spacing: normal;
2062
+ }
2063
+
2064
+ .ml-column-filter {
2065
+ display: block;
2066
+ }
2067
+
2068
+ .ml-column-filter__control.ml-input {
2069
+ width: 100%;
2070
+ font-weight: 400;
2071
+ min-width: 4rem;
2072
+ height: 1.875rem;
2073
+ padding-block: 0;
2074
+ font-size: 0.8rem;
2075
+ }
2076
+
2077
+ // ---- telefono e tablet ----------------------------------------------------
2078
+
2079
+ // Con un puntatore grosso (il dito) tutti i componenti hanno un'area da
2080
+ // toccare di almeno 44 px e i campi scrivono a 16 px : sotto, Safari su
2081
+ // iPhone ingrandisce la pagina appena il campo prende il fuoco. Col mouse
2082
+ // restano le misure di sopra.
2083
+
2084
+ // Le misure dei pulsanti restano configurabili tramite i token del tema.
2085
+ @media (pointer: coarse) {
2086
+ // La maniglia delle colonne e il filtro per colonna, da toccare col dito.
2087
+ .ml-table__resizer {
2088
+ width: 1.25rem;
2089
+ }
2090
+
2091
+ .ml-column-filter__control.ml-input {
2092
+ height: 2.75rem;
2093
+ }
2094
+
2095
+ .ml-input,
2096
+ .ml-select__input,
2097
+ .ml-select--small .ml-select__input {
2098
+ font-size: 16px;
2099
+ }
2100
+
2101
+ // Casella e radio : l'input trasparente sopra il disegno si allarga oltre
2102
+ // il disegno, che resta della sua misura.
2103
+ .ml-checkbox__input,
2104
+ .ml-radio__input {
2105
+ inset: -0.75rem;
2106
+ }
2107
+
2108
+ .ml-switch__input {
2109
+ inset: -0.625rem -0.25rem;
2110
+ }
2111
+
2112
+ .ml-slider__input {
2113
+ height: 2.75rem;
2114
+ }
2115
+
2116
+ .ml-select__trigger {
2117
+ min-height: 2.75rem;
2118
+ }
2119
+
2120
+ .ml-select__clear,
2121
+ .ml-select__arrow,
2122
+ .ml-inputnumber__buttons {
2123
+ width: 2.75rem;
2124
+ }
2125
+
2126
+ .ml-select__clear {
2127
+ height: 2.75rem;
2128
+ }
2129
+
2130
+ .ml-inputnumber--buttons > .ml-input {
2131
+ padding-right: 3rem;
2132
+ }
2133
+
2134
+ .ml-select__option {
2135
+ min-height: 2.75rem;
2136
+ }
2137
+
2138
+ .ml-selectbutton__option,
2139
+ .ml-tab {
2140
+ min-height: 2.75rem;
2141
+ }
2142
+
2143
+ .ml-paginator__button {
2144
+ min-width: 2.75rem;
2145
+ height: 2.75rem;
2146
+ }
2147
+
2148
+ .ml-datepicker__nav,
2149
+ .ml-datepicker__clear,
2150
+ .ml-datepicker__icon,
2151
+ .ml-datepicker__link {
2152
+ min-width: 2.75rem;
2153
+ min-height: 2.75rem;
2154
+ }
2155
+
2156
+ .ml-datepicker__input {
2157
+ padding-right: 5.75rem;
2158
+ }
2159
+
2160
+ .ml-datepicker__clear {
2161
+ right: 3rem;
2162
+ }
2163
+
2164
+ .ml-tree__toggle,
2165
+ .ml-tree__spacer {
2166
+ width: 2.75rem;
2167
+ height: 2.75rem;
2168
+ }
2169
+
2170
+ .ml-dialog__close,
2171
+ .ml-toast__close {
2172
+ width: 2.75rem;
2173
+ height: 2.75rem;
2174
+ }
2175
+ }