@duskmoon-dev/core 1.19.4 → 1.19.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +1 -1
  2. package/dist/components/alert.css +81 -3
  3. package/dist/components/dialog.css +29 -3
  4. package/dist/components/dropdown.css +91 -0
  5. package/dist/components/fab.css +182 -0
  6. package/dist/components/index.css +1119 -232
  7. package/dist/components/loading.css +105 -0
  8. package/dist/components/modal.css +66 -4
  9. package/dist/components/navigation.css +94 -54
  10. package/dist/components/progress.css +74 -0
  11. package/dist/components/radial-progress.css +47 -0
  12. package/dist/components/skeleton.css +13 -1
  13. package/dist/components/snackbar.css +48 -18
  14. package/dist/components/swap.css +116 -0
  15. package/dist/components/toast.css +188 -34
  16. package/dist/components/tooltip.css +2 -47
  17. package/dist/esm/components/alert.js +81 -3
  18. package/dist/esm/components/dialog.js +29 -3
  19. package/dist/esm/components/dropdown.d.ts +5 -0
  20. package/dist/esm/components/dropdown.js +100 -0
  21. package/dist/esm/components/fab.d.ts +5 -0
  22. package/dist/esm/components/fab.js +191 -0
  23. package/dist/esm/components/loading.d.ts +5 -0
  24. package/dist/esm/components/loading.js +114 -0
  25. package/dist/esm/components/modal.js +66 -4
  26. package/dist/esm/components/navigation.js +94 -54
  27. package/dist/esm/components/progress.js +74 -0
  28. package/dist/esm/components/radial-progress.d.ts +5 -0
  29. package/dist/esm/components/radial-progress.js +56 -0
  30. package/dist/esm/components/skeleton.js +13 -1
  31. package/dist/esm/components/snackbar.js +48 -18
  32. package/dist/esm/components/swap.d.ts +5 -0
  33. package/dist/esm/components/swap.js +125 -0
  34. package/dist/esm/components/toast.js +188 -34
  35. package/dist/esm/components/tooltip.js +2 -47
  36. package/dist/index.css +1119 -232
  37. package/dist/index.min.css +1 -1
  38. package/dist/standalone/duskmoonui-themes.css +1 -1
  39. package/dist/standalone/duskmoonui.css +1120 -233
  40. package/dist/standalone/duskmoonui.js +25 -9
  41. package/dist/standalone/duskmoonui.mjs +25 -9
  42. package/package.json +31 -1
@@ -721,6 +721,308 @@
721
721
  }
722
722
 
723
723
 
724
+ /* Action composition components */
725
+ /**
726
+ * FAB / Speed Dial Component Styles
727
+ *
728
+ * FAB owns viewport placement and action layout. Pair its trigger and actions
729
+ * with Button classes for color, interaction, and disabled states.
730
+ */
731
+
732
+ @layer components {
733
+ .fab {
734
+ --fab-offset-block: 1rem;
735
+ --fab-offset-inline: 1rem;
736
+ --fab-gap: 0.75rem;
737
+ --fab-size: 3.5rem;
738
+
739
+ position: fixed;
740
+ inset-block-end: calc(var(--fab-offset-block) + env(safe-area-inset-bottom, 0px));
741
+ inset-inline-end: calc(var(--fab-offset-inline) + env(safe-area-inset-right, 0px));
742
+ z-index: 40;
743
+ display: inline-flex;
744
+ flex-direction: column-reverse;
745
+ align-items: flex-end;
746
+ gap: var(--fab-gap);
747
+ max-inline-size: calc(100dvw - 2 * var(--fab-offset-inline));
748
+ }
749
+
750
+ .fab-start {
751
+ inset-inline-start: calc(var(--fab-offset-inline) + env(safe-area-inset-left, 0px));
752
+ inset-inline-end: auto;
753
+ align-items: flex-start;
754
+ }
755
+
756
+ .fab-contained {
757
+ position: absolute;
758
+ }
759
+
760
+ .fab-speed-dial {
761
+ flex-direction: column-reverse;
762
+ }
763
+
764
+ .fab-trigger {
765
+ min-inline-size: var(--fab-size);
766
+ min-block-size: var(--fab-size);
767
+ padding: 0.875rem;
768
+ border-radius: var(--radius-lg);
769
+ box-shadow: var(--shadow-lg);
770
+ }
771
+
772
+ .fab-trigger:not(.fab-extended) {
773
+ inline-size: var(--fab-size);
774
+ block-size: var(--fab-size);
775
+ }
776
+
777
+ .fab-extended {
778
+ inline-size: auto;
779
+ max-inline-size: 100%;
780
+ min-block-size: var(--fab-size);
781
+ padding-inline: 1.25rem;
782
+ border-radius: var(--radius-lg);
783
+ }
784
+
785
+ .fab-actions {
786
+ align-items: flex-end;
787
+ flex-direction: column-reverse;
788
+ gap: var(--fab-gap);
789
+ max-inline-size: min(22rem, calc(100dvw - 2rem));
790
+ }
791
+
792
+ .fab-start .fab-actions {
793
+ align-items: flex-start;
794
+ }
795
+
796
+ /* Controlled mode: application code owns .fab-open and all ARIA state. */
797
+ .fab-controlled > .fab-actions:not([popover]) {
798
+ display: none;
799
+ }
800
+
801
+ .fab-controlled.fab-open > .fab-actions:not([popover]) {
802
+ display: flex;
803
+ }
804
+
805
+ /* Native mode: the browser's popover state is the sole authority. */
806
+ .fab-actions[popover] {
807
+ display: none;
808
+ position: fixed;
809
+ inset-block-start: auto;
810
+ inset-block-end: calc(
811
+ var(--fab-offset-block, 1rem) + env(safe-area-inset-bottom, 0px) +
812
+ var(--fab-size, 3.5rem) + var(--fab-gap, 0.75rem)
813
+ );
814
+ inset-inline-start: auto;
815
+ inset-inline-end: calc(var(--fab-offset-inline, 1rem) + env(safe-area-inset-right, 0px));
816
+ margin: 0;
817
+ padding: 0;
818
+ border: 0;
819
+ overflow: visible;
820
+ color: inherit;
821
+ background: transparent;
822
+ opacity: 0;
823
+ visibility: hidden;
824
+ pointer-events: none;
825
+ transform: translateY(0.5rem);
826
+ transition:
827
+ opacity 150ms ease-out,
828
+ transform 150ms ease-out,
829
+ overlay 150ms ease-out allow-discrete,
830
+ display 150ms ease-out allow-discrete;
831
+ }
832
+
833
+ .fab-start > .fab-actions[popover] {
834
+ inset-inline-start: calc(var(--fab-offset-inline, 1rem) + env(safe-area-inset-left, 0px));
835
+ inset-inline-end: auto;
836
+ }
837
+
838
+ .fab-actions[popover]:popover-open {
839
+ display: flex;
840
+ opacity: 1;
841
+ visibility: visible;
842
+ pointer-events: auto;
843
+ transform: translateY(0);
844
+ }
845
+
846
+ @starting-style {
847
+ .fab-actions[popover]:popover-open {
848
+ opacity: 0;
849
+ transform: translateY(0.5rem);
850
+ }
851
+ }
852
+
853
+ @supports (position-area: top) {
854
+ .fab-actions[popover] {
855
+ inset: auto;
856
+ margin: var(--fab-gap, 0.75rem);
857
+ position-area: top span-left;
858
+ position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
859
+ }
860
+
861
+ .fab-start > .fab-actions[popover] {
862
+ inset: auto;
863
+ position-area: top span-right;
864
+ }
865
+ }
866
+
867
+ .fab-action {
868
+ display: inline-flex;
869
+ align-items: center;
870
+ justify-content: flex-end;
871
+ gap: 0.5rem;
872
+ max-inline-size: 100%;
873
+ }
874
+
875
+ .fab-start .fab-action {
876
+ flex-direction: row-reverse;
877
+ }
878
+
879
+ .fab-label {
880
+ max-inline-size: min(16rem, calc(100dvw - 6rem));
881
+ padding: 0.375rem 0.625rem;
882
+ overflow-wrap: anywhere;
883
+ color: var(--color-on-surface);
884
+ background-color: var(--color-surface-container-high);
885
+ border: 1px solid var(--color-outline-variant);
886
+ border-radius: var(--radius-sm);
887
+ box-shadow: var(--shadow-sm);
888
+ font-size: 0.8125rem;
889
+ font-weight: 500;
890
+ line-height: 1.125rem;
891
+ }
892
+
893
+ @media (max-width: 30rem) {
894
+ .fab {
895
+ --fab-offset-block: 0.75rem;
896
+ --fab-offset-inline: 0.75rem;
897
+ }
898
+ }
899
+
900
+ @media (prefers-reduced-motion: reduce) {
901
+ .fab-actions[popover] {
902
+ transition: none;
903
+ transform: none;
904
+ }
905
+ }
906
+ }
907
+
908
+ /**
909
+ * Swap Component Styles
910
+ * Displays one of two non-interactive state indicators.
911
+ */
912
+
913
+ @layer components {
914
+ .swap {
915
+ position: relative;
916
+ display: inline-grid;
917
+ place-items: center;
918
+ vertical-align: middle;
919
+ cursor: pointer;
920
+ user-select: none;
921
+ }
922
+
923
+ .swap-input {
924
+ position: absolute;
925
+ inset: 0;
926
+ z-index: 1;
927
+ width: 100%;
928
+ height: 100%;
929
+ margin: 0;
930
+ opacity: 0;
931
+ cursor: pointer;
932
+ }
933
+
934
+ .swap-on,
935
+ .swap-off {
936
+ grid-area: 1 / 1;
937
+ display: inline-flex;
938
+ align-items: center;
939
+ justify-content: center;
940
+ inline-size: max-content;
941
+ max-inline-size: 100%;
942
+ transition: opacity 150ms ease-out, transform 150ms ease-out;
943
+ }
944
+
945
+ .swap-on {
946
+ opacity: 0;
947
+ visibility: hidden;
948
+ pointer-events: none;
949
+ }
950
+
951
+ .swap-off {
952
+ opacity: 1;
953
+ visibility: visible;
954
+ pointer-events: none;
955
+ }
956
+
957
+ .swap-input:checked ~ .swap-on,
958
+ .swap[aria-pressed="true"] > .swap-on {
959
+ opacity: 1;
960
+ visibility: visible;
961
+ }
962
+
963
+ .swap-input:checked ~ .swap-off,
964
+ .swap[aria-pressed="true"] > .swap-off {
965
+ opacity: 0;
966
+ visibility: hidden;
967
+ }
968
+
969
+ .swap:focus-visible,
970
+ .swap:has(.swap-input:focus-visible) {
971
+ outline: none;
972
+ box-shadow: 0 0 0 3px color-mix(in oklch, currentColor 20%, transparent);
973
+ border-radius: var(--radius-sm);
974
+ }
975
+
976
+ .swap:disabled,
977
+ .swap:has(.swap-input:disabled) {
978
+ cursor: not-allowed;
979
+ opacity: 0.5;
980
+ }
981
+
982
+ .swap-input:disabled {
983
+ cursor: not-allowed;
984
+ }
985
+
986
+ .swap-rotate .swap-on {
987
+ transform: rotate(-90deg) scale(0.8);
988
+ }
989
+
990
+ .swap-rotate .swap-off {
991
+ transform: rotate(0deg) scale(1);
992
+ }
993
+
994
+ .swap-rotate .swap-input:checked ~ .swap-on,
995
+ .swap-rotate[aria-pressed="true"] > .swap-on {
996
+ transform: rotate(0deg) scale(1);
997
+ }
998
+
999
+ .swap-rotate .swap-input:checked ~ .swap-off,
1000
+ .swap-rotate[aria-pressed="true"] > .swap-off {
1001
+ transform: rotate(90deg) scale(0.8);
1002
+ }
1003
+
1004
+ /* Presentation-only override. It intentionally wins over semantic state. */
1005
+ .swap.swap-active > .swap-on {
1006
+ opacity: 1;
1007
+ visibility: visible;
1008
+ transform: rotate(0deg) scale(1);
1009
+ }
1010
+
1011
+ .swap.swap-active > .swap-off {
1012
+ opacity: 0;
1013
+ visibility: hidden;
1014
+ transform: rotate(90deg) scale(0.8);
1015
+ }
1016
+
1017
+ @media (prefers-reduced-motion: reduce) {
1018
+ .swap-on,
1019
+ .swap-off {
1020
+ transition: none;
1021
+ }
1022
+ }
1023
+ }
1024
+
1025
+
724
1026
  /* Card Component */
