@aurea-uds/core 0.1.0 → 0.3.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/dist/aurea.css +1374 -677
- package/dist/aurea.css.d.ts +3 -0
- package/dist/aurea.js +53 -0
- package/package.json +2 -2
package/dist/aurea.css
CHANGED
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
--z-modal:80;
|
|
57
57
|
--z-toast:100;
|
|
58
58
|
--sidebar-width:16.5rem;
|
|
59
|
+
--sidebar-rail:5.5rem;
|
|
59
60
|
--topbar-height:4rem;
|
|
60
61
|
--content-max:102.5rem;
|
|
61
62
|
--breakpoint-sm:640px;
|
|
@@ -272,681 +273,1377 @@
|
|
|
272
273
|
--card-pad:1.5rem;
|
|
273
274
|
--section-gap:2rem;
|
|
274
275
|
}
|
|
275
|
-
/* Aurea core — component styles. Built with @aurea-uds/tokens into dist/aurea.css. Load @aurea-uds/fonts/css for IBM Plex. */
|
|
276
|
-
/* ========================================================================== */
|
|
277
|
-
/* 02. RESET, ACESSIBILIDADE E BASE */
|
|
278
|
-
/* ========================================================================== */
|
|
279
|
-
* { box-sizing:border-box; }
|
|
280
|
-
html { scroll-behavior:smooth; }
|
|
281
|
-
body { margin:0; background:var(--background); color:var(--foreground); font-family:var(--font-ui); font-size:var(--text-md); line-height:var(--leading-normal); }
|
|
282
|
-
::selection { background:var(--selection); }
|
|
283
|
-
button,input,textarea,select { font:inherit; }
|
|
284
|
-
button,a,[role="button"],input,textarea,select { outline:none; }
|
|
285
|
-
:focus-visible { outline:2px solid var(--focus-strong); outline-offset:2px; box-shadow:none; border-color:var(--focus-strong)!important; }
|
|
286
|
-
button { color:inherit; }
|
|
287
|
-
a { color:var(--primary); text-underline-offset:3px; }
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
.
|
|
300
|
-
.
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
.
|
|
325
|
-
/*
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
.
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
.
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
.
|
|
354
|
-
/*
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
/*
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
.
|
|
386
|
-
/*
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
.
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
.
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
.
|
|
431
|
-
.
|
|
432
|
-
/*
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
.
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
.
|
|
441
|
-
.
|
|
442
|
-
.
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
.
|
|
448
|
-
.
|
|
449
|
-
.
|
|
450
|
-
/*
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
.
|
|
454
|
-
|
|
455
|
-
.
|
|
456
|
-
.
|
|
457
|
-
.
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
.
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
.
|
|
466
|
-
.
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
/*
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
.
|
|
477
|
-
.
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
.
|
|
481
|
-
|
|
482
|
-
/*
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
.
|
|
497
|
-
.
|
|
498
|
-
.btn
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
.btn-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
.btn-
|
|
508
|
-
.btn-
|
|
509
|
-
|
|
510
|
-
.
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
.
|
|
514
|
-
.
|
|
515
|
-
.
|
|
516
|
-
.
|
|
517
|
-
.
|
|
518
|
-
|
|
519
|
-
.
|
|
520
|
-
.
|
|
521
|
-
.
|
|
522
|
-
.
|
|
523
|
-
.
|
|
524
|
-
.
|
|
525
|
-
.
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
.
|
|
533
|
-
|
|
534
|
-
.
|
|
535
|
-
.
|
|
536
|
-
.
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
.
|
|
540
|
-
|
|
541
|
-
.
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
.
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
.
|
|
555
|
-
.
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
.
|
|
565
|
-
|
|
566
|
-
.
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
[data-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
/*
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
.
|
|
582
|
-
.
|
|
583
|
-
|
|
584
|
-
.
|
|
585
|
-
.
|
|
586
|
-
.
|
|
587
|
-
.
|
|
588
|
-
.
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
.
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
.
|
|
598
|
-
.
|
|
599
|
-
/*
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
.
|
|
604
|
-
.
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
.
|
|
608
|
-
.
|
|
609
|
-
|
|
610
|
-
.card
|
|
611
|
-
.
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
.
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
.
|
|
619
|
-
.
|
|
620
|
-
.
|
|
621
|
-
.
|
|
622
|
-
.
|
|
623
|
-
.
|
|
624
|
-
.
|
|
625
|
-
|
|
626
|
-
.
|
|
627
|
-
.
|
|
628
|
-
.
|
|
629
|
-
.
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
.
|
|
636
|
-
.
|
|
637
|
-
.
|
|
638
|
-
/*
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
.
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
.
|
|
651
|
-
.
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
.data-
|
|
656
|
-
.data-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
.
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
.
|
|
671
|
-
.
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
.
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
.
|
|
680
|
-
.
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
.
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
.
|
|
691
|
-
|
|
692
|
-
.
|
|
693
|
-
|
|
694
|
-
.
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
.
|
|
700
|
-
|
|
701
|
-
.
|
|
702
|
-
.
|
|
703
|
-
|
|
704
|
-
.
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
.
|
|
708
|
-
.
|
|
709
|
-
.
|
|
710
|
-
.
|
|
711
|
-
|
|
712
|
-
.
|
|
713
|
-
.
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
.
|
|
724
|
-
.
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
/*
|
|
729
|
-
|
|
730
|
-
.
|
|
731
|
-
.
|
|
732
|
-
.
|
|
733
|
-
|
|
734
|
-
.
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
.
|
|
738
|
-
.
|
|
739
|
-
.
|
|
740
|
-
.
|
|
741
|
-
.
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
.
|
|
745
|
-
.
|
|
746
|
-
|
|
747
|
-
.
|
|
748
|
-
.
|
|
749
|
-
.
|
|
750
|
-
|
|
751
|
-
.
|
|
752
|
-
|
|
753
|
-
.
|
|
754
|
-
.
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
.
|
|
769
|
-
|
|
770
|
-
.
|
|
771
|
-
.
|
|
772
|
-
.
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
.
|
|
785
|
-
.
|
|
786
|
-
.
|
|
787
|
-
.
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
.
|
|
795
|
-
.
|
|
796
|
-
.
|
|
797
|
-
.
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
.
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
.
|
|
810
|
-
.
|
|
811
|
-
.
|
|
812
|
-
.
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
.
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
.
|
|
823
|
-
.
|
|
824
|
-
|
|
825
|
-
.
|
|
826
|
-
.
|
|
827
|
-
.
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
.
|
|
834
|
-
.
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
.
|
|
839
|
-
.
|
|
840
|
-
.
|
|
841
|
-
.
|
|
842
|
-
.
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
.
|
|
856
|
-
|
|
857
|
-
.
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
.
|
|
861
|
-
.
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
.
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
.
|
|
874
|
-
.
|
|
875
|
-
.
|
|
876
|
-
.
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
.
|
|
883
|
-
.
|
|
884
|
-
.
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
.
|
|
891
|
-
.
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
.
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
/*
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
/*
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
.
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
/*
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
.
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
/*
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
:
|
|
951
|
-
:
|
|
276
|
+
/* Aurea core — component styles. Built with @aurea-uds/tokens into dist/aurea.css. Load @aurea-uds/fonts/css for IBM Plex. */
|
|
277
|
+
/* ========================================================================== */
|
|
278
|
+
/* 02. RESET, ACESSIBILIDADE E BASE */
|
|
279
|
+
/* ========================================================================== */
|
|
280
|
+
* { box-sizing:border-box; }
|
|
281
|
+
html { scroll-behavior:smooth; }
|
|
282
|
+
body { margin:0; background:var(--background); color:var(--foreground); font-family:var(--font-ui); font-size:var(--text-md); line-height:var(--leading-normal); }
|
|
283
|
+
::selection { background:var(--selection); }
|
|
284
|
+
button,input,textarea,select { font:inherit; }
|
|
285
|
+
button,a,[role="button"],input,textarea,select { outline:none; }
|
|
286
|
+
:focus-visible { outline:2px solid var(--focus-strong); outline-offset:2px; box-shadow:none; border-color:var(--focus-strong)!important; }
|
|
287
|
+
button { color:inherit; }
|
|
288
|
+
a { color:var(--primary); text-underline-offset:3px; }
|
|
289
|
+
/* LINK DE TEXTO NO TEMA CLARO — reprovação de WCAG AA que estava latente desde sempre, e que só
|
|
290
|
+
apareceu quando o catálogo ganhou a primeira página com link em corpo de texto (a do `Prose`,
|
|
291
|
+
item L5). Medido em 15/08/2026 na página gerada: o amarelo puro sobre a superfície clara dá
|
|
292
|
+
**1,68:1**, contra os 4,5:1 do AA. Com a correção, **6,92:1**.
|
|
293
|
+
NÃO é decisão de aparência nova, e é por isso que entra sem interromper o lote: a fórmula, o
|
|
294
|
+
guarda de tema e a razão já estão neste arquivo, escritos para o `.btn-link-primary` (linha
|
|
295
|
+
~247) e para a linguagem de selecionado — "no tema claro o amarelo puro como texto dá 1.6:1,
|
|
296
|
+
longe dos 4.5:1 do AA, então o rótulo aprofunda com --foreground e segue âmbar". O bare `<a>`
|
|
297
|
+
simplesmente nunca tinha recebido o mesmo tratamento.
|
|
298
|
+
`:not([class])` é a parte cirúrgica, e não zelo: sem ele esta regra (0,2,1) passaria por cima
|
|
299
|
+
de `.btn` (0,1,0), de `.doc-nav a` e de `.toc a`, trocando a cor de componentes que já resolvem
|
|
300
|
+
a própria. Assim ela alcança exatamente o que está quebrado — o link que o conteúdo escreve —
|
|
301
|
+
e nenhum outro. Limite declarado: link de conteúdo que carregue classe própria é do consumidor. */
|
|
302
|
+
[data-theme="light"] a:not([class]) { color:color-mix(in oklab, var(--primary) 45%, var(--foreground)); }
|
|
303
|
+
img,svg { display:block; }
|
|
304
|
+
/* O `display:none` que o browser dá pro atributo `hidden` vem da folha do UA e PERDE de
|
|
305
|
+
qualquer `display:` de classe nossa — o painel some do fluxo de acessibilidade mas
|
|
306
|
+
continua na tela. Já mordeu o popover do MediaPlayer e as abas do catálogo. Aqui a
|
|
307
|
+
regra fecha a classe inteira do bug, em vez de um remendo por componente.
|
|
308
|
+
`until-found` fica de fora: ali o `hidden` é revelável e o browser cuida. */
|
|
309
|
+
[hidden]:not([hidden="until-found"]) { display:none!important; }
|
|
310
|
+
.sr-only { position:absolute!important; width:1px!important; height:1px!important; padding:0!important; margin:-1px!important; overflow:hidden!important; clip:rect(0,0,0,0)!important; white-space:nowrap!important; border:0!important; }
|
|
311
|
+
.icon { width:var(--icon-md); height:var(--icon-md); fill:currentColor; flex:none; }
|
|
312
|
+
.icon-sm { width:var(--icon-sm); height:var(--icon-sm); } .icon-lg { width:var(--icon-lg); height:var(--icon-lg); } .icon-xl { width:var(--icon-xl); height:var(--icon-xl); }
|
|
313
|
+
.muted { color:var(--muted-foreground); }
|
|
314
|
+
.stack { display:flex; flex-direction:column; gap:var(--space-4); }
|
|
315
|
+
.cluster { display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-3); }
|
|
316
|
+
/* Grid: o terceiro primitivo de layout, com o mesmo gap do .stack. A pele nasceu na Fase 11
|
|
317
|
+
(achado A13): o componente existia desde sempre e saía `display:block` — empilhava. Ninguém
|
|
318
|
+
via porque o chrome do catálogo REDEFINIA .grid, então ele parecia pronto na nossa
|
|
319
|
+
documentação e chegava sem nada no consumidor. `min(...,100%)` porque `minmax(15rem,1fr)`
|
|
320
|
+
estoura o contêiner quando o texto vai a 200% e a coluna fica maior que a caixa (lição do
|
|
321
|
+
M12); --grid-min é o botão de ajuste, no idioma de --qr-module e --demo-height. */
|
|
322
|
+
.grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(min(var(--grid-min,15rem),100%),1fr)); gap:var(--space-4); }
|
|
323
|
+
|
|
324
|
+
/* ========================================================================== */
|
|
325
|
+
/* 03. APP SHELL E DOCUMENTAÇÃO */
|
|
326
|
+
/* ========================================================================== */
|
|
327
|
+
/* Regiões do AppShell — SUPERFÍCIES FLUTUANTES (decisão do Victor, 23/07/2026): topo,
|
|
328
|
+
lateral e conteúdo são caixas soltas de raio --radius-card, separadas por --space-4 e
|
|
329
|
+
descoladas da borda da janela pelo padding do shell. NADA de barra colada com linha
|
|
330
|
+
divisória: caixa retangular genérica é proibida (CLAUDE.md).
|
|
331
|
+
Arranjo escolhido: o TOPO atravessa toda a largura (grid-column 1/-1) e leva a marca;
|
|
332
|
+
a lateral começa abaixo dele. Ambos grudam na rolagem por `sticky` — o conteúdo passa
|
|
333
|
+
por baixo e as duas caixas seguem visíveis.
|
|
334
|
+
ATENÇÃO: `.app-shell` NÃO se toca. O catálogo escrito à mão (apps/docs) usa essa MESMA
|
|
335
|
+
classe como raiz, com filhos próprios (.doc-sidebar/.main-wrap) — mexer nela desloca as
|
|
336
|
+
26 telas de referência inteiras (aconteceu; o portão visual pegou). Por isso a folga
|
|
337
|
+
entre as caixas sai da MARGEM de cada filho, não de gap/padding no shell. As linhas
|
|
338
|
+
extras do grid nascem sozinhas por auto-placement. */
|
|
339
|
+
.app-shell { min-height:100vh; display:grid; grid-template-columns:var(--sidebar-width) minmax(0,1fr); background:var(--background); }
|
|
340
|
+
/* A base do topo carrega só o ARRANJO; cada variante traz a própria superfície.
|
|
341
|
+
floating = caixa solta (a que já estava) · flush = faixa encostada nas bordas com fio
|
|
342
|
+
embaixo, para o topo virar moldura da janela · pill = cápsula centrada, de cabeçalho
|
|
343
|
+
de site. Só floating e flush entram no grid do AppShell; a pill é peça avulsa (numa
|
|
344
|
+
pílula não cabem busca + densidade + tema + comando). */
|
|
345
|
+
.topbar { grid-column:1/-1; position:sticky; z-index:var(--z-sticky); display:flex; align-items:center; justify-content:space-between; gap:var(--space-4); min-height:var(--topbar-height); }
|
|
346
|
+
.topbar-floating { top:var(--space-4); margin:var(--space-4) var(--space-4) 0; padding:var(--space-2) var(--space-4); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); color:var(--card-foreground); }
|
|
347
|
+
/* flush: encostada nas bordas. SEM fio embaixo (pedido do Victor — a referência não tem)
|
|
348
|
+
e sem superfície própria: ela se funde ao fundo e cola no conteúdo, que começa logo
|
|
349
|
+
abaixo. É o topo do nosso catálogo. */
|
|
350
|
+
.topbar-flush { top:0; padding:var(--space-2) var(--space-5); background:var(--background); }
|
|
351
|
+
.topbar-pill { top:var(--space-4); width:max-content; max-width:calc(100% - var(--space-8)); margin:var(--space-4) auto 0; justify-content:flex-start; gap:var(--space-2); padding:var(--space-2); border:1px solid var(--border); border-radius:var(--radius-control); background:var(--card); color:var(--card-foreground); }
|
|
352
|
+
/* .brand nasceu como cabeçalho VERTICAL da lateral (borda embaixo + respiro); no topo
|
|
353
|
+
ele deita, então some com a borda e a margem — o lockup em si continua o mesmo. */
|
|
354
|
+
.topbar .brand { min-height:auto; margin:0; padding:0; border:0; }
|
|
355
|
+
/* altura fixa = janela menos topo e as 3 folgas; assim a caixa parece cheia mesmo com
|
|
356
|
+
poucos itens (é o que as referências mostram) e sobra o que rolar por dentro. */
|
|
357
|
+
.sidebar { --shell-top:calc(var(--topbar-height) + var(--space-4)*2); position:sticky; top:var(--shell-top); align-self:start; height:calc(100vh - var(--shell-top) - var(--space-4)); margin:var(--space-4); display:flex; flex-direction:column; gap:var(--space-1); padding:var(--space-4); overflow:auto; scrollbar-width:none; border:1px solid var(--sidebar-border); border-radius:var(--radius-card); background:var(--sidebar); color:var(--sidebar-foreground); }
|
|
358
|
+
/* a lateral ROLA mas nunca mostra a barra (pedido do Victor): a barra nativa risca a
|
|
359
|
+
superfície flutuante e não segue o raio de 22px. `scrollbar-width` cobre Firefox e
|
|
360
|
+
Chrome 121+; o pseudo cobre Safari e Chrome antigo. */
|
|
361
|
+
.sidebar::-webkit-scrollbar { width:0; height:0; }
|
|
362
|
+
/* com o topo `flush` a barra COLA no conteúdo (pedido do Victor): a folga acima da lateral
|
|
363
|
+
e do conteúdo é --space-1 (4px), e o --shell-top acompanha. */
|
|
364
|
+
/* flush cola no conteúdo com --space-05 (2px) — o degrau mais apertado da escala, criado
|
|
365
|
+
pra este caso (o Victor aprovou os 2px; tokenizado, não cru). */
|
|
366
|
+
.app-shell-flush .sidebar { --shell-top:calc(var(--topbar-height) + var(--space-05)); margin-block-start:var(--space-05); }
|
|
367
|
+
.app-shell-flush .content { margin-block-start:var(--space-05); }
|
|
368
|
+
.content { min-width:0; margin:var(--space-4) var(--space-4) var(--space-4) 0; padding:var(--space-6); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); color:var(--card-foreground); }
|
|
369
|
+
/* O topo é presentational — não conhece o conteúdo — então garante o mínimo universal:
|
|
370
|
+
os filhos encolhem em vez de forçar rolagem lateral. O COLAPSO de conteúdo (esconder a
|
|
371
|
+
busca, trocar a nav por menu) é do consumidor, com os utilitários responsivos abaixo. */
|
|
372
|
+
.topbar > * { min-width:0; }
|
|
373
|
+
/* QUEBRA POR CONTEÚDO. O `flex-wrap` vivia só dentro do @media abaixo, ou seja, a barra só
|
|
374
|
+
quebrava quando a JANELA era estreita. Texto a 200% (WCAG 1.4.4) aumenta o conteúdo sem
|
|
375
|
+
mexer no viewport: o @media não disparava e a nav passava 27px da borda direita, em todas
|
|
376
|
+
as páginas. Quebrar por conteúdo cobre os dois casos e não muda nada quando cabe. */
|
|
377
|
+
.topbar,.topbar > nav { flex-wrap:wrap; }
|
|
378
|
+
/* Colapso do shell abaixo de md (767 = md-1, escala): a lateral deixa de flutuar e de ter
|
|
379
|
+
altura de janela — empilha acima do conteúdo, que passa a ocupar a largura toda. Sem
|
|
380
|
+
estado (o off-canvas com botão é refino da Fase 3); o essencial é nunca rolar de lado. */
|
|
381
|
+
/* Abaixo de md o topo QUEBRA em duas linhas em vez de esconder a navegação: perder o acesso
|
|
382
|
+
a uma área inteira não é colapso responsivo, é bug. A nav vai pra segunda linha, centrada
|
|
383
|
+
e na largura toda; badge e selo (secundários) seguem escondidos pelos utilitários. */
|
|
384
|
+
@media (max-width:767px) { .app-shell { grid-template-columns:minmax(0,1fr); } .sidebar { position:static; height:auto; } .content { margin-inline-start:var(--space-4); }
|
|
385
|
+
.topbar { flex-wrap:wrap; row-gap:var(--space-2); }
|
|
386
|
+
.topbar > nav { order:3; flex-basis:100%; justify-content:center; }
|
|
387
|
+
/* e a nav quebra entre os PRÓPRIOS itens: mandar a barra pra segunda linha não bastava,
|
|
388
|
+
as cinco áreas somam 371px e estouravam a 320px (auditoria 26/07, A1). */
|
|
389
|
+
.topbar > nav { flex-wrap:wrap; row-gap:var(--space-1); } }
|
|
390
|
+
|
|
391
|
+
/* ── GAVETA DE NAVEGAÇÃO (achado A8) ───────────────────────────────────────────────
|
|
392
|
+
Empilhar a lateral acima do conteúdo passava, no gate de rolagem lateral, e era
|
|
393
|
+
inutilizável: medido em 375px, o `h1` da página começava 4,6 telas abaixo, atrás dos 65
|
|
394
|
+
itens da navegação. Abaixo de md ela sai do fluxo e vira gaveta.
|
|
395
|
+
SEM UMA LINHA DE JS: o <aside> é um popover nativo e o botão do topo é o invoker. O
|
|
396
|
+
navegador entrega Escape, clique fora para fechar, `aria-expanded` no disparador, a volta
|
|
397
|
+
do foco ao fechar e o ::backdrop. Baseline desde 04/2025; verificado em 30/07/2026.
|
|
398
|
+
Não-modal de propósito (o foco não fica preso), como o CommandPaletteShell: declarar
|
|
399
|
+
modalidade sem entregá-la é pior que não declarar. */
|
|
400
|
+
.btn.nav-toggle { display:none; }
|
|
401
|
+
/* O UA aplica um bloco inteiro a `[popover]` mesmo FECHADO — `width:fit-content`, `inset:0`,
|
|
402
|
+
`margin:auto`, borda e padding próprios. A `.sidebar` já sobrescreve quase tudo; sobravam
|
|
403
|
+
largura e insets, e isso encolheu a lateral do DESKTOP de 232px para 225px. Quem pegou foi o
|
|
404
|
+
gate de pixel, não o olho: 4.573 pixels de diferença numa captura de 0,03 de proporção. */
|
|
405
|
+
.sidebar[popover]:not(:popover-open) { width:auto; inset-inline:auto; inset-block-end:auto; }
|
|
406
|
+
/* Quem esconde a gaveta fechada é ESTA regra, não o `display:none` do UA para `[popover]`:
|
|
407
|
+
regra de autor vence regra de UA por ORIGEM, e a `.sidebar` já declara `display:flex`.
|
|
408
|
+
Medido: sem esta linha a lateral seguia empilhada em 375px, com o botão já visível.
|
|
409
|
+
O @supports é a rede: em navegador sem popover a regra inteira não aplica, a lateral volta a
|
|
410
|
+
empilhar (o comportamento de antes, feio e usável) em vez de sumir sem botão que a abra. */
|
|
411
|
+
@supports selector(:popover-open) {
|
|
412
|
+
@media (max-width:767px) {
|
|
413
|
+
.sidebar[popover]:not(:popover-open) { display:none; }
|
|
414
|
+
.btn.nav-toggle { display:inline-flex; }
|
|
415
|
+
/* altura EXPLÍCITA, não `auto`: medido em 30/07/2026, com `top` e `bottom` postos e
|
|
416
|
+
`height:auto` o Chromium resolveu pela altura do CONTEÚDO (3.498px de lateral rolando a
|
|
417
|
+
página inteira), não pelas âncoras. `dvh` porque a barra do navegador móvel some e volta. */
|
|
418
|
+
.sidebar[popover]:popover-open { position:fixed; inset-block:var(--space-4); inset-inline-start:var(--space-4); width:min(20rem,calc(100vw - var(--space-8))); height:calc(100dvh - var(--space-4) * 2); margin:0; }
|
|
419
|
+
.sidebar[popover]::backdrop { background:var(--overlay); }
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/* ── A LISTA DA LATERAL (PLANO-1.0, item B1) ───────────────────────────────────────
|
|
424
|
+
Até 06/08/2026 a Sidebar era só a caixa: item, grupo, aninhamento e marca de item atual
|
|
425
|
+
existiam neste arquivo como `.doc-nav`, que é CHROME do catálogo (achado A6) e nunca foi
|
|
426
|
+
API pública. Consequência medida: nenhum consumidor conseguia desenhar uma navegação sem
|
|
427
|
+
reescrevê-la, e a peça já estava aqui.
|
|
428
|
+
ITEM ATUAL por [aria-current] e não por uma classe `.active`: o estado que o leitor de tela
|
|
429
|
+
anuncia e o que o olho vê passam a ser o MESMO atributo, então não há como marcar um e
|
|
430
|
+
esquecer o outro — que é como o `.doc-nav` carrega `.active` E `aria-current` até hoje. */
|
|
431
|
+
.sidebar-nav { display:flex; flex-direction:column; gap:var(--space-1); }
|
|
432
|
+
.sidebar-list { display:flex; flex-direction:column; gap:var(--space-1); margin:0; padding:0; list-style:none; }
|
|
433
|
+
/* `width:100%` + `font:inherit` + `border:0`: o item também é <button> quando não navega, e
|
|
434
|
+
sem isto o botão vem com a caixa do navegador e quebra a fila. */
|
|
435
|
+
.sidebar-item { display:flex; align-items:center; gap:var(--space-2); width:100%; min-height:var(--control-h-md); padding:var(--space-1) var(--space-3); border:0; border-radius:var(--radius-control); background:transparent; color:var(--sidebar-foreground); font:inherit; font-size:var(--text-sm); text-align:start; text-decoration:none; cursor:pointer; }
|
|
436
|
+
.sidebar-item .icon { flex:none; opacity:.8; }
|
|
437
|
+
/* min-width:0 é o que deixa o ellipsis funcionar dentro do flex; sem ele o nome longo empurra
|
|
438
|
+
o acessório para fora da caixa em vez de cortar. */
|
|
439
|
+
.sidebar-label { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
440
|
+
@media (hover:hover) and (pointer:fine) { .sidebar-item:hover { background:var(--secondary); } }
|
|
441
|
+
.sidebar-item[aria-current] { background:var(--secondary); color:var(--foreground); font-weight:var(--weight-medium); }
|
|
442
|
+
.sidebar-item[aria-current] .icon { opacity:1; }
|
|
443
|
+
.sidebar-group-label { margin:var(--space-3) var(--space-2) var(--space-1); color:var(--subtle-foreground); font-size:var(--text-xs); font-weight:var(--weight-medium); letter-spacing:var(--tracking-widest); text-transform:uppercase; }
|
|
444
|
+
.sidebar-sub { padding-inline-start:var(--space-5); }
|
|
445
|
+
/* RECOLHIDA — a lateral vira trilho de ícones. O rótulo NÃO some do DOM: o React troca a
|
|
446
|
+
classe dele por `.sr-only`, então quem usa leitor de tela continua ouvindo o nome. Ícone
|
|
447
|
+
sozinho não nomeia nada, e essa é a falha clássica do padrão de trilho. */
|
|
448
|
+
.sidebar-collapsed { padding-inline:var(--space-2); }
|
|
449
|
+
.sidebar-collapsed .sidebar-item { justify-content:center; padding-inline:var(--space-2); }
|
|
450
|
+
.sidebar-collapsed .sidebar-sub { padding-inline-start:0; }
|
|
451
|
+
/* A ÚNICA regra que toca `.app-shell`, e está aqui porque a coluna do grid é do shell: a
|
|
452
|
+
lateral não consegue encolher a própria coluna.
|
|
453
|
+
O `>` NÃO É ENFEITE, e quem achou isso foi o navegador em 06/08/2026. Escrita como
|
|
454
|
+
`:has(.sidebar-collapsed)`, a regra casa com QUALQUER descendente — e a página do catálogo
|
|
455
|
+
que mostra uma lateral recolhida como EXEMPLO, dentro do <main>, recolhia a lateral de
|
|
456
|
+
verdade do documento inteiro. Medido: a coluna do shell saía 88px numa página que não pediu
|
|
457
|
+
nada. Gate nenhum via, porque `sidebar.html` não tem baseline de pixel. */
|
|
458
|
+
.app-shell:has(> .sidebar-collapsed) { grid-template-columns:var(--sidebar-rail) minmax(0,1fr); }
|
|
459
|
+
|
|
460
|
+
/* ── Visibilidade responsiva — o mecanismo PADRÃO de colapsar uma barra ─────────────
|
|
461
|
+
Regra do projeto (enraizada): todo layout horizontal que aperta esconde o secundário
|
|
462
|
+
por breakpoint da escala, nunca rola de lado. Estas 4 classes são esse mecanismo; o
|
|
463
|
+
gate (check 4b) trava os breakpoints. Mobile-first: `below` some acima do ponto. */
|
|
464
|
+
@media (max-width:1023px) { .hide-below-lg { display:none !important; } }
|
|
465
|
+
@media (max-width:767px) { .hide-below-md { display:none !important; } }
|
|
466
|
+
.brand { min-height:var(--topbar-height); display:flex; align-items:center; gap:12px; padding:2px 4px 16px; margin:0 0 16px; border:0; border-bottom:1px solid var(--sidebar-border); border-radius:0; background:transparent; box-shadow:none; }
|
|
467
|
+
.brand strong { display:block; letter-spacing:var(--tracking-tight); } .brand small { display:block; color:var(--muted-foreground); font-size:11px; }
|
|
468
|
+
/* minmax(0,1fr): a trilha `auto` do grid crescia até o nome mais longo e os itens
|
|
469
|
+
VAZAVAM pela direita da caixa (colavam na borda de um lado e sobrava do outro). */
|
|
470
|
+
.doc-nav { padding:0 0 8px; display:grid; grid-template-columns:minmax(0,1fr); gap:var(--space-1); }
|
|
471
|
+
/* .nav-group-label é o rótulo de categoria SEM ser título de documento: mesma aparência do
|
|
472
|
+
h4 histórico, mas o grupo se nomeia por aria-labelledby e não entra na lista de títulos
|
|
473
|
+
do leitor de tela (senão a lateral vem antes do h1 da página). É o jeito preferido. */
|
|
474
|
+
.doc-nav h4,.doc-nav .nav-group-label { margin:16px 8px 8px; color:var(--subtle-foreground); font-size:11px; letter-spacing:var(--tracking-widest); text-transform:uppercase; }
|
|
475
|
+
.doc-nav .nav-group { display:grid; gap:var(--space-1); }
|
|
476
|
+
.doc-nav a { display:flex; align-items:center; gap:10px; min-height:40px; margin:0; padding:9px 12px; border:1px solid transparent; border-radius:var(--radius-lg); background:transparent; color:var(--muted-foreground); text-decoration:none; box-shadow:none; }
|
|
477
|
+
.doc-nav a:hover { color:var(--sidebar-accent-foreground); background:var(--sidebar-accent); border-color:var(--sidebar-border); }
|
|
478
|
+
.doc-nav a.active { border-color:var(--sidebar-border); }
|
|
479
|
+
/* o glifo da família fica na frente do rótulo e nunca encolhe o texto */
|
|
480
|
+
.doc-nav a .icon { flex:none; opacity:.8; }
|
|
481
|
+
.doc-nav a.active .icon { opacity:1; }
|
|
482
|
+
.eyebrow { display:inline-flex; align-items:center; gap:8px; color:var(--primary); font-size:12px; font-weight:var(--weight-bold); letter-spacing:var(--tracking-widest); text-transform:uppercase; }
|
|
483
|
+
/* No claro o amarelo puro como texto não alcança 4.5:1 (axe). Aprofundar com --foreground
|
|
484
|
+
mantém o matiz da marca e passa o AA; no escuro segue o amarelo cheio. */
|
|
485
|
+
[data-theme="light"] .eyebrow { color:color-mix(in oklab, var(--primary) 45%, var(--foreground)); }
|
|
486
|
+
.demo { min-width:0; padding:var(--card-pad); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); color:var(--card-foreground); box-shadow:none; }
|
|
487
|
+
|
|
488
|
+
/* ========================================================================== */
|
|
489
|
+
/* 04. COMPONENTES PRIMITIVOS */
|
|
490
|
+
/* ========================================================================== */
|
|
491
|
+
.btn { --btn-bg:transparent; --btn-fg:var(--foreground); --btn-border:transparent; display:inline-flex; align-items:center; justify-content:center; gap:8px; height:var(--control-h-md); padding:0 15px; border:1px solid var(--btn-border); border-radius:var(--radius-control); background:var(--btn-bg); color:var(--btn-fg); font-size:var(--text-sm); font-weight:var(--weight-medium); line-height:var(--leading-none); text-decoration:none; white-space:nowrap; cursor:pointer; transition:transform var(--duration-fast) var(--ease-standard),background var(--duration-fast),border-color var(--duration-fast),color var(--duration-fast),opacity var(--duration-fast); }
|
|
492
|
+
.btn:hover:not(:disabled):not([aria-disabled="true"]) { transform:none; } .btn:active:not(:disabled) { transform:scale(.97); opacity:.9; }
|
|
493
|
+
/* Duas formas de "não dá para fazer isto", e a diferença é QUEM alcança a explicação.
|
|
494
|
+
`:disabled` tira o controle da ordem de foco — medido em 13/08/2026: quem usa teclado nunca
|
|
495
|
+
chega nele, então uma dica pendurada ali não é lida por ninguém. O embrulho de <span> que a
|
|
496
|
+
referência do MUI documenta resolve o ponteiro e NÃO resolve o teclado (o span nasce com
|
|
497
|
+
tabIndex -1, medido). `[aria-disabled="true"]` mantém o controle focável e inerte — é ele
|
|
498
|
+
que se usa quando existe um PORQUÊ a dizer. A pele é a mesma; o que muda é o alcance. */
|
|
499
|
+
.btn:disabled,.btn[aria-disabled="true"] { opacity:.45; cursor:not-allowed; }
|
|
500
|
+
/* Cinco alturas, todas de token de densidade (autorizado pelo Victor em 24/07/2026). O raio
|
|
501
|
+
é pill em TODAS — o tamanho muda altura e respiro, nunca a forma. Em ponteiro grosso o
|
|
502
|
+
mínimo de 44px lá embaixo pega o xs e o sm, então alvo pequeno não vira alvo impossível. */
|
|
503
|
+
.btn-xs { height:var(--control-h-xs); padding:0 10px; gap:6px; font-size:var(--text-xs); border-radius:var(--radius-control); }
|
|
504
|
+
.btn-sm { height:var(--control-h-sm); padding:0 12px; font-size:var(--text-xs); border-radius:var(--radius-control); }
|
|
505
|
+
.btn-lg { height:var(--control-h-lg); padding:0 20px; font-size:var(--text-base); border-radius:var(--radius-control); }
|
|
506
|
+
.btn-xl { height:var(--control-h-xl); padding:0 26px; gap:10px; font-size:var(--text-base); border-radius:var(--radius-control); }
|
|
507
|
+
/* Largura total: para rodapé de formulário e tela estreita. Só a largura muda. */
|
|
508
|
+
.btn-block { width:100%; }
|
|
509
|
+
.btn-primary { --btn-bg:var(--primary); --btn-fg:var(--primary-foreground); --btn-border:transparent; }
|
|
510
|
+
.btn-primary:hover:not(:disabled):not([aria-disabled="true"]) { --btn-bg:var(--primary-hover); --btn-border:transparent; }
|
|
511
|
+
.btn-secondary { --btn-bg:var(--secondary); --btn-fg:var(--secondary-foreground); --btn-border:transparent; }
|
|
512
|
+
.btn-secondary:hover:not(:disabled):not([aria-disabled="true"]) { --btn-bg:var(--secondary-hover); --btn-border:transparent; }
|
|
513
|
+
.btn-outline { --btn-bg:transparent; --btn-fg:var(--foreground); --btn-border:var(--border-strong); }
|
|
514
|
+
.btn-outline:hover:not(:disabled):not([aria-disabled="true"]) { --btn-bg:var(--accent); }
|
|
515
|
+
.btn-ghost { --btn-bg:transparent; --btn-fg:var(--foreground); --btn-border:transparent; }
|
|
516
|
+
.btn-ghost:hover:not(:disabled):not([aria-disabled="true"]) { --btn-bg:var(--accent); --btn-fg:var(--accent-foreground); }
|
|
517
|
+
.btn-danger { --btn-bg:var(--destructive); --btn-fg:var(--destructive-foreground); --btn-border:transparent; }
|
|
518
|
+
.btn-danger:hover:not(:disabled):not([aria-disabled="true"]) { --btn-bg:var(--danger-400); }
|
|
519
|
+
/* Destrutivo em OUTRAS hierarquias: apagar não é sempre a ação principal da tela. O tom é o
|
|
520
|
+
mesmo (--destructive); o que muda é o peso. No claro o vermelho puro como texto não chega
|
|
521
|
+
a 4.5:1, então aprofunda com --foreground — mesmo tratamento do amarelo. */
|
|
522
|
+
.btn-danger-outline { --btn-bg:transparent; --btn-fg:var(--destructive); --btn-border:var(--destructive); }
|
|
523
|
+
.btn-danger-outline:hover:not(:disabled):not([aria-disabled="true"]) { --btn-bg:color-mix(in oklab, var(--destructive) 14%, transparent); }
|
|
524
|
+
.btn-danger-ghost { --btn-bg:transparent; --btn-fg:var(--destructive); --btn-border:transparent; }
|
|
525
|
+
.btn-danger-ghost:hover:not(:disabled):not([aria-disabled="true"]) { --btn-bg:color-mix(in oklab, var(--destructive) 14%, transparent); }
|
|
526
|
+
[data-theme="light"] .btn-danger-outline,[data-theme="light"] .btn-danger-ghost,[data-theme="light"] .btn-link-danger { --btn-fg:color-mix(in oklab, var(--destructive) 62%, var(--foreground)); }
|
|
527
|
+
/* LINK: aparência de texto, sem cápsula e sem altura de controle — o sublinhado é o que diz
|
|
528
|
+
que é clicável, então ele existe desde o repouso (revelar no hover esconde a affordance).
|
|
529
|
+
Três tons: neutro, marca e destrutivo. No claro a marca aprofunda, senão não passa o AA. */
|
|
530
|
+
/* `min-height:24px` = WCAG 2.2 SC 2.5.8. A exceção de "alvo em linha" NÃO cobre este caso:
|
|
531
|
+
medido no catálogo, o "Learn more" é ação isolada dentro de um flex, não link no meio de
|
|
532
|
+
prosa, e media 67×13px. O texto continua onde está — a caixa cresce centrada nele. */
|
|
533
|
+
.btn-link { height:auto; min-height:24px; padding:0; gap:6px; border:0; border-radius:var(--radius-sm); --btn-bg:transparent; --btn-fg:var(--foreground); text-decoration:underline; text-underline-offset:3px; text-decoration-thickness:1px; }
|
|
534
|
+
.btn-link:hover:not(:disabled):not([aria-disabled="true"]) { text-decoration-thickness:2px; }
|
|
535
|
+
.btn-link-primary { --btn-fg:var(--primary); }
|
|
536
|
+
[data-theme="light"] .btn-link-primary { --btn-fg:color-mix(in oklab, var(--primary) 45%, var(--foreground)); }
|
|
537
|
+
.btn-link-danger { --btn-fg:var(--destructive); }
|
|
538
|
+
/* pressed entra na linguagem única de "selecionado" acima; só-ícone não leva o fio. */
|
|
539
|
+
/* Kbd — a tecla que dispara a ação, dentro ou fora do botão. Peça própria, não decoração. */
|
|
540
|
+
.kbd { display:inline-flex; align-items:center; justify-content:center; gap:2px; min-width:20px; height:20px; padding:0 6px; border:1px solid var(--border-strong); border-radius:var(--radius-sm); background:var(--secondary); color:var(--muted-foreground); font:500 11px/1 var(--font-code); }
|
|
541
|
+
/* dentro do botão a tecla herda a cor do rótulo, SEM opacidade: a 85% o contraste caía
|
|
542
|
+
para 3.67:1 (axe) e o atalho é informação, não enfeite. O fundo já o separa. */
|
|
543
|
+
/* Dentro do botão a tecla NÃO ganha fundo próprio: qualquer tinta escurece a cápsula e o
|
|
544
|
+
rótulo perde contraste (no primary claro caiu a 3.55:1). Sem fundo, o contraste da
|
|
545
|
+
tecla é o MESMO do rótulo — se o botão passa, ela passa. A borda de currentColor separa. */
|
|
546
|
+
.btn .kbd { background:transparent; border-color:color-mix(in oklab, currentColor 35%, transparent); color:inherit; }
|
|
547
|
+
|
|
548
|
+
/* nav: item de navegação. Normal = ghost silencioso; o ATIVO (aria-current) ganha texto
|
|
549
|
+
amarelo + traço embaixo — SEM borda (pedido do Victor). aria-current, não uma variante
|
|
550
|
+
"ativa", porque ele também anuncia "página atual" pro leitor de tela. O traço é
|
|
551
|
+
::after, pill, alinhado ao padding do texto; posição pelo eixo bloco (não espelha RTL). */
|
|
552
|
+
.btn-nav { --btn-bg:transparent; --btn-fg:var(--muted-foreground); --btn-border:transparent; }
|
|
553
|
+
.btn-nav:hover:not(:disabled):not([aria-disabled="true"]) { --btn-fg:var(--foreground); }
|
|
554
|
+
.btn-icon { width:var(--control-h-md); padding:0; border-radius:var(--radius-md); }
|
|
555
|
+
.btn-icon.btn-xs { width:var(--control-h-xs); border-radius:var(--radius-sm); }
|
|
556
|
+
.btn-icon.btn-sm { width:var(--control-h-sm); border-radius:var(--radius-sm); } .btn-icon.btn-lg { width:var(--control-h-lg); border-radius:var(--radius-md); }
|
|
557
|
+
/* xs e xl também precisam de largura: sem isto a altura mudava e a largura ficava na do
|
|
558
|
+
md, e o alvo só-ícone deixava de ser quadrado (achado na onda Actions, 24/07). */
|
|
559
|
+
.btn-icon.btn-xl { width:var(--control-h-xl); border-radius:var(--radius-md); }
|
|
560
|
+
/* wrap, não estoura: os botões do grupo são pills com gap (não segmentos colados), então
|
|
561
|
+
quebrar linha em tela estreita preserva o visual. Único gap de eixo horizontal que a
|
|
562
|
+
auditoria da Etapa 3 achou sem proteção — o resto já rola (tabela) ou já quebra (toolbar). */
|
|
563
|
+
.btn-group { display:inline-flex; flex-wrap:wrap; align-items:center; gap:4px; } .btn-group .btn { border-radius:var(--radius-control); margin-inline-start:0; }
|
|
564
|
+
.btn-group .btn:first-child { margin-inline-start:0; border-radius:var(--radius-control); }
|
|
565
|
+
.btn-group .btn:last-child { border-radius:var(--radius-control); }
|
|
566
|
+
/* Toolbar: contêiner de controles; o roving tabindex vem do Base UI. */
|
|
567
|
+
.toolbar { display:flex; align-items:center; flex-wrap:wrap; gap:6px; padding:6px; border:1px solid var(--border); border-radius:var(--radius-control); background:var(--secondary); }
|
|
568
|
+
/* Vertical sai da pílula: --radius-control (999px) clampa em 50% da menor
|
|
569
|
+
dimensão e vira um oval num container alto. */
|
|
570
|
+
.toolbar[data-orientation="vertical"] { flex-direction:column; align-items:stretch; border-radius:var(--radius-lg); }
|
|
571
|
+
.toolbar-group { display:flex; align-items:center; gap:var(--space-1); }
|
|
572
|
+
.toolbar-sep { flex:none; align-self:stretch; inline-size:1px; min-block-size:20px; margin-inline:4px; margin-block:0; background:var(--border); border:0; }
|
|
573
|
+
.toolbar[data-orientation="vertical"] .toolbar-sep { align-self:auto; inline-size:auto; block-size:1px; min-block-size:0; margin-inline:0; margin-block:4px; }
|
|
574
|
+
/* Spinner: o glifo existia desde sempre e só era usado por dentro do Button. Ganhou componente
|
|
575
|
+
e escala no Lote 1, e o eixo passou a ser o dos ÍCONES — mas o tamanho base continua o que
|
|
576
|
+
sempre foi: `--icon-sm` são os mesmos 16px de antes, então nenhum botão em nenhuma página
|
|
577
|
+
mudou de aparência. Cheguei a apontar o base para `--icon-md` (20px) e os baselines de pixel
|
|
578
|
+
acusaram na hora: teria trocado o tamanho do spinner dentro de todo botão sem ninguém pedir.
|
|
579
|
+
A casa do spinner é dentro de um controle, ao lado de texto; os degraus maiores existem para
|
|
580
|
+
quando ele é a única coisa na tela. */
|
|
581
|
+
.spinner { width:var(--icon-sm); height:var(--icon-sm); border:2px solid currentColor; border-right-color:transparent; border-radius:50%; animation:spin .7s linear infinite; }
|
|
582
|
+
.spinner-md { width:var(--icon-md); height:var(--icon-md); }
|
|
583
|
+
.spinner-lg { width:var(--icon-lg); height:var(--icon-lg); } @keyframes spin { to { transform:rotate(360deg); } }
|
|
584
|
+
|
|
585
|
+
.field { display:flex; flex-direction:column; gap:7px; }
|
|
586
|
+
.label { display:flex; justify-content:space-between; gap:12px; color:var(--foreground); font-size:var(--text-sm); font-weight:var(--weight-semibold); }
|
|
587
|
+
.hint { color:var(--muted-foreground); font-size:var(--text-xs); }
|
|
588
|
+
.input,.textarea,.select { width:100%; min-width:0; height:var(--control-h-md); padding:0 13px; color:var(--foreground); background:var(--field-bg); border:1px solid var(--border-strong); border-radius:var(--radius-control); transition:border-color var(--duration-fast),background-color var(--duration-fast),box-shadow var(--duration-fast); }
|
|
589
|
+
.input:hover,.textarea:hover,.select:hover { border-color:var(--border); }
|
|
590
|
+
.input::placeholder,.textarea::placeholder { color:var(--subtle-foreground); }
|
|
591
|
+
.input:disabled,.textarea:disabled,.select:disabled { opacity:.5; cursor:not-allowed; }
|
|
592
|
+
.input[aria-invalid="true"],.textarea[aria-invalid="true"] { border-color:var(--danger-400); }
|
|
593
|
+
.textarea { min-height:104px; padding:12px 14px; resize:vertical; border-radius:var(--radius-lg); }
|
|
594
|
+
/* chevron: cor = --muted-foreground de cada tema (dark #a1a1a1, light #505050); tokenizar na Fase 1 */
|
|
595
|
+
.select { appearance:none; padding-inline-end:38px; background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%23a1a1a1' stroke-width='1.6'/%3E%3C/svg%3E"); background-position:calc(100% - 12px) 50%; background-size:12px 8px; background-repeat:no-repeat; }
|
|
596
|
+
[data-theme="light"] .select { background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%23505050' stroke-width='1.6'/%3E%3C/svg%3E"); }
|
|
597
|
+
/* Widgets nativos dos campos (calendário do type=date, dropdown do select, scrollbar do textarea) seguem o tema */
|
|
598
|
+
.input,.textarea,.select { color-scheme:dark; }
|
|
599
|
+
[data-theme="light"] .input,[data-theme="light"] .textarea,[data-theme="light"] .select { color-scheme:light; }
|
|
600
|
+
/* NumberField (Lote 1): menos · campo · mais numa peça só, que é onde as referências convergem.
|
|
601
|
+
O campo é `.input` — a mesma altura, o mesmo raio, o mesmo foco de qualquer campo do sistema.
|
|
602
|
+
Largura em token para caber de 3 a 4 dígitos sem virar caixa de texto. */
|
|
603
|
+
.number-field { display:inline-flex; }
|
|
604
|
+
.number-field-group { display:inline-flex; align-items:center; gap:var(--space-1); }
|
|
605
|
+
.number-field-input { width:var(--space-16); text-align:center; }
|
|
606
|
+
/* OTPField (Lote 1): um quadrado por dígito. O lado é a altura de controle, então a fila mede o
|
|
607
|
+
mesmo que qualquer campo ao lado dela; o padding zera porque o dígito é centralizado. */
|
|
608
|
+
.otp-field { display:inline-flex; align-items:center; gap:var(--space-2); }
|
|
609
|
+
.otp-slot { width:var(--control-h-md); padding:0; text-align:center; font-family:var(--font-code); }
|
|
610
|
+
/* HoverCard (Lote 1) reusa `.popover`; só limita a largura, porque prévia é conteúdo, não rótulo. */
|
|
611
|
+
.hover-card { max-width:min(20rem,calc(100vw - var(--space-8))); }
|
|
612
|
+
.input-wrap { position:relative; } .input-wrap>.icon { position:absolute; inset-inline-start:12px; top:50%; transform:translateY(-50%); color:var(--subtle-foreground); pointer-events:none; } .input-wrap .input { padding-inline-start:40px; }
|
|
613
|
+
/* Form (M1): empilhar campos com respiro. Nada além disso — sem borda, sem fundo, sem largura.
|
|
614
|
+
Formulário é ARRANJO, e arranjo é do Stack/Grid; se esta classe crescer, ela vira uma terceira
|
|
615
|
+
maneira de fazer layout e passa a brigar com as duas que já existem. */
|
|
616
|
+
.form { display:grid; gap:var(--space-5); }
|
|
617
|
+
.field-error { color:var(--danger-400); font-size:var(--text-xs); }
|
|
618
|
+
.checkbox,.radio { display:inline-flex; align-items:flex-start; gap:9px; color:var(--foreground); cursor:pointer; }
|
|
619
|
+
.checkbox input,.radio input { position:absolute; opacity:0; pointer-events:none; }
|
|
620
|
+
.control-mark { width:18px; height:18px; margin-top:1px; display:grid; place-items:center; border:1px solid var(--border-strong); background:var(--field-bg); }
|
|
621
|
+
.checkbox .control-mark { border-radius:5px; } .radio .control-mark { border-radius:50%; }
|
|
622
|
+
.checkbox input:checked + .control-mark { background:var(--control-selected); border-color:var(--control-selected); color:var(--control-selected-foreground); }
|
|
623
|
+
.checkbox input:focus-visible + .control-mark,.radio input:focus-visible + .control-mark,.switch input:focus-visible + .switch-track { outline:2px solid var(--focus-strong); outline-offset:2px; }
|
|
624
|
+
.checkbox input:checked + .control-mark:after { content:""; width:8px; height:4px; border-left:2px solid currentColor; border-bottom:2px solid currentColor; transform:rotate(-45deg) translateY(-1px); }
|
|
625
|
+
.radio input:checked + .control-mark:after { content:""; width:8px; height:8px; border-radius:50%; background:var(--control-selected); }
|
|
626
|
+
.switch { display:inline-flex; align-items:center; gap:10px; cursor:pointer; } .switch input { position:absolute; opacity:0; }
|
|
627
|
+
.switch-track { position:relative; width:42px; height:24px; border-radius:999px; background:var(--muted); border:1px solid var(--border); transition:background var(--duration-base) var(--ease-standard),border-color var(--duration-base) var(--ease-standard); }
|
|
628
|
+
.switch-track:after { content:""; position:absolute; inset-inline-start:3px; top:3px; width:16px; height:16px; border-radius:50%; background:var(--muted-foreground); transition:transform var(--duration-base) var(--ease-standard),background var(--duration-base) var(--ease-standard); }
|
|
629
|
+
.switch input:checked + .switch-track { background:var(--control-selected); border-color:var(--control-selected); } .switch input:checked + .switch-track:after { transform:translateX(18px); background:var(--control-selected-foreground); }
|
|
630
|
+
.range { width:100%; accent-color:var(--primary); }
|
|
631
|
+
/* A CÁPSULA é que tem de medir igual a um botão/campo ao lado — não o botão de dentro.
|
|
632
|
+
Antes: `height:30px` no filho, cru. Em comfortable dava 30+3+3=36 = --control-h-md por
|
|
633
|
+
coincidência; em compact a cápsula ficava 4px alta demais e em spacious 4px baixa demais,
|
|
634
|
+
porque a densidade não alcançava a regra (achado A1, 26/07/2026). Com a altura na cápsula
|
|
635
|
+
os filhos esticam sozinhos (align-items é stretch por padrão) e a conta fecha nas TRÊS. */
|
|
636
|
+
.segmented { display:inline-flex; gap:3px; padding:3px; min-height:var(--control-h-md); border-radius:var(--radius-control); background:var(--muted); border:1px solid transparent; box-shadow:none; }
|
|
637
|
+
.segmented button { padding:0 14px; border:0; border-radius:var(--radius-control); color:var(--muted-foreground); background:transparent; cursor:pointer; }
|
|
638
|
+
.segmented button.active { color:var(--foreground); background:var(--secondary); box-shadow:none; border:0; }
|
|
639
|
+
/* Toggle (Lote 1): pressionado usa o MESMO par de tokens do segmento aceso, logo acima. Um
|
|
640
|
+
toggle solto e um segmento selecionado dizem a mesma coisa — se parecessem diferentes, o
|
|
641
|
+
sistema teria dois idiomas para "isto está ligado". O estado vem do motor (`data-pressed`),
|
|
642
|
+
não de uma classe que alguém precisa lembrar de pôr. */
|
|
643
|
+
.toggle[data-pressed] { --btn-bg:var(--secondary); --btn-fg:var(--primary); }
|
|
644
|
+
/* ── SELECIONADO: uma linguagem só ────────────────────────────────────────────────────
|
|
645
|
+
Item de nav ativo, aba ativa, item de lista lateral e botão alternado ligado mostram o
|
|
646
|
+
MESMO sinal: cápsula elevada + rótulo na cor da marca + fio amarelo encostado na borda de
|
|
647
|
+
baixo. Um usuário aprende uma vez e reconhece em todo lugar (pedido do Victor, 24/07).
|
|
648
|
+
O fio é 2px (fração de pixel borra), inset 15px, e o amarelo entra a 75% — cheio ele
|
|
649
|
+
grita mais que o próprio rótulo. No tema CLARO o amarelo puro como texto dá 1.6:1, longe
|
|
650
|
+
dos 4.5:1 do AA, então o rótulo aprofunda com --foreground e segue âmbar. */
|
|
651
|
+
.is-selected,.btn-nav[aria-current]:not([aria-current="false"]),.btn[aria-pressed="true"],
|
|
652
|
+
.segmented button.active,.doc-nav a.active { --btn-bg:var(--secondary); --btn-fg:var(--primary); position:relative; background:var(--secondary); color:var(--primary); }
|
|
653
|
+
.is-selected::after,.btn-nav[aria-current]:not([aria-current="false"])::after,
|
|
654
|
+
.btn[aria-pressed="true"]:not(.btn-icon)::after,.segmented button.active::after,
|
|
655
|
+
.doc-nav a.active::after { content:""; position:absolute; inset-inline:15px; bottom:0; height:2px; border-radius:var(--radius-full); background:color-mix(in oklab, var(--primary) 75%, transparent); }
|
|
656
|
+
[data-theme="light"] .is-selected,[data-theme="light"] .btn-nav[aria-current]:not([aria-current="false"]),
|
|
657
|
+
[data-theme="light"] .btn[aria-pressed="true"],[data-theme="light"] .segmented button.active,
|
|
658
|
+
[data-theme="light"] .doc-nav a.active { --btn-fg:color-mix(in oklab, var(--primary) 45%, var(--foreground)); color:color-mix(in oklab, var(--primary) 45%, var(--foreground)); }
|
|
659
|
+
|
|
660
|
+
/* `line-height:1` não é enfeite: sem ele o .badge herdava a entrelinha do pai e a MESMA
|
|
661
|
+
classe media 26px dentro do .brand (lh 18px) e 22px dentro de um .btn-nav (lh 12px) — na
|
|
662
|
+
mesma barra (achado A2, 26/07/2026). Geometria de componente não se decide pelo contexto.
|
|
663
|
+
O .chip do catálogo já tinha aprendido isso; o .badge não. */
|
|
664
|
+
.badge { display:inline-flex; align-items:center; gap:6px; min-height:var(--space-6); padding:3px 9px; border:1px solid var(--border); border-radius:var(--radius-control); background:var(--secondary); color:var(--secondary-foreground); font-size:var(--text-xs); font-weight:var(--weight-medium); line-height:var(--leading-none); white-space:nowrap; }
|
|
665
|
+
/* O glifo do badge tem tamanho PRÓPRIO, senão o `.icon` padrão (20px) estoura os 24px e o
|
|
666
|
+
badge com ícone fica mais alto que o badge de texto na mesma fila. 16px + 3+3 de padding
|
|
667
|
+
+ 1+1 de borda = 24px exatos: com ícone ou sem, mede o mesmo. */
|
|
668
|
+
.badge .icon { width:var(--icon-sm); height:var(--icon-sm); }
|
|
669
|
+
.badge-primary { color:var(--primary-emphasis); border-color:var(--primary-outline); background:color-mix(in srgb,var(--primary) 10%,transparent); }
|
|
670
|
+
|
|
671
|
+
.badge-success { color:var(--success-400); background:var(--success-bg); border-color:color-mix(in srgb,var(--success-400) 35%,var(--border)); }
|
|
672
|
+
.badge-warning { color:var(--warning-400); background:var(--warning-bg); border-color:color-mix(in srgb,var(--warning-400) 35%,var(--border)); }
|
|
673
|
+
.badge-danger { color:var(--danger-400); background:var(--danger-bg); border-color:color-mix(in srgb,var(--danger-400) 35%,var(--border)); }
|
|
674
|
+
.badge-info,.badge-running { color:var(--info-400); background:var(--info-bg); border-color:color-mix(in srgb,var(--info-400) 35%,var(--border)); }
|
|
675
|
+
.status-dot { width:8px; height:8px; border-radius:50%; background:currentColor; box-shadow:0 0 0 3px color-mix(in srgb,currentColor 14%,transparent); }
|
|
676
|
+
/* Status: condição operacional (DIRECTION §3.6) — NÃO é o pill do Badge; é ponto + rótulo
|
|
677
|
+
solto na linha. A variante pinta o .status (o ponto herda por currentColor) e o rótulo
|
|
678
|
+
volta pra --foreground, senão a frase inteira fica colorida e ilegível no claro. Os
|
|
679
|
+
nomes operacionais e os semânticos apontam pro mesmo par de tokens de propósito. */
|
|
680
|
+
.status { display:inline-flex; align-items:center; gap:var(--space-2); color:var(--muted-foreground); font-size:var(--text-sm); }
|
|
681
|
+
.status-label { color:var(--foreground); }
|
|
682
|
+
.status-online,.status-success { color:var(--success-400); }
|
|
683
|
+
.status-away,.status-warning { color:var(--warning-400); }
|
|
684
|
+
.status-busy,.status-danger { color:var(--danger-400); }
|
|
685
|
+
.status-running,.status-info { color:var(--info-400); }
|
|
686
|
+
/* offline é o único que NÃO é "mais uma cor": --subtle-foreground e --muted-foreground
|
|
687
|
+
colapsam no MESMO valor no tema claro, então offline sairia idêntico ao neutral. Ponto
|
|
688
|
+
VAZADO resolve nos dois temas e ainda diz a coisa certa (ausência, não outro estado).
|
|
689
|
+
Escopado em .status-offline: o .status-dot dentro do Badge (Chat) segue preenchido. */
|
|
690
|
+
.status-offline { color:var(--subtle-foreground); }
|
|
691
|
+
.status-offline .status-dot { background:transparent; box-shadow:inset 0 0 0 2px currentColor,0 0 0 3px color-mix(in srgb,currentColor 14%,transparent); }
|
|
692
|
+
|
|
693
|
+
.card { min-width:0; padding:var(--card-pad); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); color:var(--card-foreground); box-shadow:none; }
|
|
694
|
+
.card-raised { box-shadow:none; } .card-inset { background:var(--secondary); }
|
|
695
|
+
.card-interactive { cursor:pointer; transition:transform var(--duration-fast),border-color var(--duration-fast),background var(--duration-fast); }
|
|
696
|
+
.card-interactive:hover { transform:translateY(-2px); border-color:var(--border-strong); background:var(--surface-2); }
|
|
697
|
+
.card-selected { border-color:var(--primary-outline); box-shadow:inset 0 0 0 1px var(--primary-outline); }
|
|
698
|
+
.card-danger { border-color:color-mix(in srgb,var(--danger-400) 50%,var(--border)); background:var(--danger-bg); }
|
|
699
|
+
.card-header { display:flex; align-items:flex-start; justify-content:space-between; gap:16px; margin-bottom:16px; }
|
|
700
|
+
.card-title { margin:0; font-size:var(--text-base); } .card-subtitle { margin:3px 0 0; color:var(--muted-foreground); font-size:var(--text-sm); }
|
|
701
|
+
|
|
702
|
+
.alert { display:grid; grid-template-columns:auto minmax(0,1fr) auto; align-items:start; gap:12px; padding:14px 16px; border:1px solid var(--border); border-radius:var(--radius-lg); background:var(--secondary); box-shadow:none; }
|
|
703
|
+
/* Banner: aviso de largura de página. Base ANTES das variantes — mesma
|
|
704
|
+
especificidade, então a última regra vence e a base apagaria as cores. */
|
|
705
|
+
.banner { display:grid; grid-template-columns:auto minmax(0,1fr) auto; align-items:center; gap:12px; padding:14px 18px; border:1px solid var(--border); border-radius:var(--radius-card); background:var(--secondary); }
|
|
706
|
+
.alert-info,.banner-info { border-color:color-mix(in srgb,var(--info-400) 38%,var(--border)); background:var(--info-bg); }
|
|
707
|
+
.alert-success,.banner-success { border-color:color-mix(in srgb,var(--success-400) 38%,var(--border)); background:var(--success-bg); }
|
|
708
|
+
.alert-warning,.banner-warning { border-color:color-mix(in srgb,var(--warning-400) 38%,var(--border)); background:var(--warning-bg); }
|
|
709
|
+
.alert-danger,.banner-danger { border-color:color-mix(in srgb,var(--danger-400) 38%,var(--border)); background:var(--danger-bg); }
|
|
710
|
+
.alert h4 { margin:0 0 2px; font-size:var(--text-sm); } .alert p { margin:0; color:var(--muted-foreground); font-size:var(--text-sm); }
|
|
711
|
+
.banner strong { font-size:var(--text-sm); } .banner p { margin:0; color:var(--muted-foreground); font-size:var(--text-sm); }
|
|
712
|
+
@media (max-width:640px) { .banner { grid-template-columns:auto minmax(0,1fr); } .banner>:last-child { grid-column:2; justify-self:start; } }
|
|
713
|
+
.progress { height:8px; overflow:hidden; border-radius:999px; background:var(--surface-3); }
|
|
714
|
+
.progress>span { display:block; height:100%; border-radius:inherit; background:var(--primary); }
|
|
715
|
+
/* DataState (M3): a região que troca de cara. Ela NÃO desenha nada próprio — só empilha o que
|
|
716
|
+
já existe (esqueleto, alerta, estado vazio, conteúdo) com respiro entre eles. Se ganhar borda
|
|
717
|
+
ou fundo, viram duas superfícies para a mesma coisa — o defeito que a `.table-region` cobrou. */
|
|
718
|
+
.data-state { display:grid; gap:var(--space-3); }
|
|
719
|
+
.skeleton { position:relative; overflow:hidden; border-radius:7px; background:var(--surface-3); }
|
|
720
|
+
.skeleton { animation:skeleton-pulse 1.35s ease-in-out infinite; } @keyframes skeleton-pulse { 50% { opacity:.55; } }
|
|
721
|
+
|
|
722
|
+
/* Mesma regra da .segmented: a cápsula carrega a altura da densidade, o filho estica. */
|
|
723
|
+
.tabs { display:inline-flex; gap:3px; padding:3px; min-height:var(--control-h-md); border:0; border-radius:var(--radius-control); background:var(--muted); }
|
|
724
|
+
.tab { position:relative; padding:0 14px; border:0; border-radius:var(--radius-control); background:transparent; color:var(--muted-foreground); cursor:pointer; }
|
|
725
|
+
.tab.active,.tab[data-active] { color:var(--foreground); background:var(--secondary); } .tab.active:after,.tab[data-active]:after { display:none; }
|
|
726
|
+
.breadcrumb { display:flex; align-items:center; flex-wrap:wrap; gap:7px; color:var(--muted-foreground); font-size:var(--text-sm); }
|
|
727
|
+
.breadcrumb a { color:inherit; text-decoration:none; } .breadcrumb a:hover { color:var(--foreground); }
|
|
728
|
+
.pagination { display:flex; gap:6px; align-items:center; }
|
|
729
|
+
/* `:not(.btn)` porque isto é o quadrado de NÚMERO de página. Sem o :not, o seletor de
|
|
730
|
+
elemento vencia o `.btn-sm` do Anterior/Próxima por especificidade (0,1,1 contra 0,1,0)
|
|
731
|
+
e forçava 34px neles — era a terceira altura de .btn-sm que a auditoria mediu (B3). */
|
|
732
|
+
.pagination button:not(.btn) { width:var(--control-h-md); height:var(--control-h-md); border:1px solid var(--border); border-radius:var(--radius-control); background:transparent; color:var(--muted-foreground); cursor:pointer; }
|
|
733
|
+
.pagination button.active { color:var(--primary-foreground); background:var(--primary); border-color:var(--primary); }
|
|
734
|
+
/* Stepper (Lote 2): o container NUNCA existiu no core — só no docs.css, e lá era
|
|
735
|
+
`repeat(4,1fr)`, com o número de etapas cravado. `grid-auto-flow:column` distribui N etapas
|
|
736
|
+
iguais sem saber quanto é N, e colunas iguais são o que faz a linha conectora (`.step:before`,
|
|
737
|
+
ancorada em -50%) cair no lugar certo. */
|
|
738
|
+
.stepper { display:grid; grid-auto-flow:column; grid-auto-columns:1fr; }
|
|
739
|
+
.step { position:relative; text-align:center; color:var(--subtle-foreground); }
|
|
740
|
+
/* O ponto também morava só no docs.css, como o container. Os estados dele (`.step.done`,
|
|
741
|
+
`.step.active`) estavam no core e miravam uma regra que não existia aqui — meia peça. */
|
|
742
|
+
.step-dot { position:relative; z-index:1; width:32px; height:32px; margin:0 auto var(--space-2); display:grid; place-items:center; border-radius:50%; border:1px solid var(--border-strong); background:var(--surface-1); }
|
|
743
|
+
/* Erro é o estado que faltava: uma etapa que reprovou na validação não tinha como se mostrar.
|
|
744
|
+
Cor semântica, não a primária — reprovar não é progredir. */
|
|
745
|
+
.step-error { color:var(--danger-400); } .step-error .step-dot { color:var(--danger-400); border-color:var(--danger-400); }
|
|
746
|
+
.step-optional { display:block; color:var(--muted-foreground); font-size:var(--text-xs); }
|
|
747
|
+
/* Etapa clicável (fluxo não-linear): o alvo é um botão de verdade, com o foco do sistema. */
|
|
748
|
+
.step-trigger { display:contents; border:0; padding:0; background:none; color:inherit; font:inherit; cursor:pointer; }
|
|
749
|
+
.step:before { content:""; position:absolute; top:15px; inset-inline-start:-50%; width:100%; height:2px; background:var(--border); } .step:first-child:before { display:none; }
|
|
750
|
+
.step.done,.step.active { color:var(--foreground); } .step.done:before,.step.active:before { background:var(--primary); } .step.done .step-dot { color:var(--primary-foreground); background:var(--primary); border-color:var(--primary); } .step.active .step-dot { border-color:var(--primary); box-shadow:0 0 0 4px color-mix(in srgb,var(--primary) 14%,transparent); }
|
|
751
|
+
|
|
752
|
+
/* TABELA DE DADOS — e só ela. Estas cinco regras eram de ELEMENTO (`table`, `th,td`, `th`,
|
|
753
|
+
`tr:last-child td`, `tbody tr:hover`) e valiam para toda <table> do documento, inclusive a de
|
|
754
|
+
um consumidor. Nenhum gate as via: os checks 15 e 18 comparam CLASSE, e seletor de elemento
|
|
755
|
+
não tem nenhuma. O Lote 4 pagou a conta — a grade do calendário nasceu com `min-width:720px`
|
|
756
|
+
e o cabeçalho de dias herdou a faixa cinza, a caixa alta e o espaçamento de letra de um
|
|
757
|
+
cabeçalho de tabela de dados. Medido no navegador em 01 e 02/08/2026.
|
|
758
|
+
Escopar é seguro e foi medido antes: `Table` embrulha em `.table-region` e emite `.table` na
|
|
759
|
+
tabela; `DataGrid` embrulha em `.table-wrap`; e as 3 tabelas da página legada estão todas
|
|
760
|
+
dentro de `.table-wrap`. Nenhuma <table> do repositório fica descoberta — o gate de pixel é
|
|
761
|
+
quem prova, e ele tem de acusar ZERO mudança nas superfícies de tabela. */
|
|
762
|
+
/* `.table-region` entrou nesta regra em 13/08/2026, e a linha acima ("o gate tem de acusar ZERO
|
|
763
|
+
mudança nas superfícies de tabela") vale para o ESCOPO daquele lote, não para sempre: aqui a
|
|
764
|
+
mudança de superfície é o pedido. O `Table` embrulhava em `.table-region`, que tinha só
|
|
765
|
+
`overflow` e `--radius-lg` — sem borda e sem fundo. Resultado na tela: a tabela aparecia solta
|
|
766
|
+
na página enquanto o `DataGrid`, do lado, tinha a caixa flutuante da marca. Duas peles para a
|
|
767
|
+
mesma coisa, e a do componente mais simples era a errada.
|
|
768
|
+
Somar o seletor em vez de copiar os valores: copiar deixaria duas listas para manter em sincronia,
|
|
769
|
+
que é como as duas peles divergiram. O que continua só do `.table-region` é o foco — ele é
|
|
770
|
+
`tabIndex=0` (região rolável precisa ser alcançável pelo teclado) e o `.table-wrap` não é. */
|
|
771
|
+
.table-wrap,.table-region { overflow:auto; border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); }
|
|
772
|
+
.table,.table-wrap table { width:100%; border-collapse:collapse; min-width:720px; }
|
|
773
|
+
.table th,.table td,.table-wrap th,.table-wrap td { height:var(--row-h); padding:0 14px; text-align:start; border-bottom:1px solid var(--border); }
|
|
774
|
+
.table th,.table-wrap th { color:var(--subtle-foreground); background:var(--surface-2); font-size:var(--text-xs); letter-spacing:var(--tracking-wider); text-transform:uppercase; }
|
|
775
|
+
.table tr:last-child td,.table-wrap tr:last-child td { border-bottom:0; }
|
|
776
|
+
.table tbody tr:hover,.table-wrap tbody tr:hover { background:var(--surface-2); }
|
|
777
|
+
/* Avatar (Lote 2): `overflow:hidden` e o `object-fit` da imagem são a correção do defeito que
|
|
778
|
+
a medição achou — foto que não é quadrada vazava inteira da caixa redonda, porque
|
|
779
|
+
`border-radius` não recorta filho sozinho. Foto de perfil raramente vem quadrada, então isto
|
|
780
|
+
quebrava no primeiro uso real. */
|
|
781
|
+
/* B5 do PLANO-1.0: os 36px viraram --control-h-md, que É 2.25rem = os mesmos 36px em
|
|
782
|
+
`comfortable`. Nada muda de aparência aqui; o que muda é que agora a DENSIDADE alcança o
|
|
783
|
+
avatar, e a escala é a mesma dos controles — avatar e botão na mesma linha ficam da mesma
|
|
784
|
+
altura por construção, em vez de por coincidência. */
|
|
785
|
+
.avatar { width:var(--control-h-md); height:var(--control-h-md); display:grid; place-items:center; overflow:hidden; border-radius:50%; background:var(--surface-3); color:var(--foreground); border:1px solid var(--border-strong); font-weight:var(--weight-bold); }
|
|
786
|
+
.avatar-sm { width:var(--control-h-sm); height:var(--control-h-sm); font-size:var(--text-xs); }
|
|
787
|
+
.avatar-lg { width:var(--control-h-lg); height:var(--control-h-lg); }
|
|
788
|
+
.avatar img { width:100%; height:100%; object-fit:cover; }
|
|
789
|
+
/* O container do grupo NUNCA teve regra: a sobreposição abaixo existia e os avatares empilhavam
|
|
790
|
+
na vertical porque o pai saía `display:block`. Mesma falha do `.stepper` e do `.command`. */
|
|
791
|
+
.avatar-group { display:inline-flex; align-items:center; }
|
|
792
|
+
.avatar-group .avatar { margin-inline-start:-9px; border:2px solid var(--surface-1); } .avatar-group .avatar:first-child { margin-inline-start:0; }
|
|
793
|
+
/* O "+N" é um avatar como os outros — mesma caixa, mesma borda —, só que menor por dentro e sem
|
|
794
|
+
peso de nome próprio: ele conta, não identifica. */
|
|
795
|
+
.avatar-count { background:var(--secondary); color:var(--muted-foreground); font-size:var(--text-xs); font-weight:var(--weight-medium); }
|
|
796
|
+
.kpi { display:flex; flex-direction:column; gap:5px; }
|
|
797
|
+
/* DataList: chave/valor em duas colunas. O termo é secundário — mesmo idioma do cabeçalho de
|
|
798
|
+
tabela. Sem a regra (achado A13) o <dl> saía cru: dt e dd empilhados, com o recuo de 40px
|
|
799
|
+
que o navegador dá ao <dd>. */
|
|
800
|
+
/* A coluna do TERMO era `max-content`, que não encolhe nunca: um `dt` comprido empurrava a
|
|
801
|
+
PÁGINA para fora em telas estreitas — medido em 16/08/2026 a 320px, quando a página de hooks
|
|
802
|
+
estreou termos de frase inteira e a varredura acusou +179px de rolagem lateral. `auto` sizes
|
|
803
|
+
igual quando há espaço (por isso nenhuma baseline mudou) e cai para min-content quando não há,
|
|
804
|
+
deixando o termo quebrar em vez de arrastar o documento. O defeito era do COMPONENTE, não da
|
|
805
|
+
página nova: o `DataList` é publicado, e quem escrevesse um termo longo levava o mesmo.
|
|
806
|
+
`auto` foi TENTADO primeiro e não resolveu — medido, não suposto: a trilha `auto` tem
|
|
807
|
+
max-content como máximo e não encolhe abaixo dele quando o contêiner aperta, e a sobra caiu de
|
|
808
|
+
179px para 90px em vez de zerar. `minmax(0,max-content)` é o que encolhe: com espaço mede
|
|
809
|
+
igual ao que media antes (nenhuma baseline mudou), sem espaço o termo quebra. */
|
|
810
|
+
.data-list { display:grid; grid-template-columns:minmax(0,max-content) minmax(0,1fr); gap:var(--space-2) var(--space-6); margin:0; }
|
|
811
|
+
.data-list dt { min-width:0; color:var(--muted-foreground); }
|
|
812
|
+
.data-list dd { min-width:0; margin:0; }
|
|
813
|
+
/* E no ESTREITO ele empilha — a outra metade da correção. Medido a 320px com termos de frase
|
|
814
|
+
inteira: duas colunas não cabem, o termo resolvia em 164px, a calha comia o resto e a coluna do
|
|
815
|
+
valor ficava com `0px`, jogando o texto para fora da PÁGINA. Mesmo remédio que `.message` e
|
|
816
|
+
`.log-line` já usam aqui. A regra mora DEPOIS da base de propósito: escrita antes, ela não
|
|
817
|
+
valia nada — mídia não soma especificidade, então a base vencia por vir por último. Foi
|
|
818
|
+
exatamente o que aconteceu na primeira tentativa, e é a armadilha que o comentário do
|
|
819
|
+
`.banner` lá em cima já registrava. */
|
|
820
|
+
@media (max-width:640px) { .data-list { grid-template-columns:minmax(0,1fr); } }
|
|
821
|
+
/* Timeline: o trilho existia e o PONTO não — `.timeline-dot` media 0×0 (achado A13), então a
|
|
822
|
+
linha do tempo saía com a régua e sem as marcas, e o <ol> ainda mostrava a numeração do
|
|
823
|
+
navegador. Agora os dois derivam do MESMO token: o trilho fica a meio diâmetro do ponto, e
|
|
824
|
+
alinham por construção em vez de por número copiado. Saem junto os 24px de recuo e os 7px
|
|
825
|
+
do trilho — dois px crus a menos na catraca do check 12. */
|
|
826
|
+
.timeline { position:relative; display:flex; flex-direction:column; gap:var(--space-5); margin:0; padding:0; list-style:none; }
|
|
827
|
+
.timeline:before { content:""; position:absolute; inset-inline-start:calc(var(--space-3) / 2); inset-block:var(--space-2); width:1px; background:var(--border); }
|
|
828
|
+
.timeline > li { display:flex; align-items:flex-start; gap:var(--space-3); }
|
|
829
|
+
/* A coluna de conteúdo é uma PILHA, e não por estética: sem isso o item empilhava quando
|
|
830
|
+
tinha descrição (o <p> é bloco) e colava título e horário na mesma linha quando não tinha —
|
|
831
|
+
"Shipped14:20". Geometria de componente não depende do conteúdo (achados A2/A3). */
|
|
832
|
+
.timeline > li > div { display:flex; flex-direction:column; gap:var(--space-05); min-width:0; }
|
|
833
|
+
.timeline > li > div > p { margin:0; }
|
|
834
|
+
.timeline-dot { flex:none; width:var(--space-3); height:var(--space-3); border-radius:var(--radius-full); margin-block-start:var(--space-1); background:var(--primary); box-shadow:0 0 0 var(--space-05) var(--surface-1); }
|
|
835
|
+
/* Accordion: anatomia medida no Carbon em 30/07/2026 (REFERENCES.md) — cabeçalho na altura de
|
|
836
|
+
controle, divisória de 1px por item, corpo com respiro pequeno em cima e grande embaixo.
|
|
837
|
+
O marcador é o NATIVO do <summary>: gira sozinho e custa zero código, e é por isso que o
|
|
838
|
+
summary continua `display:list-item` — pôr flex nele apagaria o marcador. */
|
|
839
|
+
.accordion { display:flex; flex-direction:column; border-block:1px solid var(--border); }
|
|
840
|
+
.accordion > details + details { border-top:1px solid var(--border); }
|
|
841
|
+
.accordion > details > summary { min-height:var(--control-h-md); padding-block:var(--space-2); padding-inline:var(--space-5) var(--space-2); color:var(--foreground); font-weight:var(--weight-medium); line-height:var(--leading-normal); cursor:pointer; }
|
|
842
|
+
.accordion > details > summary:hover { background:var(--surface-hover); }
|
|
843
|
+
.accordion > details > summary::marker { color:var(--muted-foreground); }
|
|
844
|
+
/* Recuo INLINE, não `padding-left`: o marcador do <summary> troca de lado em RTL e o corpo
|
|
845
|
+
tem de acompanhar. Foi o gate de RTL que cobrou — ele mede o eixo inline do core. */
|
|
846
|
+
.accordion-content { padding-block:0 var(--space-6); padding-inline:var(--space-5) var(--space-2); color:var(--muted-foreground); }
|
|
847
|
+
/* Mockup do kit de origem (apps/docs) — não é o Accordion do sistema, que é <details> nativo. */
|
|
848
|
+
|
|
849
|
+
/* QRCode: superfície flutuante Aurea, mas o miolo é de alto contraste FIXO — um QR
|
|
850
|
+
não segue o tema (dark inverteria e nem todo leitor decodifica invertido). Override
|
|
851
|
+
consciente por --qr-module/--qr-quiet. Módulos suaves (rx no SVG) sem perder escaneabilidade. */
|
|
852
|
+
/* B6 do PLANO-1.0: o tamanho saiu dos atributos width/height do SVG e virou --qr-size, no
|
|
853
|
+
mesmo idioma dos dois botões de ajuste que este componente já tinha. `md` são os 10rem =
|
|
854
|
+
160px de antes (com box-sizing:border-box o quiet zone continua por dentro da medida).
|
|
855
|
+
Três degraus e não um número livre: o número livre era o que obrigava pixel cru no
|
|
856
|
+
consumidor. Quem precisar de um QR de cartaz sobrescreve --qr-size, que é o mesmo caminho
|
|
857
|
+
já documentado para trocar a cor dos módulos. */
|
|
858
|
+
.qrcode { --qr-module:#0b0b0c; --qr-quiet:#fff; --qr-size:10rem; box-sizing:border-box; width:var(--qr-size); height:var(--qr-size); padding:var(--space-3); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--qr-quiet); }
|
|
859
|
+
.qrcode-sm { --qr-size:7.5rem; }
|
|
860
|
+
.qrcode-lg { --qr-size:15rem; }
|
|
861
|
+
.qrcode .qr-mod { fill:var(--qr-module); }
|
|
862
|
+
.qrcode .qr-eye-gap { fill:var(--qr-quiet); }
|
|
863
|
+
|
|
864
|
+
/* `overflow:auto` faz do <pre> uma REGIÃO ROLÁVEL, e região rolável sem nada focável dentro
|
|
865
|
+
é inalcançável por teclado (axe scrollable-region-focusable). Quem escreve esta marcação à
|
|
866
|
+
mão precisa de `tabindex="0"` no <pre> — o componente React já o emite. */
|
|
867
|
+
.code-block { overflow:auto; padding:16px; border:1px solid var(--border); border-radius:var(--radius-lg); background:var(--surface-inset); color:var(--muted-foreground); font:12px/1.7 var(--font-code); }
|
|
868
|
+
/* Bloco de código COM copiar: a moldura não rola, o <pre> rola por dentro e o gatilho fica
|
|
869
|
+
parado no canto. O comportamento é do core (aurea.js, [data-aurea-copy]); aqui só a pele.
|
|
870
|
+
O check em amarelo é confirmação instantânea — dura 1,5s e volta ao ícone de copiar. */
|
|
871
|
+
/* checkbox com rótulo fora da tela: sem o texto, o alvo é só a marca — nada de gap sobrando. */
|
|
872
|
+
.checkbox-bare { gap:0; }
|
|
873
|
+
.code-block-wrap { position:relative; display:flex; min-width:0; }
|
|
874
|
+
.code-block-wrap > .code-block { flex:1; min-width:0; margin:0; }
|
|
875
|
+
.copy-code { position:absolute; top:var(--space-3); inset-inline-end:var(--space-3); z-index:1; }
|
|
876
|
+
.copy-code .c-done { display:none; }
|
|
877
|
+
.copy-code.is-done .c-copy { display:none; } .copy-code.is-done .c-done { display:block; color:var(--primary); }
|
|
878
|
+
/* "On this page": índice da própria página, fixo na lateral. Navegação, não decoração —
|
|
879
|
+
por isso é <nav> com rótulo, e o item atual se marca com aria-current. */
|
|
880
|
+
.toc { position:sticky; top:var(--space-4); align-self:start; display:grid; gap:var(--space-1); max-height:calc(100vh - var(--space-8)); overflow:auto; scrollbar-width:none; padding:var(--space-2) 0; }
|
|
881
|
+
.toc::-webkit-scrollbar { width:0; }
|
|
882
|
+
.toc-label { margin:0 0 var(--space-1); padding-inline:var(--space-3); color:var(--subtle-foreground); font-size:11px; letter-spacing:var(--tracking-widest); text-transform:uppercase; }
|
|
883
|
+
.toc a { padding:var(--space-1) var(--space-3); border-inline-start:2px solid var(--border); color:var(--muted-foreground); font-size:var(--text-sm); text-decoration:none; }
|
|
884
|
+
.toc a:hover { color:var(--foreground); }
|
|
885
|
+
.toc a[aria-current] { border-inline-start-color:var(--primary); color:var(--foreground); }
|
|
886
|
+
.toc a.toc-sub { padding-inline-start:var(--space-6); }
|
|
887
|
+
/* `--log-h` é a QUINTA válvula de altura do core, no idioma de `--chart-h` (I4), `--qr-size` (B6),
|
|
888
|
+
`--datagrid-max-h` (F6) e `--media-h` (I7). Default 240px — o de antes —, então nada muda para
|
|
889
|
+
quem não passa nada. A causa é medida em 11/08/2026: a altura era FIXA, e por isso três prévias
|
|
890
|
+
do catálogo gastavam 240px para mostrar três linhas de log e rolavam dentro da caixa de
|
|
891
|
+
demonstração, contra a ADR-0002. Altura é decisão da página, e não vira prop (check 23). */
|
|
892
|
+
.log-stream { height:var(--log-h,240px); overflow:auto; padding:14px; border:1px solid var(--border); border-radius:var(--radius-md); background:var(--surface-inset); font:12px/1.65 var(--font-code); }
|
|
893
|
+
.log-line { display:grid; grid-template-columns:86px 72px minmax(0,1fr); gap:12px; padding:3px 0; } .log-time { color:var(--subtle-foreground); } .log-level { color:var(--primary); } .log-level.warn { color:var(--warning-400); } .log-level.error { color:var(--danger-400); }
|
|
894
|
+
/* O nível pintado a partir da classe que o pacote React emite no CONTAINER (`log-error`).
|
|
895
|
+
As duas formas convivem de propósito: `.log-level.warn` serve a apps/docs/index.html,
|
|
896
|
+
escrito à mão, e sai junto com ele na Parte D. Medido no item E13: sem estas três, a
|
|
897
|
+
prop `level` do LogStream não pintava nada — pele que existe e não faz nada. */
|
|
898
|
+
.log-info .log-level { color:var(--info-400); }
|
|
899
|
+
.log-warn .log-level { color:var(--warning-400); }
|
|
900
|
+
.log-error .log-level { color:var(--danger-400); }
|
|
901
|
+
|
|
902
|
+
/* ========================================================================== */
|
|
903
|
+
/* 05. GRÁFICOS E VISUALIZAÇÃO */
|
|
904
|
+
/* ========================================================================== */
|
|
905
|
+
/* I4 do PLANO-1.0: a altura vira válvula de escape, no MESMO idioma do `--qr-size` e do
|
|
906
|
+
`--datagrid-max-h` — quem sabe quanta tela tem é quem hospeda, e altura não vira prop
|
|
907
|
+
numérica (check 23). O default é os mesmos 220px de antes, então nada muda para quem já
|
|
908
|
+
usa: medido, zero pixel nas capturas. O que ele destrava é a composição — o `I4
|
|
909
|
+
AnalyticsWorkbench` põe gráfico E tabela na mesma caixa de altura fixa (ADR-0002), e com
|
|
910
|
+
220 fixos as duas peças sozinhas já passavam do vão do painel em 95px. O fallback é
|
|
911
|
+
deliberado e é o que o check 29 exige de quem não declara o token. */
|
|
912
|
+
.chart { width:100%; height:var(--chart-h,220px); } .chart-bar.alt { fill:var(--chart-1); } .health-cell.warn { background:var(--warning-500); } .health-cell.bad { background:var(--danger-500); } .health-cell.off { background:var(--surface-3); }
|
|
913
|
+
/* Chart (Lote 3) — a pele do desenho que o Recharts emite. Os seletores são de ELEMENTO, nunca
|
|
914
|
+
`.recharts-*`: nome de classe de terceiro dentro do core reprovaria o check 15 (o core só
|
|
915
|
+
declara classe que a Aurea produz), e é a mesma razão pela qual a pele do CodeEditor vem pelo
|
|
916
|
+
EditorView.theme do CodeMirror e não daqui. O motor põe stroke/fill como ATRIBUTO de
|
|
917
|
+
apresentação (#ccc nas linhas de grade, #666 nos rótulos), e CSS vence atributo — medido em
|
|
918
|
+
01/08/2026: 20 <line> e 9 <text> num gráfico de linha com grade e dois eixos. */
|
|
919
|
+
.chart svg line { stroke:var(--border); } .chart svg text { fill:var(--muted-foreground); font-size:var(--text-xs); }
|
|
920
|
+
.chart-tooltip { display:grid; gap:var(--space-1); pointer-events:none; } .chart-tooltip strong { color:var(--foreground); font-weight:var(--weight-medium); }
|
|
921
|
+
.chart-tooltip b { margin-inline-start:auto; color:var(--foreground); font-variant-numeric:tabular-nums; }
|
|
922
|
+
.chart-legend { display:flex; flex-wrap:wrap; justify-content:center; gap:var(--space-1) var(--space-4); margin:0; padding:0; list-style:none; }
|
|
923
|
+
.chart-key { display:flex; align-items:center; gap:var(--space-2); color:var(--muted-foreground); font-size:var(--text-xs); } .chart-key i { flex:none; width:9px; height:9px; border-radius:var(--radius-sm); }
|
|
924
|
+
/* O cursor precisa de DOIS pontos de especificidade porque `.chart svg line` acima já tem dois
|
|
925
|
+
elementos: `.chart .chart-cursor` (0,2,0) vence `.chart svg line` (0,1,2). Em gráfico de linha
|
|
926
|
+
o cursor é <line> e em barra é <rect>, então a regra dá stroke E fill — cada um usa o seu. */
|
|
927
|
+
.chart .chart-cursor { stroke:var(--border-strong); fill:var(--secondary); }
|
|
928
|
+
/* Calendar (Lote 4) — a pele da grade que o react-day-picker emite. Mesma regra do Chart e pela
|
|
929
|
+
mesma razão: nada de `.rdp-*` aqui (o check 15 reprova nome de classe que a Aurea não produz).
|
|
930
|
+
Três nomes vêm renomeados pela API `classNames` do motor; o resto é ELEMENTO e `data-*`, e
|
|
931
|
+
atributo não é classe. Estado medido em 01/08/2026: data-selected, data-today, data-outside,
|
|
932
|
+
data-disabled e data-hidden — este último é obrigatório, senão o dia escondido das pontas
|
|
933
|
+
APARECE (o motor conta com o CSS dele para escondê-lo, e nós não importamos o CSS dele). */
|
|
934
|
+
.calendar { display:inline-block; padding:var(--space-3); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--surface-1); }
|
|
935
|
+
.calendar-months { position:relative; }
|
|
936
|
+
.calendar nav { position:absolute; inset-block-start:0; inset-inline:0; display:flex; justify-content:space-between; }
|
|
937
|
+
.calendar nav button { display:inline-flex; align-items:center; justify-content:center; width:var(--control-h-sm); height:var(--control-h-sm); padding:0; border:0; border-radius:var(--radius-control); background:transparent; color:var(--muted-foreground); cursor:pointer; }
|
|
938
|
+
.calendar nav button:hover:not(:disabled):not([aria-disabled="true"]) { background:var(--secondary); color:var(--foreground); }
|
|
939
|
+
.calendar nav button:disabled { opacity:.4; cursor:not-allowed; }
|
|
940
|
+
.calendar nav svg { width:var(--icon-sm); height:var(--icon-sm); fill:currentColor; }
|
|
941
|
+
.calendar-caption { display:flex; align-items:center; justify-content:center; height:var(--control-h-sm); color:var(--foreground); font-size:var(--text-sm); font-weight:var(--weight-medium); }
|
|
942
|
+
/* Estas três já foram um DESFAZIMENTO: `width:auto`, `min-width:0`, `height:auto` e
|
|
943
|
+
`border-bottom:0` existiam só para anular a regra de elemento da seção de dados. A regra foi
|
|
944
|
+
escopada em 02/08/2026 e o antídoto saiu junto — corrigir onde nasce, não onde dói.
|
|
945
|
+
O `padding:0` FICA, e não é antídoto: é o 1px que o NAVEGADOR dá a `<td>`/`<th>`. Tirá-lo
|
|
946
|
+
junto com o resto engordou a célula para 38px e a grade para 266px — medido, e voltado. */
|
|
947
|
+
.calendar table { border-collapse:collapse; margin-block-start:var(--space-2); }
|
|
948
|
+
.calendar th { padding:0 0 var(--space-1); text-align:center; color:var(--muted-foreground); font-size:var(--text-xs); font-weight:var(--weight-regular); }
|
|
949
|
+
.calendar td { padding:0; text-align:center; }
|
|
950
|
+
.calendar td button { display:flex; align-items:center; justify-content:center; width:var(--control-h-md); height:var(--control-h-md); border:0; border-radius:var(--radius-control); background:transparent; color:var(--foreground); font-size:var(--text-sm); font-variant-numeric:tabular-nums; cursor:pointer; }
|
|
951
|
+
.calendar td button:hover:not(:disabled):not([aria-disabled="true"]) { background:var(--secondary); }
|
|
952
|
+
.calendar td[data-today] button { font-weight:var(--weight-medium); box-shadow:inset 0 0 0 1px var(--border-strong); }
|
|
953
|
+
.calendar td[data-selected] button { background:var(--primary); color:var(--primary-foreground); font-weight:var(--weight-medium); box-shadow:none; }
|
|
954
|
+
.calendar td[data-outside] button { color:var(--subtle-foreground); }
|
|
955
|
+
.calendar td button:disabled { opacity:.35; cursor:not-allowed; }
|
|
956
|
+
.calendar td[data-hidden] { visibility:hidden; }
|
|
957
|
+
.message { display:grid; grid-template-columns:auto minmax(0,1fr); gap:12px; } .message-bubble { padding:12px 14px; border-radius:6px var(--radius-lg) var(--radius-lg) var(--radius-lg); background:var(--secondary); } .message-bubble p { margin:0; }
|
|
958
|
+
/* Chat React (Fase 5.4): estrutura fixa em classe, não inline (auditoria 18/07, M14). */
|
|
959
|
+
.message-status { display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-3); margin-block-start:var(--space-2); }
|
|
960
|
+
.message-composer { display:flex; align-items:center; gap:var(--space-3); flex-wrap:nowrap; } .message-composer .input-wrap { flex:1; min-width:0; }
|
|
961
|
+
|
|
962
|
+
/* ========================================================================== */
|
|
963
|
+
/* 07. MÍDIA */
|
|
964
|
+
/* ========================================================================== */
|
|
965
|
+
/* `--media-h` e `--media-ar` são VÁLVULA DE ESCAPE, autorizada pelo Victor em 11/08/2026 no item
|
|
966
|
+
I7 do PLANO-1.0, e no idioma exato das três que já existem: `--chart-h` (I4), `--qr-size` (B6) e
|
|
967
|
+
`--datagrid-max-h` (F6). O default é o de antes — 360px e 16/9 —, então nada muda para quem não
|
|
968
|
+
passa nada. A causa é medida: numa caixa de demonstração de 826px de largura o `aspect-ratio`
|
|
969
|
+
produz 464px de altura, contra um vão útil de 354; o player não cabe numa composição, e o
|
|
970
|
+
`MediaPlayer` não repassa `style` para esta caixa (as props sobrando vão para o `<video>`, de
|
|
971
|
+
propósito). Quem sabe quanta altura tem é a página, e altura não vira prop (check 23).
|
|
972
|
+
⚠ `--media-ar:auto` SÓ é seguro junto com `--media-h`. A razão do `aspect-ratio` aqui não é
|
|
973
|
+
estética: é CLS. O exemplo de playlist do `media-chrome` declara o mesmo com o motivo escrito —
|
|
974
|
+
sem proporção fixa, um player com `preload=none` mede zero até a mídia chegar e a página SALTA.
|
|
975
|
+
Tirar a proporção sem fixar a altura devolve o salto. */
|
|
976
|
+
.media-player { position:relative; isolation:isolate; overflow:hidden; min-height:var(--media-h,360px); aspect-ratio:var(--media-ar,16/9); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--media-canvas); color:var(--media-foreground); }
|
|
977
|
+
.media-viewport { position:absolute; inset:0; display:grid; place-items:center; background:var(--media-canvas); }
|
|
978
|
+
.media-fill { width:100%; height:100%; object-fit:contain; } /* vídeo React preenche o viewport (auditoria 18/07, M14) */
|
|
979
|
+
.media-placeholder { display:grid; place-items:center; gap:10px; color:var(--media-muted); text-align:center; }
|
|
980
|
+
.media-placeholder .icon { width:48px; height:48px; color:var(--media-foreground); }
|
|
981
|
+
.media-placeholder strong { color:var(--media-foreground); }
|
|
982
|
+
.media-overlay-title { position:absolute; top:16px; inset-inline:16px; z-index:2; display:flex; align-items:flex-start; justify-content:space-between; gap:16px; color:var(--media-foreground); }
|
|
983
|
+
.media-overlay-title>div>span { display:block; color:var(--media-muted); font-size:var(--text-xs); }
|
|
984
|
+
.media-player .badge { border-color:var(--media-track); background:var(--media-track); color:var(--media-foreground); }
|
|
985
|
+
.media-controls { position:absolute; inset:auto 0 0; z-index:3; display:grid; gap:8px; padding:12px; background:var(--media-scrim); color:var(--media-foreground); }
|
|
986
|
+
.media-seek { --media-played:34%; position:relative; height:20px; display:flex; align-items:center; }
|
|
987
|
+
.media-seek-track { position:absolute; inset-inline:0; height:4px; overflow:hidden; border-radius:var(--radius-full); background:var(--media-track); pointer-events:none; }
|
|
988
|
+
.media-seek-buffered,.media-seek-played { position:absolute; inset-block:0; inset-inline:0 auto; border-radius:inherit; }
|
|
989
|
+
.media-seek-buffered { width:62%; background:var(--media-buffered); }
|
|
990
|
+
.media-seek-played { width:var(--media-played); background:var(--primary); }
|
|
991
|
+
.media-seek input { position:relative; z-index:1; width:100%; height:20px; margin:0; appearance:none; background:transparent; cursor:pointer; }
|
|
992
|
+
.media-seek input::-webkit-slider-runnable-track { height:4px; background:transparent; }
|
|
993
|
+
.media-seek input::-webkit-slider-thumb { width:14px; height:14px; margin-top:-5px; appearance:none; border:2px solid var(--media-foreground); border-radius:50%; background:var(--primary); }
|
|
994
|
+
.media-seek input::-moz-range-track { height:4px; background:transparent; }
|
|
995
|
+
.media-seek input::-moz-range-thumb { width:12px; height:12px; border:2px solid var(--media-foreground); border-radius:50%; background:var(--primary); }
|
|
996
|
+
.media-seek input:focus-visible { outline:2px solid var(--primary); outline-offset:3px; box-shadow:none; }
|
|
997
|
+
.media-control-row,.media-control-group { display:flex; align-items:center; gap:4px; }
|
|
998
|
+
.media-control-row { min-width:0; justify-content:space-between; }
|
|
999
|
+
.media-control { min-width:36px; height:36px; display:inline-grid; place-items:center; padding:0 8px; border:1px solid transparent; border-radius:var(--radius-md); background:transparent; color:var(--media-foreground); cursor:pointer; }
|
|
1000
|
+
.media-control:hover,.media-control.active { background:var(--media-track); color:var(--primary); }
|
|
1001
|
+
.media-time { padding:0 7px; color:var(--media-muted); font:var(--text-xs) var(--font-code); white-space:nowrap; }
|
|
1002
|
+
.media-volume { width:82px; accent-color:var(--primary); }
|
|
1003
|
+
|
|
1004
|
+
/* IMAGEM (PLANO-1.0, item L4). A caixa é reservada ANTES do byte chegar — é a mesma razão que o
|
|
1005
|
+
comentário do `--media-ar` acima registra: sem proporção, a imagem mede zero até carregar e a
|
|
1006
|
+
página salta quando ela chega (CLS). O fundo é a superfície do esqueleto, e o bitmap a cobre ao
|
|
1007
|
+
pintar — marcador de carregamento sem uma linha de JavaScript.
|
|
1008
|
+
|
|
1009
|
+
⚠ NÃO declare `aspect-ratio` aqui, e isto foi MEDIDO em 15/08/2026, não deduzido. A primeira
|
|
1010
|
+
versão desta regra tinha `aspect-ratio:var(--image-ratio,auto)`, e o fallback `auto` PASSA POR
|
|
1011
|
+
CIMA do `aspect-ratio: auto <width> / <height>` que o navegador deriva dos atributos do
|
|
1012
|
+
elemento. Resultado medido numa caixa de 400px: com `width=300 height=200` e sem a prop `ratio`,
|
|
1013
|
+
a imagem saía **400×0** — ou seja, a regra escrita para impedir o salto de layout produzia
|
|
1014
|
+
exatamente o salto. Sem a declaração, o mesmo caso reserva 400×267. Quem tem proporção declarada
|
|
1015
|
+
recebe `aspect-ratio` inline, do componente; quem não tem fica com o comportamento do navegador,
|
|
1016
|
+
que já é o certo. */
|
|
1017
|
+
.image { display:block; width:100%; height:auto; object-fit:cover; border-radius:var(--radius-lg); background:var(--surface-3); }
|
|
1018
|
+
.image-contain { object-fit:contain; background:transparent; }
|
|
1019
|
+
.image-broken { display:grid; place-items:center; color:var(--muted-foreground); }
|
|
1020
|
+
|
|
1021
|
+
/* GALERIA (PLANO-1.0, item L2). A grade se adapta sozinha — `auto-fill` com um mínimo, e não um
|
|
1022
|
+
número de colunas —, porque quem sabe quanta largura existe é o contêiner, não o componente.
|
|
1023
|
+
`--gallery-min` é a válvula, no idioma do `--carousel-slide` e do `--qr-size`.
|
|
1024
|
+
O SELECIONADO NÃO INVENTA LINGUAGEM: o ladrilho recebe `.is-selected`, a mesma classe da aba
|
|
1025
|
+
ativa, do item de lateral e do botão alternado — cápsula elevada, rótulo na cor da marca e o
|
|
1026
|
+
fio amarelo embaixo. É a regra "uma linguagem só" deste arquivo, e por isso aqui não há uma
|
|
1027
|
+
segunda maneira de dizer "este está escolhido". O recuo existe para a cápsula aparecer: com
|
|
1028
|
+
`padding:0` o fundo do selecionado fica exatamente sob a foto e não se vê.
|
|
1029
|
+
Foco também não tem regra própria: a global do topo deste arquivo já desenha o anel, e ele é
|
|
1030
|
+
de cor DIFERENTE da seleção — senão focar e escolher viram o mesmo sinal. */
|
|
1031
|
+
.gallery { display:grid; grid-template-columns:repeat(auto-fill,minmax(var(--gallery-min,8rem),1fr)); gap:var(--space-3); margin:0; padding:0; list-style:none; }
|
|
1032
|
+
.gallery-item { min-width:0; }
|
|
1033
|
+
.gallery-tile { display:grid; gap:var(--space-1); width:100%; padding:var(--space-1); border:0; border-radius:var(--radius-lg); font:inherit; text-align:start; cursor:pointer; }
|
|
1034
|
+
/* `:not(.is-selected)` e não uma regra de selecionado própria, e a diferença foi MEDIDA em
|
|
1035
|
+
15/08/2026: `.gallery-tile` e `.is-selected` têm a MESMA especificidade, e a do ladrilho vem
|
|
1036
|
+
depois no arquivo — então `background:transparent` matava a cápsula da linguagem da casa e o
|
|
1037
|
+
selecionado saía só com o fio amarelo. Reescrever a cápsula aqui seria a segunda cópia da
|
|
1038
|
+
linguagem "uma linguagem só" existe para impedir; tirar o fundo só de quem NÃO está escolhido
|
|
1039
|
+
deixa a regra de lá governar sem competição. O fundo de botão do navegador precisa morrer de
|
|
1040
|
+
qualquer forma — ele é `buttonface`, não transparente. */
|
|
1041
|
+
.gallery-tile:not(.is-selected) { background:transparent; color:var(--muted-foreground); }
|
|
1042
|
+
.gallery-caption { font-size:var(--text-sm); }
|
|
1043
|
+
|
|
1044
|
+
/* PROSA (PLANO-1.0, item L5). É a PELE do texto longo, não o parser — quem transforma Markdown em
|
|
1045
|
+
elementos é o consumidor. Aqui só se decide como esses elementos se leem.
|
|
1046
|
+
|
|
1047
|
+
⚠ TODA regra abaixo é ESCOPADA em `.prose`, e isso não é estilo de escrita: é a trava do item, e
|
|
1048
|
+
ela tem uma conta paga atrás. As cinco regras de tabela deste arquivo eram de ELEMENTO e valiam
|
|
1049
|
+
para toda <table> do documento — o calendário nasceu com 720px de largura por causa disso, e
|
|
1050
|
+
nenhum gate viu, porque os checks 15 e 18 comparam CLASSE e seletor de elemento não tem
|
|
1051
|
+
nenhuma. Escrever `blockquote{...}` aqui repetiria o Lote 4 com outro elemento.
|
|
1052
|
+
|
|
1053
|
+
O tamanho sobe para `--text-base`: o corpo do documento é `--text-md` (14px), que serve a
|
|
1054
|
+
interface e é pequeno para ler artigo. A entrelinha é `--leading-relaxed`, que existe no token
|
|
1055
|
+
e não tinha uso. A MEDIDA de linha é `--prose-measure`, no idioma das outras válvulas.
|
|
1056
|
+
|
|
1057
|
+
A FONTE não muda: `--font-editorial` (IBM Plex Serif) existe e está sem uso, e usá-la aqui
|
|
1058
|
+
seria decisão de APARÊNCIA que o BUILDING.md §3.1 manda levar ao Victor com imagem do antes e
|
|
1059
|
+
do depois. Quem quiser serifa na prosa aponta a variável; a Aurea não decide isso sozinha. */
|
|
1060
|
+
.prose { max-width:var(--prose-measure,68ch); font-size:var(--text-base); line-height:var(--leading-relaxed); }
|
|
1061
|
+
.prose > * + * { margin-block-start:var(--space-4); }
|
|
1062
|
+
.prose > h2,.prose > h3,.prose > h4 { margin-block-start:var(--space-8); }
|
|
1063
|
+
.prose h1,.prose h2,.prose h3,.prose h4 { line-height:var(--leading-tight); font-weight:var(--weight-semibold); }
|
|
1064
|
+
.prose h1 { font-size:var(--text-3xl); }
|
|
1065
|
+
.prose h2 { font-size:var(--text-2xl); }
|
|
1066
|
+
.prose h3 { font-size:var(--text-xl); }
|
|
1067
|
+
.prose h4 { font-size:var(--text-lg); }
|
|
1068
|
+
.prose blockquote { margin-inline:0; padding-inline-start:var(--space-4); border-inline-start:2px solid var(--border-strong); color:var(--muted-foreground); }
|
|
1069
|
+
.prose ul,.prose ol { padding-inline-start:var(--space-6); }
|
|
1070
|
+
.prose li + li { margin-block-start:var(--space-2); }
|
|
1071
|
+
/* `0.9em` e não um token: código dentro do texto se mede em relação à LINHA em que está, e um
|
|
1072
|
+
valor absoluto o deixaria maior que o parágrafo dentro de um h2. É o mesmo motivo pelo qual o
|
|
1073
|
+
`.badge` tem `line-height:1` — geometria que depende do contexto se escreve relativa. */
|
|
1074
|
+
.prose code { padding:var(--space-05) var(--space-1); border-radius:var(--radius-xs); background:var(--surface-2); font-family:var(--font-code); font-size:0.9em; }
|
|
1075
|
+
.prose pre { overflow-x:auto; padding:var(--space-4); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--surface-2); }
|
|
1076
|
+
.prose pre code { padding:0; border-radius:0; background:transparent; font-size:var(--text-sm); }
|
|
1077
|
+
.prose img { max-width:100%; height:auto; border-radius:var(--radius-lg); }
|
|
1078
|
+
.prose hr { border:0; border-block-start:1px solid var(--border); }
|
|
1079
|
+
.prose figcaption { color:var(--muted-foreground); font-size:var(--text-sm); }
|
|
1080
|
+
/* A tabela da prosa NÃO é a tabela de dados: sem `min-width:720px`, sem faixa de cabeçalho em
|
|
1081
|
+
caixa alta e sem hover de linha. Uma tabela de três colunas no meio de um artigo não é uma
|
|
1082
|
+
grade — forçá-la a 720px é exatamente o defeito que o calendário sofreu. */
|
|
1083
|
+
.prose table { width:100%; border-collapse:collapse; font-size:var(--text-md); }
|
|
1084
|
+
.prose th,.prose td { padding:var(--space-2) var(--space-3); text-align:start; border-block-end:1px solid var(--border); }
|
|
1085
|
+
.prose th { color:var(--subtle-foreground); font-weight:var(--weight-semibold); }
|
|
1086
|
+
|
|
1087
|
+
/* LISTA ORDENÁVEL (PLANO-1.0, item L3). Duas regras aqui não são decoração e quebram
|
|
1088
|
+
comportamento se saírem:
|
|
1089
|
+
• `touch-action:none` na alça — sem ela o navegador rola a página em vez de deixar arrastar, e
|
|
1090
|
+
o componente não funciona em toque nenhum. É o par obrigatório do `setPointerCapture`;
|
|
1091
|
+
• `cursor:grab`/`grabbing`, que é a única affordance de que aquilo se arrasta.
|
|
1092
|
+
O item PEGO se marca com `data-grabbed`, e o sinal é ELEVAÇÃO e borda — não cor sozinha
|
|
1093
|
+
(WCAG 1.4.1), e não a cápsula de `.is-selected`: pego e escolhido são coisas diferentes e não
|
|
1094
|
+
podem falar a mesma língua. */
|
|
1095
|
+
.sortable-list { display:grid; gap:var(--space-2); margin:0; padding:0; list-style:none; }
|
|
1096
|
+
.sortable-item { display:flex; align-items:center; gap:var(--space-2); padding:var(--space-2) var(--space-3); border:1px solid var(--border); border-radius:var(--radius-lg); background:var(--card); }
|
|
1097
|
+
.sortable-item[data-grabbed] { border-color:var(--border-strong); box-shadow:var(--shadow-lg); }
|
|
1098
|
+
.sortable-handle { display:grid; place-items:center; min-width:var(--space-6); min-height:var(--space-6); padding:0; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--muted-foreground); cursor:grab; touch-action:none; }
|
|
1099
|
+
.sortable-handle[aria-pressed="true"] { cursor:grabbing; color:var(--primary); }
|
|
1100
|
+
.sortable-label { min-width:0; }
|
|
1101
|
+
|
|
1102
|
+
/* EDITOR POR BLOCOS (PLANO-1.0, item N1). A Aurea é dona da MOLDURA; o texto rico de dentro é do
|
|
1103
|
+
consumidor — ADR-0025, e o comentário do `inputs.tsx` traz a medição inteira.
|
|
1104
|
+
Duas regras aqui são COMPORTAMENTO e não enfeite, as mesmas da lista ordenável, porque o
|
|
1105
|
+
protocolo de arrasto é o mesmo (`useReorder`):
|
|
1106
|
+
• `touch-action:none` na alça — sem ela o navegador rola a página em vez de deixar arrastar, e
|
|
1107
|
+
o componente não funciona em toque nenhum. É o par obrigatório do `setPointerCapture`;
|
|
1108
|
+
• `cursor:grab`/`grabbing`, a única affordance de que aquilo se arrasta.
|
|
1109
|
+
`min-width:0` no corpo NÃO é enfeite tampouco: sem ele um filho largo (imagem, tabela, bloco de
|
|
1110
|
+
código) estoura a coluna do grid em vez de encolher, e a página ganha rolagem lateral — que é
|
|
1111
|
+
exatamente o que o `catalog-sweep` reprova.
|
|
1112
|
+
O raio é `--radius-lg` e não `--radius-card`: bloco é LINHA de uma lista, no mesmo idioma do
|
|
1113
|
+
`.sortable-item`, e não um cartão flutuante. Sai da identidade que já existe, sem decisão de
|
|
1114
|
+
aparência nova. O bloco PEGO se marca com `data-grabbed`, e o sinal é ELEVAÇÃO e borda — não
|
|
1115
|
+
cor sozinha (WCAG 1.4.1). */
|
|
1116
|
+
.block-editor { display:grid; gap:var(--space-3); margin:0; padding:0; list-style:none; }
|
|
1117
|
+
.block-item { display:grid; grid-template-columns:auto minmax(0,1fr); gap:var(--space-3); padding:var(--space-3); border:1px solid var(--border); border-radius:var(--radius-lg); background:var(--card); }
|
|
1118
|
+
.block-item[data-grabbed] { border-color:var(--border-strong); box-shadow:var(--shadow-lg); }
|
|
1119
|
+
.block-rail { display:grid; grid-auto-rows:min-content; gap:var(--space-1); }
|
|
1120
|
+
.block-handle,.block-remove { display:grid; place-items:center; min-width:var(--space-6); min-height:var(--space-6); padding:0; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--muted-foreground); }
|
|
1121
|
+
.block-handle { cursor:grab; touch-action:none; }
|
|
1122
|
+
.block-handle[aria-pressed="true"] { cursor:grabbing; color:var(--primary); }
|
|
1123
|
+
.block-body { min-width:0; }
|
|
1124
|
+
|
|
1125
|
+
/* CARROSSEL (PLANO-1.0, item L1). A pele É o motor: o encaixe, a rolagem por toque, a inércia e
|
|
1126
|
+
as setas de teclado saem de `scroll-snap` num contêiner nativo — o React só descobre em qual
|
|
1127
|
+
slide se está. Por isso estas regras não são decoração, e apagá-las quebra comportamento.
|
|
1128
|
+
`--carousel-slide` é a válvula que faz o caso `multiple` da referência sem uma prop: quantos
|
|
1129
|
+
aparecem por vez é decisão de layout da página, no idioma do `--qr-size` e do `--media-h`.
|
|
1130
|
+
`scroll-behavior:smooth` mora AQUI e não no JavaScript de propósito: `scrollBy` sem `behavior`
|
|
1131
|
+
obedece ao valor computado, e a regra global de `prefers-reduced-motion` deste arquivo já o
|
|
1132
|
+
derruba para `auto` — quem pediu menos movimento recebe menos movimento, sem código novo. */
|
|
1133
|
+
.carousel { display:grid; gap:var(--space-3); }
|
|
1134
|
+
.carousel-track { display:flex; gap:var(--space-3); overflow-x:auto; overflow-y:hidden; scroll-snap-type:inline mandatory; scroll-behavior:smooth; overscroll-behavior-inline:contain; scrollbar-width:none; }
|
|
1135
|
+
.carousel-track::-webkit-scrollbar { width:0; height:0; }
|
|
1136
|
+
/* Sem regra de foco própria: a global do topo deste arquivo já dá o anel, e ela usa
|
|
1137
|
+
`--focus-strong` — que é `--primary` no escuro e `--brand-yellow-foreground` no claro. A versão
|
|
1138
|
+
anterior desta linha fixava `--primary` nos dois e teria trocado a cor do foco num deles. */
|
|
1139
|
+
.carousel-slide { flex:0 0 var(--carousel-slide,100%); min-width:0; scroll-snap-align:start; }
|
|
1140
|
+
.carousel-controls { display:flex; align-items:center; justify-content:center; gap:var(--space-2); }
|
|
1141
|
+
.carousel-dots { display:flex; align-items:center; gap:var(--space-1); }
|
|
1142
|
+
/* 24×24 de ALVO com 8×8 de desenho: abaixo disso é reprovação do WCAG 2.2 AA (2.5.8), e uma fila
|
|
1143
|
+
de pontos é onde esse erro nasce. O ponto vem do ::before para não custar um elemento nem uma
|
|
1144
|
+
classe a mais — o alvo é o botão inteiro, o desenho é o miolo. */
|
|
1145
|
+
.carousel-dot { width:var(--space-6); height:var(--space-6); display:grid; place-items:center; padding:0; border:0; background:transparent; cursor:pointer; }
|
|
1146
|
+
.carousel-dot::before { content:""; width:var(--space-2); height:var(--space-2); border-radius:var(--radius-full); background:var(--border); }
|
|
1147
|
+
.carousel-dot[aria-current="true"]::before { background:var(--primary); }
|
|
1148
|
+
|
|
1149
|
+
/* ========================================================================== */
|
|
1150
|
+
/* 08. ÍCONES */
|
|
1151
|
+
/* ========================================================================== */
|
|
1152
|
+
.icon-search { max-width:420px; }
|
|
1153
|
+
.icon-category { margin-top:26px; } .icon-category h3 { margin:0 0 12px; font-size:var(--text-base); }
|
|
1154
|
+
.icon-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:8px; }
|
|
1155
|
+
.icon-tile { min-height:86px; display:flex; flex-direction:column; align-items:flex-start; justify-content:space-between; gap:12px; padding:13px; border:1px solid var(--border); border-radius:var(--radius-lg); background:var(--secondary); color:var(--muted-foreground); cursor:pointer; text-align:start; transition:transform var(--duration-fast) var(--ease-standard),border-color var(--duration-fast),color var(--duration-fast); }
|
|
1156
|
+
@media (hover:hover) and (pointer:fine) { .icon-tile:hover { color:var(--foreground); border-color:var(--primary); transform:translateY(-1px); } } .icon-tile:focus-visible { color:var(--foreground); border-color:var(--primary); } .icon-tile span { overflow:hidden; max-width:100%; text-overflow:ellipsis; white-space:nowrap; font:11px var(--font-code); }
|
|
1157
|
+
.dialog-backdrop { position:fixed; inset:0; z-index:var(--z-modal); background:var(--overlay); backdrop-filter:blur(5px); }
|
|
1158
|
+
.dialog { position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); z-index:var(--z-modal); width:min(560px,calc(100vw - 40px)); max-height:calc(100vh - 40px); overflow:auto; padding:24px; border:1px solid var(--border); border-radius:var(--radius-card); background:var(--popover); color:var(--popover-foreground); box-shadow:var(--shadow-lg); }
|
|
1159
|
+
.dialog>header,.drawer>header { display:flex; align-items:flex-start; justify-content:space-between; gap:16px; margin-bottom:16px; } .dialog-body { display:grid; gap:14px; }
|
|
1160
|
+
/* O ConfirmDialog é o MESMO `.dialog` — não nasce uma segunda superfície flutuante, que seria a
|
|
1161
|
+
pele divergindo como divergiu entre `.table-wrap` e `.table-region`. O que muda é a caixa mais
|
|
1162
|
+
estreita (uma frase e dois botões não precisam de 560px) e o rodapé alinhado ao fim, com o
|
|
1163
|
+
destrutivo por último: a ordem visual é cancelar → agir, e é onde as quatro referências batem. */
|
|
1164
|
+
.dialog-confirm { width:min(420px,calc(100vw - 40px)); }
|
|
1165
|
+
.dialog-confirm>footer { display:flex; justify-content:flex-end; gap:var(--space-2); margin-block-start:var(--space-5); }
|
|
1166
|
+
.drawer-wrap { position:fixed; inset:0; z-index:var(--z-drawer); display:none; background:var(--overlay); } .drawer-wrap.open { display:block; }
|
|
1167
|
+
.drawer-backdrop { position:fixed; inset:0; z-index:var(--z-drawer); background:var(--overlay); }
|
|
1168
|
+
.drawer { position:fixed; top:0; bottom:0; z-index:var(--z-drawer); width:min(480px,92vw); padding:24px; background:var(--surface-1); box-shadow:var(--shadow-lg); overflow:auto; } .drawer-right { right:0; border-left:1px solid var(--border); } .drawer-left { left:0; border-right:1px solid var(--border); }
|
|
1169
|
+
.toast-stack { position:fixed; inset-inline-end:22px; bottom:22px; z-index:var(--z-toast); width:min(360px,calc(100vw - 44px)); display:flex; flex-direction:column; gap:10px; } .toast { display:flex; align-items:center; gap:11px; padding:14px; border:1px solid var(--border); border-radius:var(--radius-lg); background:var(--popover); color:var(--popover-foreground); box-shadow:var(--shadow-md); transition:opacity .28s var(--ease-standard), transform .28s var(--ease-emphasized); } .toast>:first-child { flex:1; min-width:0; } .toast-text { display:flex; flex-direction:column; gap:2px; min-width:0; } .toast[data-starting-style],.toast[data-ending-style] { opacity:0; transform:translateY(12px); }
|
|
1170
|
+
/* As quatro faces do `AureaToastType`, escritas em 16/08/2026 — elas NÃO existiam, e o tipo
|
|
1171
|
+
publicado não pintava nada. O `system.tsx` emite `toast-${t.type}` desde sempre; classe por
|
|
1172
|
+
template é o ponto CEGO do check 18, que só enxerga classe literal — o mesmo defeito que o
|
|
1173
|
+
`log-${level}` já tinha tido. Varridos os 18 padrões dinâmicos do pacote React: este era o
|
|
1174
|
+
ÚNICO órfão (o `ev-${e.id}` do agents.tsx é `id`, não classe).
|
|
1175
|
+
Mecanismo REUSADO do .alert/.banner, não inventado: borda tingida + fundo semântico. Vêm
|
|
1176
|
+
DEPOIS da base `.toast` de propósito — mesma especificidade, a última regra vence, e é a
|
|
1177
|
+
armadilha que o comentário do .banner já registrava lá em cima. */
|
|
1178
|
+
.toast-info { border-color:color-mix(in srgb,var(--info-400) 38%,var(--border)); background:var(--info-bg); }
|
|
1179
|
+
.toast-success { border-color:color-mix(in srgb,var(--success-400) 38%,var(--border)); background:var(--success-bg); }
|
|
1180
|
+
.toast-warning { border-color:color-mix(in srgb,var(--warning-400) 38%,var(--border)); background:var(--warning-bg); }
|
|
1181
|
+
.toast-danger { border-color:color-mix(in srgb,var(--danger-400) 38%,var(--border)); background:var(--danger-bg); }
|
|
1182
|
+
/* CommandPaletteShell (Fase 11, achado A13). A superfície já existia aqui sob o nome
|
|
1183
|
+
`.command` — e `.command` é chrome da página de docs manual: nenhum componente React a
|
|
1184
|
+
emite. Ela passava no check 15 por ACIDENTE, porque o rótulo padrão "Type a command…" põe
|
|
1185
|
+
a palavra "command" numa string do pacote React e o gate lê as strings do fonte. Foi para
|
|
1186
|
+
apps/docs/docs.css, que é a casa dela; o sistema fica com os dois nomes que o componente
|
|
1187
|
+
emite de verdade. Não-modal de propósito, como a gaveta do AppShell (ADR-0003): o foco não
|
|
1188
|
+
fica preso, então não declaramos modalidade que não entregamos. */
|
|
1189
|
+
.command-overlay { position:fixed; inset:0; z-index:var(--z-modal); display:grid; place-items:start center; padding:var(--space-16) var(--space-5) var(--space-5); background:var(--overlay); backdrop-filter:blur(5px); }
|
|
1190
|
+
.command-palette { display:grid; gap:var(--space-2); width:min(680px,100%); max-height:100%; overflow:auto; padding:var(--space-4); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--popover); color:var(--popover-foreground); box-shadow:var(--shadow-lg); }
|
|
1191
|
+
/* Camadas flutuantes (Base UI): tooltip, popover, menu. z-modal para funcionarem sobre diálogos; empilhamento mútuo pela ordem do portal no DOM. */
|
|
1192
|
+
.tooltip { z-index:var(--z-modal); max-width:260px; padding:6px 10px; border:1px solid var(--border); border-radius:var(--radius-md); background:var(--surface-inset); color:var(--foreground); font-size:var(--text-xs); line-height:var(--leading-normal); box-shadow:var(--shadow-md); }
|
|
1193
|
+
.popover { z-index:var(--z-modal); min-width:220px; max-width:min(360px,calc(100vw - 32px)); padding:16px; border:1px solid var(--border); border-radius:var(--radius-card); background:var(--popover); color:var(--popover-foreground); box-shadow:var(--shadow-lg); display:grid; gap:10px; }
|
|
1194
|
+
.menu { z-index:var(--z-modal); min-width:200px; max-width:min(320px,calc(100vw - 32px)); padding:6px; border:1px solid var(--border); border-radius:var(--radius-lg); background:var(--popover); color:var(--popover-foreground); box-shadow:var(--shadow-lg); }
|
|
1195
|
+
.menu-item { display:flex; align-items:center; gap:10px; width:100%; min-height:var(--control-h-md); padding:0 10px; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--foreground); font:inherit; text-align:start; cursor:pointer; }
|
|
1196
|
+
.menu-item[data-highlighted],.menu-item:hover:not([data-disabled]) { background:var(--surface-3); outline:none; }
|
|
1197
|
+
.menu-item[data-disabled] { opacity:.5; cursor:not-allowed; }
|
|
1198
|
+
/* CommandPalette (M6): a lista dentro da paleta. Reusa `.menu` e `.menu-item` — a paleta nao
|
|
1199
|
+
inventa uma segunda pele de lista, que e o defeito que a `.table-region` cobrou caro. O que se
|
|
1200
|
+
acrescenta e o teto de altura (a lista rola, a caixa nao cresce sem fim) e a linha do item,
|
|
1201
|
+
que tem icone, rotulo que se estica e atalho no fim.
|
|
1202
|
+
DEPOIS do `.menu-item` de proposito: as duas regras tem a MESMA especificidade, entao quem vem
|
|
1203
|
+
por ultimo vence. Escrita antes, a grade de tres colunas era apagada pelo `display:flex` do
|
|
1204
|
+
menu — medido em 13/08/2026, e o gate de pele foi quem pegou. */
|
|
1205
|
+
.command-positioner { inline-size:var(--anchor-width); }
|
|
1206
|
+
.command-list { max-height:min(50vh,360px); overflow-y:auto; overscroll-behavior:contain; }
|
|
1207
|
+
.command-item { display:grid; grid-template-columns:auto minmax(0,1fr) auto; gap:var(--space-3); align-items:center; }
|
|
1208
|
+
.command-item-label { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
1209
|
+
|
|
1210
|
+
.menu-sep { height:1px; margin:6px 4px; background:var(--border); border:0; }
|
|
1211
|
+
/* Combobox: reaproveita .menu/.menu-item; só dimensionamento e a coluna do check são próprios.
|
|
1212
|
+
--anchor-width e --available-height vêm do positioner do Base UI. */
|
|
1213
|
+
.combobox-group { position:relative; display:flex; align-items:center; }
|
|
1214
|
+
.combobox-group .input { padding-inline-end:calc(var(--control-h-sm) * 2 + 10px); }
|
|
1215
|
+
.combobox-actions { position:absolute; inset-inline-end:5px; display:flex; align-items:center; gap:2px; }
|
|
1216
|
+
.combobox-popup { inline-size:var(--anchor-width); min-inline-size:0; max-inline-size:none; max-block-size:min(320px,var(--available-height)); overflow-y:auto; overscroll-behavior:contain; }
|
|
1217
|
+
.combobox-empty { padding:12px 10px; color:var(--muted-foreground); font-size:var(--text-sm); }
|
|
1218
|
+
.combobox-empty:empty { display:none; }
|
|
1219
|
+
.combobox-item { display:grid; grid-template-columns:16px minmax(0,1fr); gap:8px; align-items:center; }
|
|
1220
|
+
.combobox-check { display:inline-flex; color:var(--primary); }
|
|
1221
|
+
/* MultiCombobox (Fase 4) — chips de multi-seleção + grupos. Espaçamento novo tokenizado. */
|
|
1222
|
+
.combobox-multi { display:flex; align-items:center; gap:var(--space-2); width:100%; min-width:0; min-height:var(--control-h-md); padding:var(--space-1) var(--space-2); background:var(--field-bg); border:1px solid var(--border-strong); border-radius:var(--radius-control); transition:border-color var(--duration-fast); }
|
|
1223
|
+
.combobox-multi:hover { border-color:var(--border); }
|
|
1224
|
+
.combobox-multi:focus-within { outline:2px solid var(--focus-strong); outline-offset:2px; border-color:var(--focus-strong); }
|
|
1225
|
+
.combobox-multi>.combobox-actions { position:static; inset-inline-end:auto; }
|
|
1226
|
+
/* o campo de chips não é `.input`, então a regra de :disabled dos campos não o alcança. Quem
|
|
1227
|
+
marca aqui é o `data-disabled` que o Base UI põe no InputGroup a partir do estado da Root. */
|
|
1228
|
+
.combobox-multi[data-disabled] { opacity:.5; cursor:not-allowed; }
|
|
1229
|
+
.combobox-multi[data-disabled] .combobox-chip-input { cursor:not-allowed; }
|
|
1230
|
+
.combobox-chips { display:flex; flex:1; flex-wrap:wrap; align-items:center; gap:var(--space-2); min-width:0; }
|
|
1231
|
+
.combobox-chip { display:inline-flex; align-items:center; gap:var(--space-1); padding-block:var(--space-1); padding-inline:var(--space-3) var(--space-1); background:var(--secondary); color:var(--foreground); border-radius:var(--radius-control); font-size:var(--text-sm); }
|
|
1232
|
+
.combobox-chip-remove { display:inline-flex; padding:0; border:0; background:transparent; color:var(--muted-foreground); border-radius:var(--radius-full); cursor:pointer; }
|
|
1233
|
+
.combobox-chip-remove:hover { color:var(--foreground); }
|
|
1234
|
+
.combobox-chip-input { flex:1; min-width:6ch; height:var(--control-h-sm); border:0; background:transparent; padding:0 var(--space-1); color:var(--foreground); }
|
|
1235
|
+
.combobox-chip-input::placeholder { color:var(--subtle-foreground); }
|
|
1236
|
+
.combobox-chip-input:focus-visible { outline:none; }
|
|
1237
|
+
.combobox-group-label { padding:var(--space-1) var(--space-2); color:var(--muted-foreground); font-size:var(--text-xs); font-weight:var(--weight-semibold); }
|
|
1238
|
+
/* FileInput / DropZone (Fase 4) — só a UI de entrada; upload real é a Fase 5.
|
|
1239
|
+
A zona é um <label> em volta do <input> nativo: clique/foco/teclado de graça,
|
|
1240
|
+
o arrastar-soltar é reforço. Espaçamento novo tokenizado; superfície = card. */
|
|
1241
|
+
.dropzone { display:flex; flex-direction:column; align-items:center; gap:var(--space-2); padding:var(--space-8) var(--space-6); text-align:center; color:var(--muted-foreground); background:var(--surface-inset); border:1px dashed var(--border-strong); border-radius:var(--radius-card); cursor:pointer; transition:border-color var(--duration-fast),background-color var(--duration-fast); }
|
|
1242
|
+
.dropzone:hover { border-color:var(--border); }
|
|
1243
|
+
.dropzone:focus-within { outline:2px solid var(--focus-strong); outline-offset:2px; border-color:var(--focus-strong); }
|
|
1244
|
+
.dropzone[data-dragging="true"] { border-style:solid; border-color:var(--primary); background:var(--surface-2); }
|
|
1245
|
+
.dropzone strong { color:var(--foreground); }
|
|
1246
|
+
.dropzone-icon { color:var(--primary); }
|
|
1247
|
+
.dropzone-hint { font-size:var(--text-xs); }
|
|
1248
|
+
.file-list { display:flex; flex-direction:column; gap:var(--space-2); margin-top:var(--space-3); padding:0; list-style:none; }
|
|
1249
|
+
.file-item { display:flex; align-items:center; gap:var(--space-3); padding:var(--space-2) var(--space-3); background:var(--surface-2); border:1px solid var(--border); border-radius:var(--radius-md); }
|
|
1250
|
+
.file-progress { flex-basis:var(--space-20); flex-shrink:0; } /* largura fixa da barra de upload (auditoria 18/07, M14) */
|
|
1251
|
+
.file-name { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
1252
|
+
.file-size { flex:none; color:var(--muted-foreground); font-size:var(--text-xs); font-variant-numeric:tabular-nums; }
|
|
1253
|
+
|
|
1254
|
+
/* TreeView (Fase 4) — árvore headless própria (Base UI 1.6 não tem tree).
|
|
1255
|
+
role=tree/treeitem/group + roving tabindex vêm do React; aqui só a pele.
|
|
1256
|
+
A indentação por nível é padding-inline-start inline (style). Espaço novo
|
|
1257
|
+
tokenizado; a linha não é pill (radius-sm, como o .menu-item). */
|
|
1258
|
+
.tree, .tree-group { margin:0; padding:0; list-style:none; }
|
|
1259
|
+
.tree-item { outline:none; }
|
|
1260
|
+
.tree-node { display:flex; align-items:center; gap:var(--space-2); min-height:var(--control-h-md); padding-block:var(--space-1); padding-inline-end:var(--space-3); border-radius:var(--radius-sm); color:var(--foreground); cursor:pointer; user-select:none; }
|
|
1261
|
+
.tree-node:hover { background:var(--surface-3); }
|
|
1262
|
+
.tree-item:focus-visible > .tree-node { outline:2px solid var(--focus-strong); outline-offset:-2px; }
|
|
1263
|
+
.tree-node[data-selected] { background:color-mix(in srgb,var(--primary) 14%,transparent); }
|
|
1264
|
+
.tree-twist { flex:none; color:var(--muted-foreground); transition:transform var(--duration-fast); }
|
|
1265
|
+
.tree-item[aria-expanded="true"] > .tree-node > .tree-twist { transform:rotate(90deg); }
|
|
1266
|
+
.tree-item[aria-expanded="false"]:dir(rtl) > .tree-node > .tree-twist { transform:rotate(180deg); }
|
|
1267
|
+
.tree-indent { flex:none; width:1rem; }
|
|
1268
|
+
.tree-label { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
1269
|
+
|
|
1270
|
+
/* NotificationCenter (Fase 4) — compõe o .popover; aqui só o gatilho com count,
|
|
1271
|
+
o cabeçalho e as linhas do feed. Espaço novo tokenizado; a linha usa radius-sm
|
|
1272
|
+
(não é pill, como o .menu-item/.tree-node). O painel NÃO é live region — a
|
|
1273
|
+
chegada é anunciada por um role=status à parte no React. */
|
|
1274
|
+
.notification-trigger { position:relative; display:inline-flex; }
|
|
1275
|
+
.notification-count { position:absolute; inset-block-start:-4px; inset-inline-end:-4px; display:inline-flex; align-items:center; justify-content:center; min-width:18px; height:18px; padding:0 var(--space-1); border-radius:var(--radius-control); background:var(--primary); color:var(--primary-foreground); font-size:var(--text-xs); font-weight:var(--weight-semibold); line-height:var(--leading-none); pointer-events:none; }
|
|
1276
|
+
.notification-panel { width:min(360px,calc(100vw - 32px)); max-width:none; padding:0; gap:0; display:flex; flex-direction:column; overflow:hidden; }
|
|
1277
|
+
.notification-head { display:flex; align-items:center; justify-content:space-between; gap:var(--space-3); padding:var(--space-3) var(--space-4); border-block-end:1px solid var(--border); }
|
|
1278
|
+
.notification-head strong { font-size:var(--text-sm); }
|
|
1279
|
+
.notification-list { margin:0; padding:var(--space-1); overflow-y:auto; max-height:min(60vh,440px); }
|
|
1280
|
+
.notification-sublist { margin:0; padding:0; list-style:none; }
|
|
1281
|
+
.notification-group-label { margin:0; padding:var(--space-2) var(--space-3) var(--space-1); color:var(--muted-foreground); font-size:var(--text-xs); font-weight:var(--weight-semibold); letter-spacing:var(--tracking-wide); text-transform:uppercase; }
|
|
1282
|
+
.notification-item { display:grid; grid-template-columns:auto minmax(0,1fr) auto; align-items:baseline; column-gap:var(--space-3); row-gap:var(--space-1); width:100%; padding:var(--space-3); border:0; border-radius:var(--radius-sm); background:none; color:var(--foreground); font:inherit; text-align:start; }
|
|
1283
|
+
button.notification-item { cursor:pointer; }
|
|
1284
|
+
button.notification-item:hover { background:var(--surface-3); }
|
|
1285
|
+
.notification-item:focus-visible { outline:2px solid var(--focus-strong); outline-offset:-2px; }
|
|
1286
|
+
.notification-dot { grid-row:1/-1; align-self:center; width:8px; height:8px; border-radius:50%; background:var(--primary); }
|
|
1287
|
+
.notification-item[data-read] .notification-dot { visibility:hidden; }
|
|
1288
|
+
.notification-item-title { grid-column:2; display:flex; align-items:center; gap:var(--space-2); min-width:0; font-size:var(--text-sm); font-weight:var(--weight-medium); }
|
|
1289
|
+
.notification-item[data-read] .notification-item-title { color:var(--muted-foreground); font-weight:var(--weight-regular); }
|
|
1290
|
+
.notification-item-desc { grid-column:2; color:var(--muted-foreground); font-size:var(--text-xs); }
|
|
1291
|
+
.notification-time { grid-column:3; grid-row:1; color:var(--muted-foreground); font-size:var(--text-xs); white-space:nowrap; }
|
|
1292
|
+
.notification-empty { margin:0; padding:var(--space-8) var(--space-4); color:var(--muted-foreground); font-size:var(--text-sm); text-align:center; }
|
|
1293
|
+
/* EmptyState é o membro GRANDE da família "aqui não há nada" — .notification-empty acima e
|
|
1294
|
+
.datagrid-empty abaixo já respondiam a mesma pergunta do mesmo jeito (centralizado, muted),
|
|
1295
|
+
e o componente público era o único dos três sem regra (achado A13). A ordem das partes
|
|
1296
|
+
(imagem → título → corpo → ação) é a do padrão de empty state do Carbon, registrado em
|
|
1297
|
+
REFERENCES.md; a pele é Aurea. O título vinha com o h3 do NAVEGADOR (16,38px). */
|
|
1298
|
+
.empty-state { display:flex; flex-direction:column; align-items:center; gap:var(--space-3); padding:var(--space-10) var(--space-6); color:var(--muted-foreground); text-align:center; }
|
|
1299
|
+
.empty-state > .icon { color:var(--subtle-foreground); }
|
|
1300
|
+
.empty-state p { max-width:46ch; margin:0; }
|
|
1301
|
+
.empty-title { margin:0; color:var(--foreground); font-size:var(--text-base); font-weight:var(--weight-semibold); line-height:var(--leading-tight); }
|
|
1302
|
+
|
|
1303
|
+
/* DataGrid (Fase 4) — TanStack Table v8 headless; aqui só a pele, que reusa
|
|
1304
|
+
.table-wrap/table/th/td. aria-sort fica só no th ordenado; a linha
|
|
1305
|
+
selecionada usa data-selected (o estado acessível é o checkbox da linha).
|
|
1306
|
+
Espaço novo tokenizado. */
|
|
1307
|
+
.datagrid { display:grid; gap:var(--space-3); }
|
|
1308
|
+
.datagrid > .table-wrap:focus-visible { outline:none; box-shadow:0 0 0 3px color-mix(in oklab,var(--focus) 38%,transparent); }
|
|
1309
|
+
.datagrid > .pagination { justify-self:end; }
|
|
1310
|
+
/* Fix aditivo: os 34px dos botões numéricos do .pagination esmagavam os botões
|
|
1311
|
+
de TEXTO (Anterior/Próxima) do Pagination React. Não muda os numéricos. */
|
|
1312
|
+
/* text-transform/letter-spacing: o UA reseta nos <button>; herdar explícito
|
|
1313
|
+
para o cabeçalho ordenável ficar idêntico ao th estático. */
|
|
1314
|
+
.datagrid-sort { display:inline-flex; align-items:center; gap:var(--space-1); padding:0; border:0; background:none; color:inherit; font:inherit; text-transform:inherit; letter-spacing:inherit; cursor:pointer; }
|
|
1315
|
+
.datagrid-sort:focus-visible { outline:2px solid var(--focus-strong); outline-offset:2px; border-radius:var(--radius-sm); }
|
|
1316
|
+
.datagrid-sort-icon { flex:none; color:var(--subtle-foreground); }
|
|
1317
|
+
th[aria-sort] .datagrid-sort-icon { color:var(--primary); }
|
|
1318
|
+
.datagrid-selcol { width:1%; white-space:nowrap; }
|
|
1319
|
+
|
|
1320
|
+
/* F3: a linha de filtro é do PRÓPRIO cabeçalho, então herda o recuo lateral das
|
|
1321
|
+
células e nasce alinhada com a coluna — ninguém escreve alinhamento aqui.
|
|
1322
|
+
As três declarações abaixo foram provadas UMA A UMA no navegador, tirando cada
|
|
1323
|
+
uma e medindo de novo: sem `text-transform` o campo digita em MAIÚSCULAS; sem
|
|
1324
|
+
`vertical-align` os dois controles (36px e 40px) começam em linhas diferentes;
|
|
1325
|
+
sem `gap:0` o rótulo só-para-leitor-de-tela cobra 7px de vão.
|
|
1326
|
+
Três outras foram escritas e MORRERAM na mesma prova, por não mudarem nada:
|
|
1327
|
+
`height:auto` (o conteúdo já passa de --row-h, e altura em célula é mínimo),
|
|
1328
|
+
`letter-spacing:normal` (o .input não herda o entreletras do cabeçalho) e
|
|
1329
|
+
`line-height:0` no rótulo (o <label> vazio já não ocupa altura). */
|
|
1330
|
+
.datagrid-filters th { padding-block:var(--space-2); text-transform:none; vertical-align:top; }
|
|
1331
|
+
.datagrid-filters .field { gap:0; }
|
|
1332
|
+
|
|
1333
|
+
/* F6: cabeçalho fixo. A `.table-wrap` já é o contêiner de rolagem (overflow:auto),
|
|
1334
|
+
e é ELE que ancora o sticky — não a janela. Por isso a altura precisa de teto:
|
|
1335
|
+
sem teto a caixa nunca rola por dentro e o cabeçalho nunca teria de grudar.
|
|
1336
|
+
`--datagrid-max-h` é a válvula de escape, no mesmo idioma do `--qr-size`: quem
|
|
1337
|
+
sabe quanta tela tem é o consumidor, e altura não vira prop numérica (check 23).
|
|
1338
|
+
A linha de FILTRO gruda logo abaixo do cabeçalho, e o deslocamento é `--row-h`
|
|
1339
|
+
porque é essa a altura da célula de cabeçalho — medido, não deduzido. */
|
|
1340
|
+
.datagrid-sticky .table-wrap { max-block-size:var(--datagrid-max-h,60vh); }
|
|
1341
|
+
/* `z-index:1` fica DECLARADO COMO PRECAUÇÃO, não como fato provado: não consegui
|
|
1342
|
+
medi-lo (elementFromPoint usa coordenada de janela, e a grade está a 7000px de
|
|
1343
|
+
rolagem na página de prova). É prática corrente para cabeçalho fixo — sem ele o
|
|
1344
|
+
fundo da linha do corpo pode passar por cima —, e removê-lo por não ter gate
|
|
1345
|
+
seria trocar risco real por pureza de método. As outras três regras daqui foram
|
|
1346
|
+
provadas. */
|
|
1347
|
+
.datagrid-sticky thead th { position:sticky; inset-block-start:0; z-index:1; }
|
|
1348
|
+
.datagrid-sticky .datagrid-filters th { inset-block-start:var(--row-h); }
|
|
1349
|
+
|
|
1350
|
+
/* F7: a alça de redimensionar. Fina, colada no fim da célula e da altura toda —
|
|
1351
|
+
alvo estreito de propósito, porque largo demais rouba o clique do cabeçalho
|
|
1352
|
+
ordenável que está ao lado. O `th` precisa de `position:relative` para ancorá-la. */
|
|
1353
|
+
.datagrid thead th:has(> .datagrid-resizer) { position:relative; }
|
|
1354
|
+
.datagrid-resizer { position:absolute; inset-block:0; inset-inline-end:0; inline-size:var(--space-1); padding:0; border:0; background:none; cursor:col-resize; touch-action:none; }
|
|
1355
|
+
.datagrid-resizer:hover, .datagrid-resizer:focus-visible { background:var(--primary); }
|
|
1356
|
+
.datagrid-resizer:focus-visible { outline:2px solid var(--focus-strong); outline-offset:1px; }
|
|
1357
|
+
|
|
1358
|
+
/* F8: o esqueleto dentro da célula. Sem altura própria ele mede zero — a `.skeleton`
|
|
1359
|
+
é uma <div> vazia — e a linha de carregamento sairia rasa demais para parecer uma
|
|
1360
|
+
linha. `1em` acompanha a tipografia em vez de fixar pixel. */
|
|
1361
|
+
.datagrid-skeleton { block-size:1em; }
|
|
1362
|
+
|
|
1363
|
+
/* F9: lista e detalhe lado a lado.
|
|
1364
|
+
LIMITE DECLARADO: a decisão é por largura de JANELA, não da grade. O `@container`
|
|
1365
|
+
seria mais certo — quem sabe se o painel cabe é a grade — e foi tentado: exige
|
|
1366
|
+
`container-type:inline-size` num ancestral, e pôr isso na `.datagrid` dá a ela
|
|
1367
|
+
contenção de tamanho, o que COLAPSA a grade dentro de um pai que encolhe para
|
|
1368
|
+
caber (float, inline-block, item de flex com largura automática). Trocar um
|
|
1369
|
+
defeito de layout raro por um defeito de layout comum não vale. Consequência
|
|
1370
|
+
honesta: grade estreita dentro de janela larga divide mesmo assim — o escape é
|
|
1371
|
+
`--datagrid-detail-w`. */
|
|
1372
|
+
.datagrid-split { display:grid; gap:var(--space-3); align-items:start; }
|
|
1373
|
+
@media (min-width:768px) {
|
|
1374
|
+
.datagrid-split { grid-template-columns:1fr var(--datagrid-detail-w,20rem); }
|
|
1375
|
+
}
|
|
1376
|
+
.datagrid-detail { border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); padding:var(--space-4); }
|
|
1377
|
+
.datagrid-detail-head { display:flex; justify-content:flex-end; }
|
|
1378
|
+
|
|
1379
|
+
/* G2: a ação de conjunto fica à direita, acima da fila — perto do que ela comanda e
|
|
1380
|
+
fora do caminho de leitura da lista. */
|
|
1381
|
+
.file-queue-actions { display:flex; justify-content:flex-end; }
|
|
1382
|
+
|
|
1383
|
+
/* G3/G4: a miniatura ocupa o mesmo espaço do ícone que ela substitui — a linha da
|
|
1384
|
+
fila não muda de altura por ter prévia. `object-fit:cover` porque foto não é
|
|
1385
|
+
quadrada e deformar a prévia mente sobre o arquivo. */
|
|
1386
|
+
.file-thumb { flex:none; inline-size:var(--space-5); block-size:var(--space-5); border-radius:var(--radius-sm); object-fit:cover; }
|
|
1387
|
+
.file-checksum { color:var(--muted-foreground); font-family:var(--font-code); font-size:var(--text-xs); }
|
|
1388
|
+
|
|
1389
|
+
/* G5/G6: a escolha do conflito e o recibo. Os dois são superfície de card porque são
|
|
1390
|
+
blocos de decisão e de registro, não linhas da fila. */
|
|
1391
|
+
.file-conflict { display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-2); padding:var(--space-3); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--surface-2); }
|
|
1392
|
+
.file-receipt { padding:var(--space-3); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); }
|
|
1393
|
+
.file-receipt-head { display:flex; align-items:center; justify-content:space-between; gap:var(--space-2); }
|
|
1394
|
+
.file-receipt ul { margin:0; padding-inline-start:var(--space-5); color:var(--muted-foreground); font-size:var(--text-sm); }
|
|
1395
|
+
|
|
1396
|
+
/* Parte H — a camada operacional. As três primeiras peças são COMPOSIÇÃO: `.card` já
|
|
1397
|
+
dá a superfície flutuante, `.status` já dá o estado, `.data-list` já dá o par
|
|
1398
|
+
termo/valor. O que falta é só o arranjo — e arranjo é o que não vem de graça. */
|
|
1399
|
+
.agent-card { display:grid; gap:var(--space-3); }
|
|
1400
|
+
.agent-card-head { display:flex; align-items:center; gap:var(--space-3); }
|
|
1401
|
+
.agent-card-id { display:grid; flex:1; min-inline-size:0; }
|
|
1402
|
+
.agent-card-desc { margin:0; color:var(--muted-foreground); }
|
|
1403
|
+
.agent-caps { display:flex; flex-wrap:wrap; gap:var(--space-2); margin:0; padding:0; list-style:none; }
|
|
1404
|
+
.agent-cap { display:inline-flex; align-items:center; gap:var(--space-1); padding:var(--space-1) var(--space-3); border:1px solid var(--border); border-radius:var(--radius-control); font-size:var(--text-sm); }
|
|
1405
|
+
.agent-card-actions { display:flex; justify-content:flex-end; gap:var(--space-2); }
|
|
1406
|
+
.agent-inspector { display:grid; gap:var(--space-4); }
|
|
1407
|
+
.agent-inspector-head { display:flex; align-items:center; justify-content:space-between; }
|
|
1408
|
+
.agent-inspector-section { display:grid; gap:var(--space-2); }
|
|
1409
|
+
.agent-inspector-label { margin:0; color:var(--subtle-foreground); font-size:var(--text-xs); letter-spacing:var(--tracking-wider); text-transform:uppercase; font-weight:var(--weight-bold); }
|
|
1410
|
+
|
|
1411
|
+
/* H.b — a execução. O passo dobrável é `<details>` nativo, então a marca de aberto/
|
|
1412
|
+
fechado já é do navegador; o que se acrescenta é o arranjo e o traço de estado. */
|
|
1413
|
+
.invocation { display:grid; gap:var(--space-4); }
|
|
1414
|
+
.invocation-head { display:flex; align-items:center; justify-content:space-between; gap:var(--space-3); }
|
|
1415
|
+
.invocation-io { display:grid; gap:var(--space-2); }
|
|
1416
|
+
.invocation-label { margin:0; color:var(--subtle-foreground); font-size:var(--text-xs); letter-spacing:var(--tracking-wider); text-transform:uppercase; font-weight:var(--weight-bold); }
|
|
1417
|
+
.invocation-steps { display:grid; gap:var(--space-2); margin:0; padding:0; list-style:none; }
|
|
1418
|
+
/* O estado do passo entra por BORDA lateral, não por cor de fundo: fundo colorido
|
|
1419
|
+
compete com o texto do passo, e a borda diz o mesmo sem disputar leitura. */
|
|
1420
|
+
.invocation-step { padding-inline-start:var(--space-3); border-inline-start:2px solid var(--border); }
|
|
1421
|
+
.invocation-step[data-state="running"] { border-inline-start-color:var(--primary); }
|
|
1422
|
+
.invocation-step[data-state="error"] { border-inline-start-color:var(--danger-400); }
|
|
1423
|
+
.invocation-step-body { padding-block-start:var(--space-2); }
|
|
1424
|
+
|
|
1425
|
+
.task-queue { display:grid; gap:var(--space-3); margin:0; padding:0; list-style:none; }
|
|
1426
|
+
.task-item { display:grid; gap:var(--space-2); padding:var(--space-3); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); }
|
|
1427
|
+
.task-line { display:flex; align-items:center; gap:var(--space-2); }
|
|
1428
|
+
.task-title { flex:1; min-inline-size:0; font-weight:var(--weight-medium); }
|
|
1429
|
+
.task-desc { margin:0; color:var(--muted-foreground); font-size:var(--text-sm); }
|
|
1430
|
+
|
|
1431
|
+
/* H.c — governança da ação. */
|
|
1432
|
+
.approval { display:grid; gap:var(--space-3); }
|
|
1433
|
+
.approval-head { display:flex; align-items:center; justify-content:space-between; gap:var(--space-3); }
|
|
1434
|
+
.approval-desc, .approval-reason { margin:0; }
|
|
1435
|
+
.approval-reason { color:var(--muted-foreground); font-size:var(--text-sm); }
|
|
1436
|
+
/* Negar vem ANTES de aprovar na ordem de leitura e de tabulação: a ação destrutiva
|
|
1437
|
+
não deve ser a primeira a receber foco nem a mais fácil de acertar sem ler. */
|
|
1438
|
+
.approval-actions { display:flex; justify-content:flex-end; gap:var(--space-2); }
|
|
1439
|
+
.tool-permission-list { display:grid; gap:var(--space-3); margin:0; padding:0; list-style:none; }
|
|
1440
|
+
.tool-permission-item { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:var(--space-3); }
|
|
1441
|
+
.tool-permission-id { display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--space-2); min-inline-size:0; }
|
|
1442
|
+
.tool-permission-scope { padding:0 var(--space-1); border-radius:var(--radius-sm); background:var(--surface-2); font-family:var(--font-code); font-size:var(--text-xs); }
|
|
1443
|
+
|
|
1444
|
+
/* H.d — a observação. */
|
|
1445
|
+
.event-stream { display:grid; gap:var(--space-2); }
|
|
1446
|
+
/* O feed é do GRUPO: `role="feed"` só aceita `article` como filho, então o rótulo do grupo
|
|
1447
|
+
mora FORA dele. Ver o comentário do EventStream — a regra é do ARIA, não de estilo. */
|
|
1448
|
+
.event-group-feed { display:grid; gap:var(--space-2); }
|
|
1449
|
+
.event-group { margin:var(--space-3) 0 0; color:var(--subtle-foreground); font-size:var(--text-xs); letter-spacing:var(--tracking-wider); text-transform:uppercase; font-weight:var(--weight-bold); }
|
|
1450
|
+
.event-item { display:flex; align-items:baseline; gap:var(--space-3); }
|
|
1451
|
+
.event-body { display:grid; flex:1; min-inline-size:0; }
|
|
1452
|
+
/* O ponto do evento é o MESMO tamanho e a mesma escala do ponto do Status: dois
|
|
1453
|
+
indicadores de gravidade com tamanhos diferentes na mesma tela leem como coisas
|
|
1454
|
+
diferentes, e não são. */
|
|
1455
|
+
.event-dot { flex:none; inline-size:var(--space-2); block-size:var(--space-2); border-radius:var(--radius-full); background:var(--muted-foreground); }
|
|
1456
|
+
.event-item[data-severity="success"] .event-dot { background:var(--success-400); }
|
|
1457
|
+
.event-item[data-severity="warning"] .event-dot { background:var(--warning-400); }
|
|
1458
|
+
.event-item[data-severity="danger"] .event-dot { background:var(--danger-400); }
|
|
1459
|
+
.event-time { flex:none; color:var(--muted-foreground); font-family:var(--font-code); font-size:var(--text-xs); }
|
|
1460
|
+
|
|
1461
|
+
.trace { display:grid; gap:var(--space-1); margin:0; padding:0; list-style:none; }
|
|
1462
|
+
/* A profundidade do span entra como RECUO, e por variável: a cascata precisa mostrar
|
|
1463
|
+
quem chamou quem, e recuar por nível é o que a referência faz sem precisar desenhar
|
|
1464
|
+
linhas de ligação. */
|
|
1465
|
+
/* O RÓTULO é quem cede, e a barra tem piso. A primeira versão era
|
|
1466
|
+
`minmax(6rem,14rem) 1fr`, e num painel estreito o rótulo comia tudo: medido no catálogo em
|
|
1467
|
+
09/08/2026, as colunas resolviam `224px 24px` e a cascata inteira desenhava em 24px — barras
|
|
1468
|
+
de 24, 5, 6 e **0** pixels. O `1fr` só recebe a sobra, e não havia sobra. Com o mínimo do
|
|
1469
|
+
lado da BARRA e o rótulo podendo encolher até zero, quem trunca é o texto, que já tem
|
|
1470
|
+
reticência para isso — e o dado, que é a barra, nunca desaparece. */
|
|
1471
|
+
.trace-span { display:grid; grid-template-columns:minmax(0,14rem) minmax(8rem,1fr); align-items:center; gap:var(--space-3); padding-inline-start:calc(var(--trace-depth,0) * var(--space-3)); }
|
|
1472
|
+
.trace-label { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:var(--text-sm); }
|
|
1473
|
+
.trace-track { position:relative; block-size:var(--space-3); border-radius:var(--radius-full); background:var(--surface-2); }
|
|
1474
|
+
.trace-bar { position:absolute; inset-block:0; border-radius:var(--radius-full); background:var(--primary); }
|
|
1475
|
+
.trace-span[data-error] .trace-bar { background:var(--danger-400); }
|
|
1476
|
+
|
|
1477
|
+
.health-matrix { display:grid; grid-template-columns:repeat(auto-fill,minmax(12rem,1fr)); gap:var(--space-3); margin:0; padding:0; list-style:none; }
|
|
1478
|
+
.health-cell { display:grid; gap:var(--space-1); padding:var(--space-3); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); }
|
|
1479
|
+
.health-name { font-weight:var(--weight-medium); }
|
|
1480
|
+
|
|
1481
|
+
/* H.e — custo e memória.
|
|
1482
|
+
O número total é o `TotalMetric` da referência, e ele é UMA linha de arranjo: a escala
|
|
1483
|
+
tipográfica da Aurea vai só até `--text-base`, e o `text-3xl` de lá é a identidade DELA.
|
|
1484
|
+
Aqui o destaque vem do peso e do contraste com o rótulo em `--text-xs`, não de um degrau
|
|
1485
|
+
de fonte que a escala não tem. Compartilhado pelo ModelUsage e pelo CostMeter porque é a
|
|
1486
|
+
mesma coisa nos dois — duas classes diriam que são duas. */
|
|
1487
|
+
.metric-total { display:flex; align-items:baseline; gap:var(--space-2); }
|
|
1488
|
+
.metric-total strong { font-size:var(--text-base); font-weight:var(--weight-bold); font-variant-numeric:tabular-nums; }
|
|
1489
|
+
|
|
1490
|
+
.model-usage { display:grid; gap:var(--space-3); }
|
|
1491
|
+
.model-usage-list { display:grid; gap:var(--space-2); margin:0; padding:0; list-style:none; }
|
|
1492
|
+
/* Mesma regra do `.trace-span`, e pelo mesmo defeito medido no mesmo dia: o mínimo fica do
|
|
1493
|
+
lado da BARRA, e o nome do modelo encolhe com reticência. Barra sem piso desaparece antes
|
|
1494
|
+
do texto, e é ela que carrega o dado. */
|
|
1495
|
+
.model-usage-row { display:grid; grid-template-columns:minmax(0,12rem) minmax(8rem,1fr) auto; align-items:center; gap:var(--space-3); }
|
|
1496
|
+
.model-usage-name { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:var(--text-sm); }
|
|
1497
|
+
/* A trilha mede o MESMO que a do rastro: são os dois um `meter`, e dois medidores de
|
|
1498
|
+
alturas diferentes na mesma aplicação leem como coisas diferentes — não são. */
|
|
1499
|
+
.model-usage-track { position:relative; block-size:var(--space-3); border-radius:var(--radius-full); background:var(--surface-2); }
|
|
1500
|
+
.model-usage-bar { position:absolute; inset-block:0; inset-inline-start:0; border-radius:var(--radius-full); background:var(--primary); }
|
|
1501
|
+
.model-usage-value { font-size:var(--text-sm); font-variant-numeric:tabular-nums; }
|
|
1502
|
+
|
|
1503
|
+
.cost-meter { display:grid; gap:var(--space-3); }
|
|
1504
|
+
.cost-meter-track { position:relative; block-size:var(--space-3); border-radius:var(--radius-full); background:var(--surface-2); }
|
|
1505
|
+
.cost-meter-bar { position:absolute; inset-block:0; inset-inline-start:0; border-radius:var(--radius-full); background:var(--primary); }
|
|
1506
|
+
/* Estourar o teto muda a BARRA, e não o fundo do cartão: fundo colorido num cartão inteiro
|
|
1507
|
+
é o que a Aurea não faz, e a barra é justamente a peça que fala de quantidade.
|
|
1508
|
+
O limite BRANDO não tem cor, e isso foi MEDIDO, não escolhido por gosto: no tema escuro
|
|
1509
|
+
`--warning-400` É `var(--brand-yellow)`, o mesmo valor de `--primary`. Uma barra "de
|
|
1510
|
+
aviso" ali sairia idêntica à barra normal — degrau invisível justo em metade dos temas.
|
|
1511
|
+
O aviso do limite brando sai por PALAVRA, no Alert, que é o mesmo critério dos cinco
|
|
1512
|
+
estados do HealthMatrix. A cor fica para o limite rígido, onde o vermelho separa nos dois. */
|
|
1513
|
+
.cost-meter[data-state="over"] .cost-meter-bar { background:var(--danger-400); }
|
|
1514
|
+
|
|
1515
|
+
.memory-ledger { display:grid; gap:var(--space-2); margin:0; padding:0; list-style:none; }
|
|
1516
|
+
.memory-entry { display:grid; gap:var(--space-1); padding:var(--space-3); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); }
|
|
1517
|
+
.memory-line { display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--space-2); }
|
|
1518
|
+
.memory-content { flex:1; min-inline-size:0; }
|
|
1519
|
+
.memory-time { flex:none; color:var(--muted-foreground); font-family:var(--font-code); font-size:var(--text-xs); }
|
|
1520
|
+
/* Esquecida continua NA LISTA, riscada: o livro-razão registra o lançamento, não o estado
|
|
1521
|
+
final. Sumir com a linha apaga exatamente o que se procura quando o agente para de
|
|
1522
|
+
saber uma coisa. O risco não é a única marca — o selo ao lado diz "Forgotten" em palavra. */
|
|
1523
|
+
.memory-entry[data-operation="forgotten"] .memory-content { color:var(--muted-foreground); text-decoration:line-through; }
|
|
1524
|
+
.memory-provenance { font-size:var(--text-sm); }
|
|
1525
|
+
.memory-provenance summary { color:var(--subtle-foreground); font-size:var(--text-xs); letter-spacing:var(--tracking-wider); text-transform:uppercase; cursor:pointer; }
|
|
1526
|
+
.memory-source { margin:var(--space-2) 0 0; color:var(--muted-foreground); font-size:var(--text-sm); }
|
|
1527
|
+
|
|
1528
|
+
/* H.f — a relação. */
|
|
1529
|
+
.agent-messages { display:grid; gap:var(--space-2); margin:0; padding:0; list-style:none; }
|
|
1530
|
+
.agent-message { display:grid; gap:var(--space-1); padding:var(--space-3); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); }
|
|
1531
|
+
/* O recado que FALHOU muda a borda, não o fundo: é o mesmo tratamento do passo do
|
|
1532
|
+
`InvocationPanel`, e pelo mesmo motivo — fundo colorido disputa leitura com o texto. */
|
|
1533
|
+
.agent-message[data-kind="error"] { border-color:var(--danger-400); }
|
|
1534
|
+
.agent-message-line { display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-2); }
|
|
1535
|
+
.agent-message-route { display:inline-flex; align-items:center; gap:var(--space-1); flex:1; min-inline-size:0; }
|
|
1536
|
+
.agent-message-arrow { flex:none; color:var(--muted-foreground); }
|
|
1537
|
+
.agent-message-time { flex:none; color:var(--muted-foreground); font-family:var(--font-code); font-size:var(--text-xs); }
|
|
1538
|
+
.agent-message-body { margin:0; }
|
|
1539
|
+
.agent-message-why { font-size:var(--text-sm); }
|
|
1540
|
+
.agent-message-why summary { color:var(--subtle-foreground); font-size:var(--text-xs); letter-spacing:var(--tracking-wider); text-transform:uppercase; font-weight:var(--weight-bold); cursor:pointer; }
|
|
1541
|
+
.agent-message-reason { margin:var(--space-2) 0 0; color:var(--muted-foreground); font-size:var(--text-sm); }
|
|
1542
|
+
|
|
1543
|
+
.automation { display:grid; gap:var(--space-3); }
|
|
1544
|
+
.automation-head { display:flex; align-items:flex-start; justify-content:space-between; gap:var(--space-3); }
|
|
1545
|
+
.automation-id { display:grid; flex:1; min-inline-size:0; }
|
|
1546
|
+
/* Regra DESLIGADA não some e não muda de cor — ela recua. O interruptor ao lado já diz o
|
|
1547
|
+
estado em palavra e em teclado; apagar o cartão esconderia justamente a regra que alguém
|
|
1548
|
+
precisa achar para religar. */
|
|
1549
|
+
.automation:not([data-enabled]) .automation-id { color:var(--muted-foreground); }
|
|
1550
|
+
.automation-foot { display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-3); }
|
|
1551
|
+
|
|
1552
|
+
/* H14 — o grafo. A pele do MOTOR entra por variável, e nenhuma classe dele aparece aqui:
|
|
1553
|
+
o `@xyflow/react` publica tudo como `var(--xy-algo, --xy-algo-default)`, e sobrescrever a
|
|
1554
|
+
variável na nossa raiz vale para toda a árvore dele (propriedade customizada herda). Escrever
|
|
1555
|
+
`.react-flow__*` no core resolveria igual e criaria uma classe que componente nenhum daqui
|
|
1556
|
+
produz — o check 15 existe exatamente para barrar isso. O consumidor importa o `base.css`
|
|
1557
|
+
do motor (estrutura); o `style.css` dele, que é a identidade deles, nunca entra. */
|
|
1558
|
+
/* `inline-size:100%` não é enfeite, é a mesma lição do Chart: painel de demo é flex, e uma
|
|
1559
|
+
caixa de largura automática entra como item que encolhe — medido no catálogo, a tela do grafo
|
|
1560
|
+
deu 71px e os nós saíram todos para fora dela. A tela ocupa o que lhe derem. */
|
|
1561
|
+
.dependency-graph { inline-size:100%; block-size:28rem; border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); overflow:hidden;
|
|
1562
|
+
--xy-background-color:transparent;
|
|
1563
|
+
--xy-background-pattern-color:var(--border);
|
|
1564
|
+
--xy-edge-stroke:var(--muted-foreground);
|
|
1565
|
+
--xy-edge-stroke-selected:var(--primary);
|
|
1566
|
+
--xy-edge-label-color:var(--muted-foreground);
|
|
1567
|
+
--xy-edge-label-background-color:var(--card);
|
|
1568
|
+
--xy-connectionline-stroke:var(--primary);
|
|
1569
|
+
--xy-attribution-background-color:transparent; }
|
|
1570
|
+
/* A atribuição do motor (que a licença dele manda manter, e mantemos) traz `color:#999`
|
|
1571
|
+
CRAVADO no `init.css` — o único ponto em que a folha "estrutural" carrega cor. Reprovou
|
|
1572
|
+
contraste no axe, tema claro. A regra é de ELEMENTO e vem ESCOPADA à nossa classe, que é a
|
|
1573
|
+
lição que o `table { min-width:720px }` do Lote 4 deixou: regra de elemento no core não tem
|
|
1574
|
+
gate, então escreva-a presa a alguma coisa nossa ou ela é global.
|
|
1575
|
+
E leva `[href]` para GANHAR de `.react-flow__attribution a`, que tem a MESMA especificidade
|
|
1576
|
+
e vem depois na folha do consumidor. Subir por atributo evita citar a classe deles aqui —
|
|
1577
|
+
classe de terceiro no nosso core é o que o check 15 barra, e com razão. */
|
|
1578
|
+
.dependency-graph a[href] { color:var(--muted-foreground); }
|
|
1579
|
+
/* O nó é uma superfície flutuante como qualquer outra da Aurea — mesmo raio de cartão, mesma
|
|
1580
|
+
borda, mesmo fundo. É aqui que ele deixa de parecer React Flow. */
|
|
1581
|
+
.graph-node { position:relative; inline-size:180px; }
|
|
1582
|
+
.graph-node-body { display:grid; gap:var(--space-05); inline-size:100%; padding:var(--space-2) var(--space-3); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); color:var(--foreground); font-family:inherit; font-size:var(--text-sm); text-align:start; }
|
|
1583
|
+
button.graph-node-body { cursor:pointer; }
|
|
1584
|
+
.graph-node[data-selected] .graph-node-body { border-color:var(--primary); }
|
|
1585
|
+
.graph-node-label { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-weight:var(--weight-medium); }
|
|
1586
|
+
/* `kind` é TEXTO, e não cor: a referência pinta dez tipos de nó em dez cores, e é a quarta vez
|
|
1587
|
+
que esta parte recusa a mesma coisa. */
|
|
1588
|
+
.graph-node-kind { color:var(--subtle-foreground); font-size:var(--text-xs); letter-spacing:var(--tracking-wider); text-transform:uppercase; }
|
|
1589
|
+
.graph-handle { inline-size:var(--space-2); block-size:var(--space-2); border:1px solid var(--border); background:var(--surface-2); }
|
|
1590
|
+
.datagrid tbody tr[data-selected] { background:color-mix(in srgb,var(--primary) 14%,transparent); }
|
|
1591
|
+
.datagrid-empty { padding:var(--space-6); color:var(--muted-foreground); text-align:center; }
|
|
1592
|
+
|
|
1593
|
+
/* ========================================================================== */
|
|
1594
|
+
/* 10. RESPONSIVIDADE */
|
|
1595
|
+
/* ========================================================================== */
|
|
1596
|
+
/* Aperto de tela baixa: é densidade do SHELL DOS DOCS (.doc-sidebar), não da .doc-nav em
|
|
1597
|
+
si — sem o escopo ela zerava o gap de qualquer nav, inclusive a do catálogo. */
|
|
1598
|
+
/* Legado do catálogo escrito à mão: `display:block` desmancha o grid e empilha a lateral.
|
|
1599
|
+
Agora vale SÓ para o shell que não tem gaveta — o `apps/docs/index.html`, que traz a
|
|
1600
|
+
própria `.doc-sidebar` e o próprio JS de abrir. O shell do sistema segue em grid de uma
|
|
1601
|
+
coluna com a gaveta acima. Sai junto com aquela página (achado M13). */
|
|
1602
|
+
@media (max-width:640px) { :root { --card-pad:16px; --section-gap:16px; } .doc-actions .select { flex:1; width:auto!important; min-width:0; } .doc-actions>.btn-primary { width:var(--control-h-md); padding:0; font-size:0; } .doc-actions>.btn-primary .mono { display:none; } .tabs,.pagination,.segmented { max-width:100%; overflow-x:auto; } .step:nth-child(3):before { display:none; } .alert { grid-template-columns:auto minmax(0,1fr); } .alert>:last-child { grid-column:2; justify-self:start; } .log-line { grid-template-columns:70px 58px minmax(0,1fr); gap:6px; } .queue-item>.badge { grid-column:2; justify-self:start; } .event-row>.badge { grid-column:3; justify-self:start; } .message { grid-template-columns:1fr; } .media-player { min-height:330px; aspect-ratio:auto; } .media-overlay-title { top:12px; left:12px; right:12px; } .media-controls { padding:10px; } .media-control-row { align-items:flex-start; flex-direction:column; gap:8px; } .media-control-row>.media-control-group { width:100%; justify-content:space-between; } .media-optional,.media-volume { display:none; } .media-time { padding:0 4px; font-size:11px; } .toast-stack { inset-inline:12px; bottom:12px; } .toast { width:100%; min-width:0; grid-template-columns:minmax(0,1fr) auto; } .drawer { width:100%; padding:20px; } .dialog { padding:20px; } }
|
|
1603
|
+
@media (prefers-reduced-motion:reduce) { *,*:before,*:after { scroll-behavior:auto!important; animation-duration:.01ms!important; animation-iteration-count:1!important; transition-duration:.01ms!important; } }
|
|
1604
|
+
|
|
1605
|
+
/* Padrões compostos Aurea 1.7: blocos de operação, não widgets de domínio. */
|
|
1606
|
+
/* Alvo de toque. `.tabs`/`.segmented` no lugar de `.tab`/`.segmented button`: agora a altura
|
|
1607
|
+
mora na cápsula, então é ela que precisa crescer — o filho estica atrás. */
|
|
1608
|
+
@media (pointer:coarse) { .btn:not(.btn-link),.tabs,.segmented,.pagination button,.schedule-grid button,.media-control { min-height:var(--target-min); } .btn-icon,.media-control { min-width:var(--target-min); } }
|
|
1609
|
+
@media (forced-colors:active) {
|
|
1610
|
+
:focus-visible { outline:2px solid CanvasText; outline-offset:2px; box-shadow:none; }
|
|
1611
|
+
.badge,.pattern-gallery button[aria-pressed="true"],.device-grid button[aria-pressed="true"] { border:1px solid CanvasText; }
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
|
|
1615
|
+
/* Aurea v1.7 stabilization patch — visual design unchanged. */
|
|
1616
|
+
.badge-running{background:var(--success-bg);color:var(--success-400);border-color:color-mix(in oklab,var(--success-400) 32%,transparent)}
|
|
1617
|
+
/* superfície (overflow, borda, fundo, raio) mora junto com a do `.table-wrap` lá em cima — aqui
|
|
1618
|
+
fica só o que é DESTA região: ela é focável, e o anel dela é o box-shadow abaixo. */
|
|
1619
|
+
.table-region{outline:none}
|
|
1620
|
+
.table-region:focus-visible{box-shadow:0 0 0 3px color-mix(in oklab,var(--focus) 38%,transparent)}
|
|
1621
|
+
/* CONTAINER QUERY, e não breakpoint de viewport — Parte D, item D3 (08/08/2026).
|
|
1622
|
+
Era `@media (max-width:400px)`, o último dos seis legados do achado M13. Trocar por um degrau
|
|
1623
|
+
da escala (639px) teria resolvido o gate e mantido o defeito: a largura que aperta os
|
|
1624
|
+
controles é a do PLAYER, não a da janela. Um player numa lateral de 400px dentro de uma tela
|
|
1625
|
+
de 1920px tem exatamente o mesmo aperto, e o breakpoint de viewport nunca o via.
|
|
1626
|
+
`.media-player` já era `position:relative` + `overflow:hidden`, então a contenção não muda o
|
|
1627
|
+
posicionamento do que está dentro — medido antes de escrever. */
|
|
1628
|
+
.media-player { container-type:inline-size; }
|
|
1629
|
+
@container (max-width:400px) {
|
|
1630
|
+
.media-controls { flex-wrap:wrap; overflow:visible!important; gap:8px; }
|
|
1631
|
+
.media-control { min-width:var(--target-min); min-height:var(--target-min); }
|
|
1632
|
+
}
|
|
1633
|
+
@media(pointer:coarse){
|
|
1634
|
+
.media-control,.btn-icon{min-width:var(--target-min);min-height:var(--target-min)}
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
/* ========================================================================== */
|
|
1638
|
+
/* 12. RTL */
|
|
1639
|
+
/* ========================================================================== */
|
|
1640
|
+
/* O eixo inline do CSS acima já é lógico e espelha sozinho. Aqui ficam só os
|
|
1641
|
+
casos sem forma lógica: background-position e translateX.
|
|
1642
|
+
Deliberadamente NÃO espelham:
|
|
1643
|
+
- o check do .checkbox e o .spinner são glifos desenhados com borda;
|
|
1644
|
+
- .map-* e .builder-* são geografia/arte com rotate() fixo — espelhar os
|
|
1645
|
+
nós sem as arestas quebraria o desenho;
|
|
1646
|
+
- .drawer-left/.drawer-right prometem lado físico no nome (prop side). */
|
|
1647
|
+
:dir(rtl) .select { background-position:12px 50%; }
|
|
1648
|
+
:dir(rtl) .switch input:checked + .switch-track:after { transform:translateX(-18px); }
|
|
952
1649
|
}
|