725
1027
  /**
726
1028
  * Card Component Styles
@@ -2825,45 +3127,139 @@
2825
3127
 
2826
3128
 
2827
3129
 
2828
- /* Navigation Component - includes navbar, menu, breadcrumbs, tabs, pagination, dropdown */
3130
+ /* Navigation Component - retains the legacy Dropdown import contract */
2829
3131
  /**
2830
3132
  * Navigation Component Styles
2831
3133
  * DuskMoonUI - Material Design 3 inspired navigation system
2832
3134
  */
2833
3135
 
3136
+ /* Preserve the Navigation entrypoint's published Dropdown coverage. */
3137
+ /**
3138
+ * Dropdown Component Styles
3139
+ * Native Popover disclosure with logical CSS anchor positioning.
3140
+ */
3141
+
2834
3142
  @layer components {
2835
- /* Navbar Base */
2836
- .navbar {
2837
- display: flex;
2838
- align-items: center;
2839
- width: 100%;
2840
- min-height: 4rem;
2841
- padding: 0.5rem 1rem;
2842
- background-color: var(--color-surface);
2843
- color: var(--color-on-surface);
3143
+ .dropdown {
3144
+ position: relative;
3145
+ display: inline-block;
2844
3146
  }
2845
3147
 
2846
- .navbar-primary {
2847
- background-color: var(--color-primary);
2848
- color: var(--color-primary-content);
3148
+ .dropdown > .dropdown-content[popover] {
3149
+ display: none;
3150
+ position: fixed;
3151
+ inset-block-start: auto;
3152
+ inset-block-end: max(0.5rem, env(safe-area-inset-bottom, 0px));
3153
+ inset-inline-start: auto;
3154
+ inset-inline-end: max(
3155
+ 0.5rem,
3156
+ env(safe-area-inset-left, 0px),
3157
+ env(safe-area-inset-right, 0px)
3158
+ );
3159
+ z-index: 50;
3160
+ min-inline-size: 12rem;
3161
+ max-inline-size: min(24rem, calc(100dvw - 1rem));
3162
+ max-block-size: calc(100dvh - 1rem);
3163
+ margin: 0;
3164
+ padding: 0.5rem;
3165
+ overflow: auto;
3166
+ color: var(--color-on-surface);
3167
+ background-color: var(--color-surface);
3168
+ border: 1px solid var(--color-outline);
3169
+ border-radius: var(--radius-sm);
3170
+ box-shadow: var(--shadow-lg);
3171
+ opacity: 0;
3172
+ visibility: hidden;
3173
+ pointer-events: none;
3174
+ transform: translateY(-0.5rem);
3175
+ transition:
3176
+ opacity 150ms ease-out,
3177
+ transform 150ms ease-out,
3178
+ overlay 150ms ease-out allow-discrete,
3179
+ display 150ms ease-out allow-discrete;
2849
3180
  }
2850
3181
 
2851
- .navbar-secondary {
2852
- background-color: var(--color-secondary);
2853
- color: var(--color-secondary-content);
3182
+ .dropdown > .dropdown-content[popover]:popover-open {
3183
+ display: block;
3184
+ opacity: 1;
3185
+ visibility: visible;
3186
+ pointer-events: auto;
3187
+ transform: translateY(0);
2854
3188
  }
2855
3189
 
2856
- .navbar-tertiary {
2857
- background-color: var(--color-tertiary);
2858
- color: var(--color-tertiary-content);
3190
+ @starting-style {
3191
+ .dropdown > .dropdown-content[popover]:popover-open {
3192
+ opacity: 0;
3193
+ transform: translateY(-0.5rem);
3194
+ }
2859
3195
  }
2860
3196
 
2861
- .navbar-accent {
2862
- background-color: var(--color-accent);
2863
- color: var(--color-accent-content);
2864
- }
3197
+ @supports (position-area: block-end) {
3198
+ .dropdown > .dropdown-content[popover] {
3199
+ inset: auto;
3200
+ margin: 0.25rem;
3201
+ position-area: block-end span-inline-end;
3202
+ position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
3203
+ }
2865
3204
 
2866
- .navbar-neutral {
3205
+ .dropdown.dropdown-block-start > .dropdown-content[popover] {
3206
+ position-area: block-start span-inline-end;
3207
+ }
3208
+
3209
+ .dropdown.dropdown-block-end > .dropdown-content[popover] {
3210
+ position-area: block-end span-inline-end;
3211
+ }
3212
+
3213
+ .dropdown.dropdown-inline-start > .dropdown-content[popover] {
3214
+ position-area: inline-start span-block-end;
3215
+ }
3216
+
3217
+ .dropdown.dropdown-inline-end > .dropdown-content[popover] {
3218
+ position-area: inline-end span-block-end;
3219
+ }
3220
+ }
3221
+
3222
+ @media (prefers-reduced-motion: reduce) {
3223
+ .dropdown > .dropdown-content[popover] {
3224
+ transition: none;
3225
+ }
3226
+ }
3227
+ }
3228
+
3229
+
3230
+ @layer components {
3231
+ /* Navbar Base */
3232
+ .navbar {
3233
+ display: flex;
3234
+ align-items: center;
3235
+ width: 100%;
3236
+ min-height: 4rem;
3237
+ padding: 0.5rem 1rem;
3238
+ background-color: var(--color-surface);
3239
+ color: var(--color-on-surface);
3240
+ }
3241
+
3242
+ .navbar-primary {
3243
+ background-color: var(--color-primary);
3244
+ color: var(--color-primary-content);
3245
+ }
3246
+
3247
+ .navbar-secondary {
3248
+ background-color: var(--color-secondary);
3249
+ color: var(--color-secondary-content);
3250
+ }
3251
+
3252
+ .navbar-tertiary {
3253
+ background-color: var(--color-tertiary);
3254
+ color: var(--color-tertiary-content);
3255
+ }
3256
+
3257
+ .navbar-accent {
3258
+ background-color: var(--color-accent);
3259
+ color: var(--color-accent-content);
3260
+ }
3261
+
3262
+ .navbar-neutral {
2867
3263
  background-color: var(--color-neutral);
2868
3264
  color: var(--color-neutral-content);
2869
3265
  }
@@ -3417,60 +3813,6 @@
3417
3813
  font-size: 1rem;
3418
3814
  }
3419
3815
 
3420
- /* Dropdown */
3421
- .dropdown {
3422
- position: relative;
3423
- display: inline-block;
3424
- }
3425
-
3426
- .dropdown-content {
3427
- position: absolute;
3428
- z-index: 50;
3429
- min-width: 12rem;
3430
- padding: 0.5rem;
3431
- background-color: var(--color-surface);
3432
- border: 1px solid var(--color-outline);
3433
- border-radius: var(--radius-sm);
3434
- box-shadow: var(--shadow-lg);
3435
- opacity: 0;
3436
- visibility: hidden;
3437
- transform: translateY(-0.5rem);
3438
- transition: all 150ms ease-in-out;
3439
- }
3440
-
3441
- .dropdown:hover .dropdown-content,
3442
- .dropdown:focus-within .dropdown-content,
3443
- .dropdown.dropdown-open .dropdown-content {
3444
- opacity: 1;
3445
- visibility: visible;
3446
- transform: translateY(0);
3447
- }
3448
-
3449
- /* Dropdown Positions */
3450
- .dropdown-end .dropdown-content {
3451
- right: 0;
3452
- }
3453
-
3454
- .dropdown-top .dropdown-content {
3455
- bottom: 100%;
3456
- top: auto;
3457
- margin-bottom: 0.25rem;
3458
- }
3459
-
3460
- .dropdown-left .dropdown-content {
3461
- right: 100%;
3462
- left: auto;
3463
- top: 0;
3464
- margin-right: 0.25rem;
3465
- }
3466
-
3467
- .dropdown-right .dropdown-content {
3468
- left: 100%;
3469
- right: auto;
3470
- top: 0;
3471
- margin-left: 0.25rem;
3472
- }
3473
-
3474
3816
  /* Pagination */
3475
3817
  .pagination {
3476
3818
  display: flex;
@@ -3714,7 +4056,7 @@
3714
4056
  position: relative;
3715
4057
  z-index: 1;
3716
4058
  max-width: 32rem;
3717
- max-height: calc(100vh - 5rem);
4059
+ max-height: calc(100dvh - 5rem);
3718
4060
  padding: 1.5rem;
3719
4061
  background-color: var(--color-surface);
3720
4062
  color: var(--color-on-surface);
@@ -3746,8 +4088,10 @@
3746
4088
  }
3747
4089
 
3748
4090
  /* Modal Action */
3749
- .modal-action {
4091
+ .modal-action,
4092
+ .modal-footer {
3750
4093
  display: flex;
4094
+ flex-wrap: wrap;
3751
4095
  justify-content: flex-end;
3752
4096
  gap: 0.5rem;
3753
4097
  margin-top: 1.5rem;
@@ -3777,10 +4121,18 @@
3777
4121
  max-width: 20rem;
3778
4122
  }
3779
4123
 
4124
+ .modal-md .modal-box {
4125
+ max-width: 32rem;
4126
+ }
4127
+
3780
4128
  .modal-lg .modal-box {
3781
4129
  max-width: 48rem;
3782
4130
  }
3783
4131
 
4132
+ .modal-xl .modal-box {
4133
+ max-width: 64rem;
4134
+ }
4135
+
3784
4136
  .modal-full .modal-box {
3785
4137
  max-width: calc(100vw - 2rem);
3786
4138
  max-height: calc(100vh - 2rem);
@@ -3803,6 +4155,38 @@
3803
4155
  align-items: center;
3804
4156
  }
3805
4157
 
4158
+ /* Animation Variants */
4159
+ .modal-slide-up .modal-box {
4160
+ transform: translateY(6rem) scale(0.95);
4161
+ }
4162
+
4163
+ .modal-slide-down .modal-box {
4164
+ transform: translateY(-6rem) scale(0.95);
4165
+ }
4166
+
4167
+ .modal-zoom .modal-box {
4168
+ transform: scale(0.75);
4169
+ }
4170
+
4171
+ :is(.modal-slide-up, .modal-slide-down, .modal-zoom).modal-open .modal-box,
4172
+ :is(.modal-slide-up, .modal-slide-down, .modal-zoom):target .modal-box {
4173
+ transform: translateY(0) scale(1);
4174
+ }
4175
+
4176
+ /* Backdrop Variants */
4177
+ .modal-backdrop-light {
4178
+ background-color: color-mix(in srgb, white 80%, transparent);
4179
+ }
4180
+
4181
+ .modal-backdrop-blur {
4182
+ background-color: color-mix(in srgb, var(--color-scrim) 30%, transparent);
4183
+ backdrop-filter: blur(8px);
4184
+ }
4185
+
4186
+ .modal-no-backdrop {
4187
+ background-color: transparent;
4188
+ }
4189
+
3806
4190
  /* Modal Close Button */
3807
4191
  .modal-close {
3808
4192
  position: absolute;
@@ -3851,6 +4235,22 @@
3851
4235
  line-height: 1.5;
3852
4236
  }
3853
4237
 
4238
+ .modal-scrollable .modal-body {
4239
+ max-height: 60vh;
4240
+ overflow-y: auto;
4241
+ }
4242
+
4243
+ .modal-no-padding .modal-body {
4244
+ padding: 0;
4245
+ }
4246
+
4247
+ .modal-centered .modal-body {
4248
+ display: flex;
4249
+ align-items: center;
4250
+ justify-content: center;
4251
+ text-align: center;
4252
+ }
4253
+
3854
4254
  /* Responsive Modal */
3855
4255
  @media (max-width: 640px) {
3856
4256
  .modal-box {
@@ -3865,7 +4265,7 @@
3865
4265
 
3866
4266
  .modal-responsive .modal-box {
3867
4267
  max-width: 100%;
3868
- max-height: 90vh;
4268
+ max-height: 90dvh;
3869
4269
  margin: 0;
3870
4270
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
3871
4271
  }
@@ -3880,7 +4280,7 @@
3880
4280
 
3881
4281
  .drawer-modal .modal-box {
3882
4282
  max-width: 20rem;
3883
- max-height: 100vh;
4283
+ max-height: 100dvh;
3884
4284
  height: 100%;
3885
4285
  margin: 0;
3886
4286
  border-radius: 0;
@@ -3972,6 +4372,10 @@
3972
4372
  white-space: nowrap;
3973
4373
  border: 0;
3974
4374
  }
4375
+
4376
+ body.modal-open {
4377
+ overflow: hidden;
4378
+ }
3975
4379
  }
3976
4380
 
3977
4381
 
@@ -12529,8 +12933,11 @@
12529
12933
  @layer components {
12530
12934
  /* Base Alert */
12531
12935
  .alert {
12532
- display: flex;
12533
- align-items: flex-start;
12936
+ display: grid;
12937
+ grid-template-columns: auto minmax(0, 1fr) auto auto;
12938
+ grid-template-areas:
12939
+ "icon content actions close";
12940
+ align-items: center;
12534
12941
  gap: 0.75rem;
12535
12942
  padding: 1rem;
12536
12943
  border-radius: var(--radius-sm);
@@ -12541,6 +12948,7 @@
12541
12948
 
12542
12949
  /* Alert Icon */
12543
12950
  .alert-icon {
12951
+ grid-area: icon;
12544
12952
  display: flex;
12545
12953
  align-items: center;
12546
12954
  justify-content: center;
@@ -12548,10 +12956,12 @@
12548
12956
  height: 1.5rem;
12549
12957
  font-size: 1.25rem;
12550
12958
  flex-shrink: 0;
12959
+ align-self: start;
12551
12960
  }
12552
12961
 
12553
12962
  /* Alert Content */
12554
12963
  .alert-content {
12964
+ grid-area: content;
12555
12965
  display: flex;
12556
12966
  flex-direction: column;
12557
12967
  gap: 0.25rem;
@@ -12559,13 +12969,42 @@
12559
12969
  min-width: 0;
12560
12970
  }
12561
12971
 
12972
+ .alert-content > p {
12973
+ margin: 0;
12974
+ }
12975
+
12976
+ /* Keep the compact single-message form vertically balanced against global typography margins. */
12977
+ .alert > p {
12978
+ margin: 0;
12979
+ }
12980
+
12981
+ .alert-horizontal { display: grid; }
12982
+ .alert-actions-end { grid-template-areas: "icon content actions close"; }
12983
+ .alert-actions-bottom {
12984
+ grid-template-columns: auto minmax(0, 1fr) auto;
12985
+ grid-template-areas:
12986
+ "icon content close"
12987
+ ". actions .";
12988
+ }
12989
+
12990
+ .alert-actions-bottom .alert-actions {
12991
+ justify-self: start;
12992
+ margin-top: 0.5rem;
12993
+ }
12994
+ .alert-vertical {
12995
+ display: flex;
12996
+ flex-direction: column;
12997
+ }
12998
+
12562
12999
  .alert-title {
13000
+ margin: 0;
12563
13001
  font-size: 0.875rem;
12564
13002
  font-weight: 600;
12565
13003
  line-height: 1.25rem;
12566
13004
  }
12567
13005
 
12568
13006
  .alert-description {
13007
+ margin: 0;
12569
13008
  font-size: 0.875rem;
12570
13009
  line-height: 1.25rem;
12571
13010
  opacity: 0.9;
@@ -12573,6 +13012,7 @@
12573
13012
 
12574
13013
  /* Alert Close Button */
12575
13014
  .alert-close {
13015
+ grid-area: close;
12576
13016
  display: flex;
12577
13017
  align-items: center;
12578
13018
  justify-content: center;
@@ -12786,6 +13226,7 @@
12786
13226
  /* Dismissible */
12787
13227
  .alert-dismissible {
12788
13228
  padding-right: 2.5rem;
13229
+ padding-inline-end: 2.5rem;
12789
13230
  position: relative;
12790
13231
  }
12791
13232
 
@@ -12793,6 +13234,7 @@
12793
13234
  position: absolute;
12794
13235
  top: 0.75rem;
12795
13236
  right: 0.75rem;
13237
+ inset-inline-end: 0.75rem;
12796
13238
  }
12797
13239
 
12798
13240
  /* Compact */
@@ -12812,11 +13254,25 @@
12812
13254
  font-size: 0.8125rem;
12813
13255
  }
12814
13256
 
13257
+ .alert-comfortable {
13258
+ padding: 1.25rem;
13259
+ gap: 1rem;
13260
+ }
13261
+
12815
13262
  /* Alert Actions */
12816
13263
  .alert-actions {
13264
+ grid-area: actions;
12817
13265
  display: flex;
12818
13266
  gap: 0.5rem;
12819
- margin-top: 0.5rem;
13267
+ margin-top: 0;
13268
+ flex-wrap: wrap;
13269
+ align-self: center;
13270
+ justify-self: end;
13271
+ }
13272
+
13273
+ .alert-vertical .alert-actions {
13274
+ align-self: stretch;
13275
+ width: 100%;
12820
13276
  }
12821
13277
 
12822
13278
  .alert-filled .alert-actions .btn-text {
@@ -12840,6 +13296,32 @@
12840
13296
  transition: none;
12841
13297
  }
12842
13298
  }
13299
+
13300
+ @media (max-width: 32rem) {
13301
+ .alert:not(.alert-vertical) .alert-content,
13302
+ .alert-horizontal .alert-content {
13303
+ flex-basis: min(100%, 18rem);
13304
+ }
13305
+ .alert:not(.alert-vertical),
13306
+ .alert-horizontal {
13307
+ grid-template-columns: auto minmax(0, 1fr) auto;
13308
+ grid-template-areas:
13309
+ "icon content close"
13310
+ ". actions actions";
13311
+ }
13312
+ .alert:not(.alert-vertical).alert-actions-end,
13313
+ .alert-horizontal.alert-actions-end {
13314
+ grid-template-columns: auto minmax(0, 1fr) auto;
13315
+ grid-template-areas:
13316
+ "icon content close"
13317
+ ". actions actions";
13318
+ }
13319
+ .alert:not(.alert-vertical) .alert-actions,
13320
+ .alert-horizontal .alert-actions {
13321
+ justify-self: start;
13322
+ margin-top: 0.5rem;
13323
+ }
13324
+ }
12843
13325
  }
12844
13326
 
12845
13327
  /**
@@ -12855,9 +13337,10 @@
12855
13337
  margin: auto;
12856
13338
  padding: 0;
12857
13339
  border: none;
12858
- width: 100%;
13340
+ width: calc(100% - 2rem);
12859
13341
  max-width: 28rem;
12860
- max-height: calc(100vh - 4rem);
13342
+ max-height: calc(100dvh - 2rem);
13343
+ box-sizing: border-box;
12861
13344
  background-color: var(--color-surface);
12862
13345
  color: var(--color-on-surface);
12863
13346
  border-radius: var(--radius-2xl);
@@ -12874,7 +13357,7 @@
12874
13357
  .dialog-box {
12875
13358
  display: flex;
12876
13359
  flex-direction: column;
12877
- max-height: calc(100vh - 4rem);
13360
+ max-height: calc(100dvh - 2rem);
12878
13361
  overflow: hidden;
12879
13362
  }
12880
13363
 
@@ -12933,6 +13416,7 @@
12933
13416
  /* Dialog Footer */
12934
13417
  .dialog-footer {
12935
13418
  display: flex;
13419
+ flex-wrap: wrap;
12936
13420
  justify-content: flex-end;
12937
13421
  gap: 0.5rem;
12938
13422
  padding: 1rem 1.5rem 1.5rem;
@@ -12972,6 +13456,30 @@
12972
13456
  margin: 0;
12973
13457
  }
12974
13458
 
13459
+ @media (max-width: 640px) {
13460
+ dialog.dialog {
13461
+ width: calc(100% - 1rem);
13462
+ max-height: calc(100dvh - 1rem);
13463
+ border-radius: var(--radius-lg);
13464
+ }
13465
+
13466
+ .dialog-box {
13467
+ max-height: calc(100dvh - 1rem);
13468
+ }
13469
+
13470
+ .dialog-header {
13471
+ padding: 1rem 1rem 0;
13472
+ }
13473
+
13474
+ .dialog-body {
13475
+ padding: 1rem;
13476
+ }
13477
+
13478
+ .dialog-footer {
13479
+ padding: 0.75rem 1rem 1rem;
13480
+ }
13481
+ }
13482
+
12975
13483
  dialog.dialog.dialog-fullscreen .dialog-box {
12976
13484
  max-height: 100%;
12977
13485
  }
@@ -13017,79 +13525,230 @@
13017
13525
  }
13018
13526
 
13019
13527
  /**
13020
- * Progress Component Styles
13021
- * DuskMoonUI - Material Design 3 inspired progress system
13528
+ * Loading Component Styles
13529
+ * CSS-only activity indicators. State, aria-busy, and disabling remain consumer-owned.
13022
13530
  */
13023
13531
 
13024
13532
  @layer components {
13025
- /* Base Progress (Linear) */
13026
- .progress {
13027
- position: relative;
13028
- width: 100%;
13029
- height: 0.5rem;
13030
- background-color: var(--color-surface-container-highest);
13031
- border-radius: var(--radius-full);
13032
- overflow: hidden;
13533
+ .loading {
13534
+ --loading-size: 1.25rem;
13535
+ display: inline-flex;
13536
+ width: var(--loading-size);
13537
+ height: var(--loading-size);
13538
+ flex: 0 0 var(--loading-size);
13539
+ color: currentColor;
13540
+ vertical-align: middle;
13033
13541
  }
13034
13542
 
13035
- /* Progress Bar */
13036
- .progress-bar {
13037
- position: absolute;
13038
- top: 0;
13039
- left: 0;
13040
- height: 100%;
13041
- background-color: var(--color-primary);
13543
+ .loading-spinner {
13544
+ border: max(2px, calc(var(--loading-size) / 8)) solid color-mix(in oklch, currentColor 25%, transparent);
13545
+ border-top-color: currentColor;
13042
13546
  border-radius: var(--radius-full);
13043
- transition: width 300ms ease-in-out;
13547
+ animation: loading-spin 800ms linear infinite;
13044
13548
  }
13045
13549
 
13046
- /* Color Variants */
13047
- .progress-primary .progress-bar {
13048
- background-color: var(--color-primary);
13550
+ .loading-dots,
13551
+ .loading-bars {
13552
+ align-items: center;
13553
+ justify-content: center;
13554
+ gap: max(2px, calc(var(--loading-size) / 8));
13049
13555
  }
13050
13556
 
13051
- .progress-secondary .progress-bar {
13052
- background-color: var(--color-secondary);
13557
+ .loading-dots::before,
13558
+ .loading-dots::after,
13559
+ .loading-bars::before,
13560
+ .loading-bars::after {
13561
+ content: "";
13562
+ display: block;
13563
+ background: currentColor;
13053
13564
  }
13054
13565
 
13055
- .progress-tertiary .progress-bar {
13056
- background-color: var(--color-tertiary);
13566
+ .loading-dots::before,
13567
+ .loading-dots::after {
13568
+ width: 25%;
13569
+ height: 25%;
13570
+ border-radius: var(--radius-full);
13571
+ box-shadow: calc(var(--loading-size) / 3) 0 currentColor;
13572
+ animation: loading-dots 900ms ease-in-out infinite;
13057
13573
  }
13058
13574
 
13059
- .progress-info .progress-bar {
13060
- background-color: var(--color-info);
13575
+ .loading-dots::after {
13576
+ display: none;
13061
13577
  }
13062
13578
 
13063
- .progress-success .progress-bar {
13064
- background-color: var(--color-success);
13579
+ .loading-bars {
13580
+ padding-inline: 10%;
13065
13581
  }
13066
13582
 
13067
- .progress-warning .progress-bar {
13068
- background-color: var(--color-warning);
13583
+ .loading-bars::before,
13584
+ .loading-bars::after {
13585
+ width: 18%;
13586
+ height: 65%;
13587
+ border-radius: var(--radius-xs);
13588
+ box-shadow: calc(var(--loading-size) / 3) 0 currentColor, calc(var(--loading-size) * 2 / 3) 0 currentColor;
13589
+ animation: loading-bars 900ms ease-in-out infinite;
13069
13590
  }
13070
13591
 
13071
- .progress-error .progress-bar {
13072
- background-color: var(--color-error);
13592
+ .loading-bars::after {
13593
+ display: none;
13073
13594
  }
13074
13595
 
13075
- .progress-accent .progress-bar {
13076
- background-color: var(--color-accent);
13077
- }
13596
+ .loading-xs { --loading-size: 0.75rem; }
13597
+ .loading-sm { --loading-size: 1rem; }
13598
+ .loading-md { --loading-size: 1.25rem; }
13599
+ .loading-lg { --loading-size: 1.75rem; }
13600
+ .loading-xl { --loading-size: 2.5rem; }
13078
13601
 
13079
- .progress-neutral .progress-bar {
13080
- background-color: var(--color-neutral);
13602
+ .loading-primary { color: var(--color-primary); }
13603
+ .loading-secondary { color: var(--color-secondary); }
13604
+ .loading-tertiary { color: var(--color-tertiary); }
13605
+ .loading-info { color: var(--color-info); }
13606
+ .loading-success { color: var(--color-success); }
13607
+ .loading-warning { color: var(--color-warning); }
13608
+ .loading-error { color: var(--color-error); }
13609
+
13610
+ @keyframes loading-spin {
13611
+ to { transform: rotate(360deg); }
13081
13612
  }
13082
13613
 
13083
- .progress-base .progress-bar {
13084
- background-color: var(--color-base-content);
13614
+ @keyframes loading-dots {
13615
+ 0%, 100% { opacity: 0.35; transform: scale(0.75); }
13616
+ 50% { opacity: 1; transform: scale(1); }
13085
13617
  }
13086
13618
 
13087
- /* Size Variants */
13088
- .progress-xs {
13089
- height: 0.25rem;
13619
+ @keyframes loading-bars {
13620
+ 0%, 100% { opacity: 0.35; transform: scaleY(0.65); }
13621
+ 50% { opacity: 1; transform: scaleY(1); }
13090
13622
  }
13091
13623
 
13092
- .progress-sm {
13624
+ @media (prefers-reduced-motion: reduce) {
13625
+ .loading-spinner,
13626
+ .loading-dots::before,
13627
+ .loading-bars::before {
13628
+ animation: none;
13629
+ }
13630
+ }
13631
+ }
13632
+
13633
+ /**
13634
+ * Progress Component Styles
13635
+ * DuskMoonUI - Material Design 3 inspired progress system
13636
+ */
13637
+
13638
+ @layer components {
13639
+ /* Base Progress (Linear) */
13640
+ .progress {
13641
+ position: relative;
13642
+ width: 100%;
13643
+ height: 0.5rem;
13644
+ background-color: var(--color-surface-container-highest);
13645
+ border-radius: var(--radius-full);
13646
+ overflow: hidden;
13647
+ }
13648
+
13649
+ /* Native progress keeps the platform's accessible value/max contract. */
13650
+ progress.progress {
13651
+ appearance: none;
13652
+ border: 0;
13653
+ display: block;
13654
+ }
13655
+
13656
+ progress.progress::-webkit-progress-bar {
13657
+ background: var(--color-surface-container-highest);
13658
+ border-radius: var(--radius-full);
13659
+ }
13660
+
13661
+ progress.progress::-webkit-progress-value {
13662
+ background: var(--color-primary);
13663
+ border-radius: var(--radius-full);
13664
+ transition: width 300ms ease-in-out;
13665
+ }
13666
+
13667
+ progress.progress::-moz-progress-bar {
13668
+ background: var(--color-primary);
13669
+ border-radius: var(--radius-full);
13670
+ transition: width 300ms ease-in-out;
13671
+ }
13672
+
13673
+ progress.progress:indeterminate::-webkit-progress-value,
13674
+ progress.progress:indeterminate::-moz-progress-bar {
13675
+ width: 30%;
13676
+ animation: progress-indeterminate 1.5s infinite ease-in-out;
13677
+ }
13678
+
13679
+ /* Progress Bar */
13680
+ .progress-bar {
13681
+ position: absolute;
13682
+ top: 0;
13683
+ left: 0;
13684
+ height: 100%;
13685
+ background-color: var(--color-primary);
13686
+ border-radius: var(--radius-full);
13687
+ transition: width 300ms ease-in-out;
13688
+ }
13689
+
13690
+ /* Color Variants */
13691
+ .progress-primary .progress-bar {
13692
+ background-color: var(--color-primary);
13693
+ }
13694
+
13695
+ .progress-secondary .progress-bar {
13696
+ background-color: var(--color-secondary);
13697
+ }
13698
+
13699
+ .progress-tertiary .progress-bar {
13700
+ background-color: var(--color-tertiary);
13701
+ }
13702
+
13703
+ .progress-info .progress-bar {
13704
+ background-color: var(--color-info);
13705
+ }
13706
+
13707
+ .progress-success .progress-bar {
13708
+ background-color: var(--color-success);
13709
+ }
13710
+
13711
+ .progress-warning .progress-bar {
13712
+ background-color: var(--color-warning);
13713
+ }
13714
+
13715
+ .progress-error .progress-bar {
13716
+ background-color: var(--color-error);
13717
+ }
13718
+
13719
+ .progress-accent .progress-bar {
13720
+ background-color: var(--color-accent);
13721
+ }
13722
+
13723
+ .progress-neutral .progress-bar {
13724
+ background-color: var(--color-neutral);
13725
+ }
13726
+
13727
+ .progress-base .progress-bar {
13728
+ background-color: var(--color-base-content);
13729
+ }
13730
+
13731
+ progress.progress-primary::-webkit-progress-value,
13732
+ progress.progress-primary::-moz-progress-bar { background: var(--color-primary); }
13733
+ progress.progress-secondary::-webkit-progress-value,
13734
+ progress.progress-secondary::-moz-progress-bar { background: var(--color-secondary); }
13735
+ progress.progress-tertiary::-webkit-progress-value,
13736
+ progress.progress-tertiary::-moz-progress-bar { background: var(--color-tertiary); }
13737
+ progress.progress-info::-webkit-progress-value,
13738
+ progress.progress-info::-moz-progress-bar { background: var(--color-info); }
13739
+ progress.progress-success::-webkit-progress-value,
13740
+ progress.progress-success::-moz-progress-bar { background: var(--color-success); }
13741
+ progress.progress-warning::-webkit-progress-value,
13742
+ progress.progress-warning::-moz-progress-bar { background: var(--color-warning); }
13743
+ progress.progress-error::-webkit-progress-value,
13744
+ progress.progress-error::-moz-progress-bar { background: var(--color-error); }
13745
+
13746
+ /* Size Variants */
13747
+ .progress-xs {
13748
+ height: 0.25rem;
13749
+ }
13750
+
13751
+ .progress-sm {
13093
13752
  height: 0.375rem;
13094
13753
  }
13095
13754
 
@@ -13159,6 +13818,25 @@
13159
13818
  }
13160
13819
  }
13161
13820
 
13821
+ /* Buffer tracks belong to custom markup, not native <progress>. */
13822
+ .progress-buffer {
13823
+ position: relative;
13824
+ }
13825
+
13826
+ .progress-buffer-bar {
13827
+ position: absolute;
13828
+ inset-block: 0;
13829
+ inset-inline-start: 0;
13830
+ width: 0;
13831
+ background: color-mix(in oklch, var(--color-primary) 30%, transparent);
13832
+ border-radius: var(--radius-full);
13833
+ transition: width 300ms ease-in-out;
13834
+ }
13835
+
13836
+ .progress-buffer .progress-bar {
13837
+ z-index: 1;
13838
+ }
13839
+
13162
13840
  /* Circular Progress */
13163
13841
  .progress-circular {
13164
13842
  position: relative;
@@ -13258,7 +13936,17 @@
13258
13936
 
13259
13937
  /* Reduce Motion */
13260
13938
  @media (prefers-reduced-motion: reduce) {
13939
+ .progress-bar,
13940
+ progress.progress::-webkit-progress-value,
13941
+ progress.progress::-moz-progress-bar,
13942
+ .progress-circular-bar,
13943
+ .progress-buffer-bar {
13944
+ transition: none;
13945
+ }
13946
+
13261
13947
  .progress-indeterminate .progress-bar,
13948
+ progress.progress:indeterminate::-webkit-progress-value,
13949
+ progress.progress:indeterminate::-moz-progress-bar,
13262
13950
  .progress-striped.progress-animated .progress-bar,
13263
13951
  .progress-circular-indeterminate svg,
13264
13952
  .progress-circular-indeterminate .progress-circular-bar {
@@ -13267,6 +13955,54 @@
13267
13955
  }
13268
13956
  }
13269
13957
 
13958
+ /**
13959
+ * Radial Progress Component Styles
13960
+ * Determinate percentage progress without circumference arithmetic.
13961
+ */
13962
+
13963
+ @layer components {
13964
+ .radial-progress {
13965
+ --radial-progress-value: 0;
13966
+ --radial-progress-size: 3rem;
13967
+ --radial-progress-thickness: 0.375rem;
13968
+ --radial-progress-track: var(--color-surface-container-highest);
13969
+ position: relative;
13970
+ display: inline-grid;
13971
+ width: var(--radial-progress-size);
13972
+ height: var(--radial-progress-size);
13973
+ place-items: center;
13974
+ color: var(--color-primary);
13975
+ border-radius: var(--radius-full);
13976
+ background: conic-gradient(currentColor calc(clamp(0, var(--radial-progress-value), 100) * 1%), var(--radial-progress-track) 0);
13977
+ isolation: isolate;
13978
+ }
13979
+
13980
+ .radial-progress::before {
13981
+ content: "";
13982
+ position: absolute;
13983
+ inset: var(--radial-progress-thickness);
13984
+ z-index: 0;
13985
+ border-radius: inherit;
13986
+ background: var(--color-surface);
13987
+ }
13988
+
13989
+ .radial-progress-primary { color: var(--color-primary); }
13990
+ .radial-progress-secondary { color: var(--color-secondary); }
13991
+ .radial-progress-tertiary { color: var(--color-tertiary); }
13992
+ .radial-progress-info { color: var(--color-info); }
13993
+ .radial-progress-success { color: var(--color-success); }
13994
+ .radial-progress-warning { color: var(--color-warning); }
13995
+ .radial-progress-error { color: var(--color-error); }
13996
+
13997
+ .radial-progress-sm { --radial-progress-size: 2rem; --radial-progress-thickness: 0.25rem; }
13998
+ .radial-progress-lg { --radial-progress-size: 4rem; --radial-progress-thickness: 0.5rem; }
13999
+ .radial-progress-xl { --radial-progress-size: 6rem; --radial-progress-thickness: 0.625rem; }
14000
+
14001
+ @media (prefers-reduced-motion: reduce) {
14002
+ .radial-progress { transition: none; }
14003
+ }
14004
+ }
14005
+
13270
14006
  /**
13271
14007
  * Skeleton Component Styles
13272
14008
  * DuskMoonUI - Material Design 3 inspired skeleton loading system
@@ -13300,6 +14036,10 @@
13300
14036
  border-radius: var(--radius-sm);
13301
14037
  }
13302
14038
 
14039
+ .skeleton-static {
14040
+ animation: none;
14041
+ }
14042
+
13303
14043
  /* Size Variants */
13304
14044
  .skeleton-xs {
13305
14045
  height: 0.5rem;
@@ -13402,7 +14142,7 @@
13402
14142
  background: linear-gradient(
13403
14143
  90deg,
13404
14144
  transparent,
13405
- rgba(255, 255, 255, 0.3),
14145
+ color-mix(in oklch, var(--color-surface-bright) 35%, transparent),
13406
14146
  transparent
13407
14147
  );
13408
14148
  animation: skeleton-wave 1.5s infinite;
@@ -13480,6 +14220,14 @@
13480
14220
 
13481
14221
  .skeleton-wave::after {
13482
14222
  animation: none;
14223
+ transform: translateX(0);
14224
+ opacity: 0.35;
14225
+ }
14226
+
14227
+ .skeleton-static::after {
14228
+ animation: none;
14229
+ transform: translateX(0);
14230
+ opacity: 0.35;
13483
14231
  }
13484
14232
  }
13485
14233
  }
@@ -13696,49 +14444,49 @@
13696
14444
 
13697
14445
  /* Color Variants */
13698
14446
  .snackbar-info {
13699
- background-color: var(--color-info-container);
13700
- color: var(--color-on-info-container);
14447
+ background-color: var(--color-info);
14448
+ color: var(--color-info-content);
13701
14449
  }
13702
14450
 
13703
14451
  .snackbar-success {
13704
- background-color: var(--color-success-container);
13705
- color: var(--color-on-success-container);
14452
+ background-color: var(--color-success);
14453
+ color: var(--color-success-content);
13706
14454
  }
13707
14455
 
13708
14456
  .snackbar-warning {
13709
- background-color: var(--color-warning-container);
13710
- color: var(--color-on-warning-container);
14457
+ background-color: var(--color-warning);
14458
+ color: var(--color-warning-content);
13711
14459
  }
13712
14460
 
13713
14461
  .snackbar-error {
13714
- background-color: var(--color-error-container);
13715
- color: var(--color-on-error-container);
14462
+ background-color: var(--color-error);
14463
+ color: var(--color-error-content);
13716
14464
  }
13717
14465
 
13718
14466
  /* Brand Color Variants */
13719
14467
  .snackbar-primary {
13720
- background-color: var(--color-primary-container);
13721
- color: var(--color-on-primary-container);
14468
+ background-color: var(--color-primary);
14469
+ color: var(--color-primary-content);
13722
14470
  }
13723
14471
 
13724
14472
  .snackbar-secondary {
13725
- background-color: var(--color-secondary-container);
13726
- color: var(--color-on-secondary-container);
14473
+ background-color: var(--color-secondary);
14474
+ color: var(--color-secondary-content);
13727
14475
  }
13728
14476
 
13729
14477
  .snackbar-tertiary {
13730
- background-color: var(--color-tertiary-container);
13731
- color: var(--color-on-tertiary-container);
14478
+ background-color: var(--color-tertiary);
14479
+ color: var(--color-tertiary-content);
13732
14480
  }
13733
14481
 
13734
14482
  .snackbar-accent {
13735
- background-color: color-mix(in oklch, var(--color-accent) 15%, var(--color-surface));
13736
- color: var(--color-on-surface);
14483
+ background-color: var(--color-accent);
14484
+ color: var(--color-accent-content);
13737
14485
  }
13738
14486
 
13739
14487
  .snackbar-neutral {
13740
- background-color: color-mix(in oklch, var(--color-neutral) 15%, var(--color-surface));
13741
- color: var(--color-on-surface);
14488
+ background-color: var(--color-neutral);
14489
+ color: var(--color-neutral-content);
13742
14490
  }
13743
14491
 
13744
14492
  .snackbar-base {
@@ -13746,6 +14494,36 @@
13746
14494
  color: var(--color-base-content);
13747
14495
  }
13748
14496
 
14497
+ :is(
14498
+ .snackbar-info,
14499
+ .snackbar-success,
14500
+ .snackbar-warning,
14501
+ .snackbar-error,
14502
+ .snackbar-primary,
14503
+ .snackbar-secondary,
14504
+ .snackbar-tertiary,
14505
+ .snackbar-accent,
14506
+ .snackbar-neutral,
14507
+ .snackbar-base
14508
+ ) :is(.snackbar-action, .snackbar-close) {
14509
+ color: inherit;
14510
+ }
14511
+
14512
+ :is(
14513
+ .snackbar-info,
14514
+ .snackbar-success,
14515
+ .snackbar-warning,
14516
+ .snackbar-error,
14517
+ .snackbar-primary,
14518
+ .snackbar-secondary,
14519
+ .snackbar-tertiary,
14520
+ .snackbar-accent,
14521
+ .snackbar-neutral,
14522
+ .snackbar-base
14523
+ ) :is(.snackbar-action, .snackbar-close):hover {
14524
+ background-color: color-mix(in oklch, currentColor 12%, transparent);
14525
+ }
14526
+
13749
14527
  /* Dark Snackbar (default MD3 style) */
13750
14528
  .snackbar-dark {
13751
14529
  background-color: var(--color-on-surface);
@@ -13828,17 +14606,36 @@
13828
14606
  pointer-events: none;
13829
14607
  }
13830
14608
 
14609
+ /* Native command targets use the container as a manual popover. Reset the
14610
+ user-agent popover box while preserving the existing positioning API. */
14611
+ :where(.toast-container[popover]) {
14612
+ inset: auto;
14613
+ width: auto;
14614
+ height: auto;
14615
+ margin: 0;
14616
+ overflow: visible;
14617
+ color: inherit;
14618
+ background: transparent;
14619
+ border: 0;
14620
+ }
14621
+
14622
+ .toast-container[popover]:not(:popover-open) {
14623
+ display: none;
14624
+ }
14625
+
13831
14626
  /* Position Variants */
13832
14627
  .toast-container-top-right {
13833
14628
  top: 0;
13834
14629
  right: 0;
13835
14630
  align-items: flex-end;
14631
+ padding-top: max(1rem, env(safe-area-inset-top));
13836
14632
  }
13837
14633
 
13838
14634
  .toast-container-top-left {
13839
14635
  top: 0;
13840
14636
  left: 0;
13841
14637
  align-items: flex-start;
14638
+ padding-top: max(1rem, env(safe-area-inset-top));
13842
14639
  }
13843
14640
 
13844
14641
  .toast-container-top-center {
@@ -13846,18 +14643,21 @@
13846
14643
  left: 50%;
13847
14644
  transform: translateX(-50%);
13848
14645
  align-items: center;
14646
+ padding-top: max(1rem, env(safe-area-inset-top));
13849
14647
  }
13850
14648
 
13851
14649
  .toast-container-bottom-right {
13852
14650
  bottom: 0;
13853
14651
  right: 0;
13854
14652
  align-items: flex-end;
14653
+ padding-bottom: max(1rem, env(safe-area-inset-bottom));
13855
14654
  }
13856
14655
 
13857
14656
  .toast-container-bottom-left {
13858
14657
  bottom: 0;
13859
14658
  left: 0;
13860
14659
  align-items: flex-start;
14660
+ padding-bottom: max(1rem, env(safe-area-inset-bottom));
13861
14661
  }
13862
14662
 
13863
14663
  .toast-container-bottom-center {
@@ -13865,10 +14665,20 @@
13865
14665
  left: 50%;
13866
14666
  transform: translateX(-50%);
13867
14667
  align-items: center;
14668
+ padding-bottom: max(1rem, env(safe-area-inset-bottom));
13868
14669
  }
13869
14670
 
14671
+ /* Logical aliases add RTL-aware placement without changing left/right. */
14672
+ .toast-container-top-start { top: 0; inset-inline-start: 0; align-items: flex-start; }
14673
+ .toast-container-top-end { top: 0; inset-inline-end: 0; align-items: flex-end; }
14674
+ .toast-container-bottom-start { bottom: 0; inset-inline-start: 0; align-items: flex-start; }
14675
+ .toast-container-bottom-end { bottom: 0; inset-inline-end: 0; align-items: flex-end; }
14676
+
13870
14677
  /* Base Toast */
13871
14678
  .toast {
14679
+ --_toast-accent-color: var(--color-primary);
14680
+
14681
+ position: relative;
13872
14682
  display: flex;
13873
14683
  align-items: flex-start;
13874
14684
  gap: 0.75rem;
@@ -13899,9 +14709,28 @@
13899
14709
  /* Toast Open State */
13900
14710
  .toast.toast-open,
13901
14711
  .toast.show,
13902
- .toast-show {
14712
+ .toast.toast-show {
14713
+ opacity: 1;
14714
+ transform: translateX(0) translateY(0);
14715
+ visibility: visible;
14716
+ pointer-events: auto;
14717
+ }
14718
+
14719
+ /* A closed item cannot intercept input. Consumers should also use hidden,
14720
+ inert, or unmounting when removing it from the accessibility tree. */
14721
+ .toast:not(.toast-open):not(.show):not(.toast-show),
14722
+ .toast[hidden],
14723
+ .toast[inert],
14724
+ .toast[aria-hidden="true"] {
14725
+ pointer-events: none;
14726
+ visibility: hidden;
14727
+ }
14728
+
14729
+ .toast-container[popover]:popover-open .toast {
13903
14730
  opacity: 1;
13904
14731
  transform: translateX(0) translateY(0);
14732
+ visibility: visible;
14733
+ pointer-events: auto;
13905
14734
  }
13906
14735
 
13907
14736
  /* Toast Icon */
@@ -13952,7 +14781,7 @@
13952
14781
  cursor: pointer;
13953
14782
  transition: background-color 150ms ease-in-out, color 150ms ease-in-out;
13954
14783
  flex-shrink: 0;
13955
- margin-left: auto;
14784
+ margin-inline-start: auto;
13956
14785
  }
13957
14786
 
13958
14787
  .toast-close:hover {
@@ -13970,10 +14799,46 @@
13970
14799
  display: flex;
13971
14800
  gap: 0.5rem;
13972
14801
  margin-top: 0.5rem;
14802
+ flex-wrap: wrap;
14803
+ }
14804
+
14805
+ .toast-action {
14806
+ display: inline-flex;
14807
+ align-items: center;
14808
+ justify-content: center;
14809
+ width: fit-content;
14810
+ min-height: 2rem;
14811
+ padding: 0.375rem 0.75rem;
14812
+ color: var(--color-primary);
14813
+ font-size: 0.875rem;
14814
+ font-weight: 500;
14815
+ background-color: transparent;
14816
+ border: 1px solid currentColor;
14817
+ border-radius: var(--radius-sm);
14818
+ cursor: pointer;
14819
+ }
14820
+
14821
+ .toast-action:hover {
14822
+ background-color: color-mix(in oklch, currentColor 10%, transparent);
14823
+ }
14824
+
14825
+ .toast-action:focus-visible {
14826
+ outline: none;
14827
+ box-shadow: 0 0 0 3px color-mix(in oklch, currentColor 20%, transparent);
13973
14828
  }
13974
14829
 
13975
14830
  /* Type Variants */
14831
+ .toast-accent {
14832
+ --_toast-accent-color: var(--color-accent);
14833
+ border-color: var(--color-accent);
14834
+ }
14835
+
14836
+ .toast-accent .toast-icon {
14837
+ color: var(--color-accent);
14838
+ }
14839
+
13976
14840
  .toast-info {
14841
+ --_toast-accent-color: var(--color-info);
13977
14842
  border-color: var(--color-info);
13978
14843
  }
13979
14844
 
@@ -13982,6 +14847,7 @@
13982
14847
  }
13983
14848
 
13984
14849
  .toast-success {
14850
+ --_toast-accent-color: var(--color-success);
13985
14851
  border-color: var(--color-success);
13986
14852
  }
13987
14853
 
@@ -13990,6 +14856,7 @@
13990
14856
  }
13991
14857
 
13992
14858
  .toast-warning {
14859
+ --_toast-accent-color: var(--color-warning);
13993
14860
  border-color: var(--color-warning);
13994
14861
  }
13995
14862
 
@@ -13998,6 +14865,7 @@
13998
14865
  }
13999
14866
 
14000
14867
  .toast-error {
14868
+ --_toast-accent-color: var(--color-error);
14001
14869
  border-color: var(--color-error);
14002
14870
  }
14003
14871
 
@@ -14006,6 +14874,7 @@
14006
14874
  }
14007
14875
 
14008
14876
  .toast-primary {
14877
+ --_toast-accent-color: var(--color-primary);
14009
14878
  border-color: var(--color-primary);
14010
14879
  }
14011
14880
 
@@ -14014,6 +14883,7 @@
14014
14883
  }
14015
14884
 
14016
14885
  .toast-secondary {
14886
+ --_toast-accent-color: var(--color-secondary);
14017
14887
  border-color: var(--color-secondary);
14018
14888
  }
14019
14889
 
@@ -14022,6 +14892,7 @@
14022
14892
  }
14023
14893
 
14024
14894
  .toast-tertiary {
14895
+ --_toast-accent-color: var(--color-tertiary);
14025
14896
  border-color: var(--color-tertiary);
14026
14897
  }
14027
14898
 
@@ -14029,15 +14900,8 @@
14029
14900
  color: var(--color-tertiary);
14030
14901
  }
14031
14902
 
14032
- .toast-accent {
14033
- border-color: var(--color-accent);
14034
- }
14035
-
14036
- .toast-accent .toast-icon {
14037
- color: var(--color-accent);
14038
- }
14039
-
14040
14903
  .toast-neutral {
14904
+ --_toast-accent-color: var(--color-neutral);
14041
14905
  border-color: var(--color-neutral);
14042
14906
  }
14043
14907
 
@@ -14046,6 +14910,7 @@
14046
14910
  }
14047
14911
 
14048
14912
  .toast-base {
14913
+ --_toast-accent-color: var(--color-base-content);
14049
14914
  border-color: var(--color-base-content);
14050
14915
  }
14051
14916
 
@@ -14054,58 +14919,58 @@
14054
14919
  }
14055
14920
 
14056
14921
  /* Filled Variants */
14922
+ .toast-filled.toast-accent {
14923
+ background-color: var(--color-accent);
14924
+ border-color: transparent;
14925
+ color: var(--color-accent-content);
14926
+ }
14927
+
14057
14928
  .toast-filled.toast-info {
14058
- background-color: var(--color-info-container);
14929
+ background-color: var(--color-info);
14059
14930
  border-color: transparent;
14060
- color: var(--color-on-info-container);
14931
+ color: var(--color-info-content);
14061
14932
  }
14062
14933
 
14063
14934
  .toast-filled.toast-success {
14064
- background-color: var(--color-success-container);
14935
+ background-color: var(--color-success);
14065
14936
  border-color: transparent;
14066
- color: var(--color-on-success-container);
14937
+ color: var(--color-success-content);
14067
14938
  }
14068
14939
 
14069
14940
  .toast-filled.toast-warning {
14070
- background-color: var(--color-warning-container);
14941
+ background-color: var(--color-warning);
14071
14942
  border-color: transparent;
14072
- color: var(--color-on-warning-container);
14943
+ color: var(--color-warning-content);
14073
14944
  }
14074
14945
 
14075
14946
  .toast-filled.toast-error {
14076
- background-color: var(--color-error-container);
14947
+ background-color: var(--color-error);
14077
14948
  border-color: transparent;
14078
- color: var(--color-on-error-container);
14949
+ color: var(--color-error-content);
14079
14950
  }
14080
14951
 
14081
14952
  .toast-filled.toast-primary {
14082
- background-color: var(--color-primary-container);
14953
+ background-color: var(--color-primary);
14083
14954
  border-color: transparent;
14084
- color: var(--color-on-primary-container);
14955
+ color: var(--color-primary-content);
14085
14956
  }
14086
14957
 
14087
14958
  .toast-filled.toast-secondary {
14088
- background-color: var(--color-secondary-container);
14959
+ background-color: var(--color-secondary);
14089
14960
  border-color: transparent;
14090
- color: var(--color-on-secondary-container);
14961
+ color: var(--color-secondary-content);
14091
14962
  }
14092
14963
 
14093
14964
  .toast-filled.toast-tertiary {
14094
- background-color: var(--color-tertiary-container);
14095
- border-color: transparent;
14096
- color: var(--color-on-tertiary-container);
14097
- }
14098
-
14099
- .toast-filled.toast-accent {
14100
- background-color: color-mix(in oklch, var(--color-accent) 15%, var(--color-surface));
14965
+ background-color: var(--color-tertiary);
14101
14966
  border-color: transparent;
14102
- color: var(--color-on-surface);
14967
+ color: var(--color-tertiary-content);
14103
14968
  }
14104
14969
 
14105
14970
  .toast-filled.toast-neutral {
14106
- background-color: color-mix(in oklch, var(--color-neutral) 15%, var(--color-surface));
14971
+ background-color: var(--color-neutral);
14107
14972
  border-color: transparent;
14108
- color: var(--color-on-surface);
14973
+ color: var(--color-neutral-content);
14109
14974
  }
14110
14975
 
14111
14976
  .toast-filled.toast-base {
@@ -14118,8 +14983,16 @@
14118
14983
  .toast-title and .toast-message have explicit color rules that would otherwise
14119
14984
  override the filled variant's inherited on-container color. */
14120
14985
  .toast-filled .toast-title,
14121
- .toast-filled .toast-message {
14986
+ .toast-filled .toast-message,
14987
+ .toast-filled .toast-icon,
14988
+ .toast-filled .toast-close,
14989
+ .toast-filled .toast-action {
14990
+ color: inherit;
14991
+ }
14992
+
14993
+ .toast-filled .toast-close:hover {
14122
14994
  color: inherit;
14995
+ background-color: color-mix(in oklch, currentColor 12%, transparent);
14123
14996
  }
14124
14997
 
14125
14998
  /* Ghost Variant */
@@ -14128,6 +15001,7 @@
14128
15001
  border-color: transparent;
14129
15002
  }
14130
15003
 
15004
+ .toast-ghost.toast-accent { color: var(--color-accent); }
14131
15005
  .toast-ghost.toast-primary { color: var(--color-primary); }
14132
15006
  .toast-ghost.toast-secondary { color: var(--color-secondary); }
14133
15007
  .toast-ghost.toast-tertiary { color: var(--color-tertiary); }
@@ -14135,7 +15009,6 @@
14135
15009
  .toast-ghost.toast-success { color: var(--color-success); }
14136
15010
  .toast-ghost.toast-warning { color: var(--color-warning); }
14137
15011
  .toast-ghost.toast-error { color: var(--color-error); }
14138
- .toast-ghost.toast-accent { color: var(--color-accent); }
14139
15012
  .toast-ghost.toast-neutral { color: var(--color-neutral); }
14140
15013
  .toast-ghost.toast-base { color: var(--color-base-content); }
14141
15014
 
@@ -14144,6 +15017,49 @@
14144
15017
  color: inherit;
14145
15018
  }
14146
15019
 
15020
+ /* Size and density variants retained by the public API. */
15021
+ .toast-sm {
15022
+ width: 18rem;
15023
+ padding: 0.75rem;
15024
+ }
15025
+
15026
+ .toast-lg {
15027
+ width: 26rem;
15028
+ padding: 1.25rem;
15029
+ }
15030
+
15031
+ .toast-compact {
15032
+ padding: 0.75rem;
15033
+ gap: 0.5rem;
15034
+ }
15035
+
15036
+ .toast-compact .toast-icon {
15037
+ width: 1.25rem;
15038
+ height: 1.25rem;
15039
+ font-size: 1rem;
15040
+ }
15041
+
15042
+ .toast-compact .toast-title { font-size: 0.8125rem; }
15043
+ .toast-compact .toast-message { font-size: 0.8125rem; }
15044
+
15045
+ /* Accent edge and stacked presentation. */
15046
+ .toast-accent::before {
15047
+ content: "";
15048
+ position: absolute;
15049
+ inset-block: 0;
15050
+ inset-inline-start: 0;
15051
+ width: 0.25rem;
15052
+ background-color: var(--_toast-accent-color);
15053
+ border-start-start-radius: var(--radius-md);
15054
+ border-end-start-radius: var(--radius-md);
15055
+ }
15056
+
15057
+ .toast-container-stacked .toast:not(:first-child) {
15058
+ margin-top: -0.75rem;
15059
+ transform: scale(0.97);
15060
+ opacity: 0.9;
15061
+ }
15062
+
14147
15063
  /* Progress Bar (for auto-dismiss) */
14148
15064
  .toast-progress {
14149
15065
  position: absolute;
@@ -14174,6 +15090,22 @@
14174
15090
  .toast-progress {
14175
15091
  animation: none;
14176
15092
  }
15093
+
15094
+ .toast-container { scroll-behavior: auto; }
15095
+ }
15096
+
15097
+ @media (max-width: 40rem) {
15098
+ .toast-container[popover] {
15099
+ inset-inline: 0;
15100
+ width: 100%;
15101
+ transform: none;
15102
+ align-items: stretch;
15103
+ }
15104
+
15105
+ .toast {
15106
+ width: 100%;
15107
+ max-width: 100%;
15108
+ }
14177
15109
  }
14178
15110
  }
14179
15111
 
@@ -14255,53 +15187,8 @@
14255
15187
  position-area: right;
14256
15188
  }
14257
15189
 
14258
- /* ========================================
14259
- * Arrow (preferred position only; may be wrong after flip)
14260
- * ======================================== */
14261
-
14262
- .tooltip[popover]::before {
14263
- content: '';
14264
- position: absolute;
14265
- width: 0;
14266
- height: 0;
14267
- border: 0.375rem solid transparent;
14268
- }
14269
-
14270
- .tooltip-top[popover]::before,
14271
- .tooltip[popover]:not(.tooltip-bottom):not(.tooltip-left):not(.tooltip-right)::before {
14272
- top: 100%;
14273
- left: 50%;
14274
- transform: translateX(-50%);
14275
- border-top-color: var(--tooltip-bg);
14276
- }
14277
-
14278
- .tooltip-bottom[popover]::before {
14279
- bottom: 100%;
14280
- top: auto;
14281
- left: 50%;
14282
- transform: translateX(-50%);
14283
- border-bottom-color: var(--tooltip-bg);
14284
- border-top-color: transparent;
14285
- }
14286
-
14287
- .tooltip-left[popover]::before {
14288
- left: 100%;
14289
- top: 50%;
14290
- bottom: auto;
14291
- transform: translateY(-50%);
14292
- border-left-color: var(--tooltip-bg);
14293
- border-top-color: transparent;
14294
- }
14295
-
14296
- .tooltip-right[popover]::before {
14297
- right: 100%;
14298
- left: auto;
14299
- top: 50%;
14300
- bottom: auto;
14301
- transform: translateY(-50%);
14302
- border-right-color: var(--tooltip-bg);
14303
- border-top-color: transparent;
14304
- }
15190
+ /* Automatic placement can flip independently of the preferred side. The
15191
+ core stays arrowless instead of showing a misleading arrow. */
14305
15192
 
14306
15193
  /* ========================================
14307
15194
  * Color variants