@duskmoon-dev/core 1.9.0 → 1.10.1

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 (54) hide show
  1. package/README.md +3 -3
  2. package/dist/components/appbar.css +2 -2
  3. package/dist/components/autocomplete.css +1 -1
  4. package/dist/components/card.css +4 -4
  5. package/dist/components/cascader.css +1 -1
  6. package/dist/components/collapse.css +1 -1
  7. package/dist/components/datepicker.css +2 -2
  8. package/dist/components/dialog.css +1 -1
  9. package/dist/components/drawer.css +1 -1
  10. package/dist/components/file-upload.css +1 -1
  11. package/dist/components/form-group.css +33 -1
  12. package/dist/components/index.css +630 -42
  13. package/dist/components/modal.css +1 -1
  14. package/dist/components/multi-select.css +1 -1
  15. package/dist/components/navigation.css +2 -2
  16. package/dist/components/nested-menu.css +261 -0
  17. package/dist/components/popover.css +28 -16
  18. package/dist/components/snackbar.css +1 -1
  19. package/dist/components/theme-controller.css +281 -0
  20. package/dist/components/time-input.css +1 -1
  21. package/dist/components/toast.css +1 -1
  22. package/dist/components/toggle.css +274 -0
  23. package/dist/components/tooltip.css +2 -2
  24. package/dist/components/tree-select.css +1 -1
  25. package/dist/esm/components/appbar.js +2 -2
  26. package/dist/esm/components/autocomplete.js +1 -1
  27. package/dist/esm/components/card.js +4 -4
  28. package/dist/esm/components/cascader.js +1 -1
  29. package/dist/esm/components/collapse.js +1 -1
  30. package/dist/esm/components/datepicker.js +2 -2
  31. package/dist/esm/components/dialog.js +1 -1
  32. package/dist/esm/components/drawer.js +1 -1
  33. package/dist/esm/components/file-upload.js +1 -1
  34. package/dist/esm/components/form-group.js +33 -1
  35. package/dist/esm/components/modal.js +1 -1
  36. package/dist/esm/components/multi-select.js +1 -1
  37. package/dist/esm/components/navigation.js +2 -2
  38. package/dist/esm/components/nested-menu.js +268 -0
  39. package/dist/esm/components/popover.js +28 -16
  40. package/dist/esm/components/snackbar.js +1 -1
  41. package/dist/esm/components/theme-controller.js +288 -0
  42. package/dist/esm/components/time-input.js +1 -1
  43. package/dist/esm/components/toast.js +1 -1
  44. package/dist/esm/components/toggle.js +281 -0
  45. package/dist/esm/components/tooltip.js +2 -2
  46. package/dist/esm/components/tree-select.js +1 -1
  47. package/dist/index.css +702 -73
  48. package/dist/index.min.css +1 -0
  49. package/dist/themes/moonlight.css +34 -16
  50. package/dist/themes/ocean.css +16 -7
  51. package/dist/themes/sunset.css +5 -4
  52. package/dist/themes/sunshine.css +6 -4
  53. package/dist/types/types/plugin.d.ts +1 -1
  54. package/package.json +21 -1
@@ -35,7 +35,7 @@
35
35
  background-color: var(--color-surface);
36
36
  color: var(--color-on-surface);
37
37
  border-radius: 1rem;
38
- box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);
38
+ box-shadow: var(--shadow-2xl);
39
39
  overflow-y: auto;
40
40
  transform: scale(0.95);
41
41
  transition: transform 200ms ease-out;
@@ -191,7 +191,7 @@
191
191
  background-color: var(--color-surface);
192
192
  border: 1px solid var(--color-outline-variant);
193
193
  border-radius: 0.5rem;
194
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
194
+ box-shadow: var(--shadow-md);
195
195
  overflow: hidden;
196
196
  }
197
197
 
@@ -438,7 +438,7 @@
438
438
  .tabs-boxed .tab[aria-selected="true"] {
439
439
  background-color: var(--color-surface);
440
440
  color: var(--color-on-surface);
441
- box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
441
+ box-shadow: var(--shadow-xs);
442
442
  }
443
443
 
444
444
  /* Tabs Lifted */
@@ -490,7 +490,7 @@
490
490
  background-color: var(--color-surface);
491
491
  border: 1px solid var(--color-outline);
492
492
  border-radius: 0.5rem;
493
- box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
493
+ box-shadow: var(--shadow-lg);
494
494
  opacity: 0;
495
495
  visibility: hidden;
496
496
  transform: translateY(-0.5rem);
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Nested Menu Component Styles
3
+ * DuskMoonUI - Sidebar navigation with collapsible cascading levels via <details>/<summary>
4
+ */
5
+
6
+ @layer components {
7
+ /* ============================================
8
+ * ROOT CONTAINER
9
+ * ============================================ */
10
+
11
+ .nested-menu {
12
+ display: flex;
13
+ flex-direction: column;
14
+ list-style: none;
15
+ margin: 0;
16
+ padding: 0.5rem;
17
+ gap: 0.125rem;
18
+ font-size: 0.875rem;
19
+ color: var(--color-on-surface);
20
+ }
21
+
22
+ /* ============================================
23
+ * SECTION TITLES
24
+ * ============================================ */
25
+
26
+ .nested-menu-title {
27
+ padding: 0.75rem 0.75rem 0.25rem;
28
+ font-size: 0.6875rem;
29
+ font-weight: 600;
30
+ text-transform: uppercase;
31
+ letter-spacing: 0.05em;
32
+ color: var(--color-on-surface-variant);
33
+ user-select: none;
34
+ }
35
+
36
+ /* ============================================
37
+ * MENU ITEMS (links and buttons)
38
+ * ============================================ */
39
+
40
+ .nested-menu li > a,
41
+ .nested-menu li > button {
42
+ display: flex;
43
+ align-items: center;
44
+ gap: 0.5rem;
45
+ width: 100%;
46
+ padding: 0.5rem 0.75rem;
47
+ font-size: inherit;
48
+ color: var(--color-on-surface);
49
+ text-decoration: none;
50
+ background-color: transparent;
51
+ border: none;
52
+ border-radius: var(--radius-field, 0.375rem);
53
+ cursor: pointer;
54
+ transition: background-color 150ms ease-in-out, color 150ms ease-in-out;
55
+ }
56
+
57
+ .nested-menu li > a:hover,
58
+ .nested-menu li > button:hover {
59
+ background-color: var(--color-surface-container);
60
+ }
61
+
62
+ .nested-menu li > a:focus-visible,
63
+ .nested-menu li > button:focus-visible {
64
+ outline: 2px solid var(--color-primary);
65
+ outline-offset: -2px;
66
+ }
67
+
68
+ /* Active state */
69
+ .nested-menu li > a.active,
70
+ .nested-menu li > button.active,
71
+ .nested-menu li > a[aria-current="page"],
72
+ .nested-menu li > button[aria-current="page"] {
73
+ background-color: var(--color-primary-container);
74
+ color: var(--color-on-primary-container);
75
+ }
76
+
77
+ .nested-menu li > a.active:hover,
78
+ .nested-menu li > button.active:hover,
79
+ .nested-menu li > a[aria-current="page"]:hover,
80
+ .nested-menu li > button[aria-current="page"]:hover {
81
+ background-color: color-mix(in oklch, var(--color-primary-container), var(--color-on-primary-container) 8%);
82
+ }
83
+
84
+ /* Disabled state */
85
+ .nested-menu li.disabled {
86
+ opacity: 0.5;
87
+ pointer-events: none;
88
+ }
89
+
90
+ /* ============================================
91
+ * COLLAPSIBLE SUBMENUS (<details>/<summary>)
92
+ * ============================================ */
93
+
94
+ .nested-menu details {
95
+ width: 100%;
96
+ }
97
+
98
+ /* Remove native marker */
99
+ .nested-menu summary {
100
+ display: flex;
101
+ align-items: center;
102
+ gap: 0.5rem;
103
+ width: 100%;
104
+ padding: 0.5rem 0.75rem;
105
+ font-size: inherit;
106
+ color: var(--color-on-surface);
107
+ background-color: transparent;
108
+ border: none;
109
+ border-radius: var(--radius-field, 0.375rem);
110
+ cursor: pointer;
111
+ list-style: none;
112
+ transition: background-color 150ms ease-in-out;
113
+ }
114
+
115
+ .nested-menu summary::-webkit-details-marker {
116
+ display: none;
117
+ }
118
+
119
+ .nested-menu summary::marker {
120
+ display: none;
121
+ content: "";
122
+ }
123
+
124
+ .nested-menu summary:hover {
125
+ background-color: var(--color-surface-container);
126
+ }
127
+
128
+ .nested-menu summary:focus-visible {
129
+ outline: 2px solid var(--color-primary);
130
+ outline-offset: -2px;
131
+ }
132
+
133
+ /* Chevron indicator */
134
+ .nested-menu summary::after {
135
+ content: "";
136
+ display: inline-block;
137
+ margin-left: auto;
138
+ width: 0.375rem;
139
+ height: 0.375rem;
140
+ border-right: 1.5px solid currentColor;
141
+ border-bottom: 1.5px solid currentColor;
142
+ transform: rotate(-45deg);
143
+ transition: transform 200ms ease-in-out;
144
+ flex-shrink: 0;
145
+ opacity: 0.6;
146
+ }
147
+
148
+ .nested-menu details[open] > summary::after {
149
+ transform: rotate(45deg);
150
+ }
151
+
152
+ /* Nested <ul> inside details — auto-indentation */
153
+ .nested-menu details > ul {
154
+ list-style: none;
155
+ margin: 0;
156
+ padding: 0.125rem 0 0.125rem 1rem;
157
+ display: flex;
158
+ flex-direction: column;
159
+ gap: 0.125rem;
160
+ }
161
+
162
+ /* ============================================
163
+ * SIZE VARIANTS
164
+ * ============================================ */
165
+
166
+ .nested-menu-xs {
167
+ font-size: 0.75rem;
168
+ padding: 0.25rem;
169
+ }
170
+
171
+ .nested-menu-xs li > a,
172
+ .nested-menu-xs li > button,
173
+ .nested-menu-xs summary {
174
+ padding: 0.25rem 0.5rem;
175
+ gap: 0.375rem;
176
+ }
177
+
178
+ .nested-menu-xs .nested-menu-title {
179
+ padding: 0.5rem 0.5rem 0.125rem;
180
+ font-size: 0.625rem;
181
+ }
182
+
183
+ .nested-menu-sm {
184
+ font-size: 0.8125rem;
185
+ padding: 0.375rem;
186
+ }
187
+
188
+ .nested-menu-sm li > a,
189
+ .nested-menu-sm li > button,
190
+ .nested-menu-sm summary {
191
+ padding: 0.375rem 0.625rem;
192
+ gap: 0.375rem;
193
+ }
194
+
195
+ .nested-menu-sm .nested-menu-title {
196
+ padding: 0.625rem 0.625rem 0.1875rem;
197
+ font-size: 0.625rem;
198
+ }
199
+
200
+ .nested-menu-lg {
201
+ font-size: 1rem;
202
+ padding: 0.625rem;
203
+ }
204
+
205
+ .nested-menu-lg li > a,
206
+ .nested-menu-lg li > button,
207
+ .nested-menu-lg summary {
208
+ padding: 0.625rem 1rem;
209
+ gap: 0.625rem;
210
+ }
211
+
212
+ .nested-menu-lg .nested-menu-title {
213
+ padding: 0.875rem 1rem 0.375rem;
214
+ font-size: 0.75rem;
215
+ }
216
+
217
+ /* ============================================
218
+ * MODIFIER VARIANTS
219
+ * ============================================ */
220
+
221
+ /* Bordered — sidebar panel look */
222
+ .nested-menu-bordered {
223
+ background-color: var(--color-surface);
224
+ border: 1px solid var(--color-outline-variant);
225
+ border-radius: var(--radius-card, 0.75rem);
226
+ box-shadow: var(--shadow-sm, 0 1px 2px 0 rgb(0 0 0 / 0.05));
227
+ }
228
+
229
+ /* Compact — tighter padding throughout */
230
+ .nested-menu-compact {
231
+ padding: 0.25rem;
232
+ gap: 0;
233
+ }
234
+
235
+ .nested-menu-compact li > a,
236
+ .nested-menu-compact li > button,
237
+ .nested-menu-compact summary {
238
+ padding: 0.3125rem 0.625rem;
239
+ }
240
+
241
+ .nested-menu-compact .nested-menu-title {
242
+ padding: 0.5rem 0.625rem 0.125rem;
243
+ }
244
+
245
+ .nested-menu-compact details > ul {
246
+ padding: 0 0 0 0.75rem;
247
+ }
248
+
249
+ /* ============================================
250
+ * REDUCED MOTION
251
+ * ============================================ */
252
+
253
+ @media (prefers-reduced-motion: reduce) {
254
+ .nested-menu li > a,
255
+ .nested-menu li > button,
256
+ .nested-menu summary,
257
+ .nested-menu summary::after {
258
+ transition: none;
259
+ }
260
+ }
261
+ }
@@ -4,8 +4,8 @@
4
4
  */
5
5
 
6
6
  @layer components {
7
- /* Popover Container */
8
- .popover {
7
+ /* Popover Container (class-based approach only, not native [popover]) */
8
+ .popover:not([popover]) {
9
9
  position: relative;
10
10
  display: inline-block;
11
11
  }
@@ -20,7 +20,7 @@
20
20
  background-color: var(--color-surface);
21
21
  border: 1px solid var(--color-outline-variant);
22
22
  border-radius: 0.75rem;
23
- box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
23
+ box-shadow: var(--shadow-lg);
24
24
  opacity: 0;
25
25
  visibility: hidden;
26
26
  transform: scale(0.95);
@@ -55,7 +55,7 @@
55
55
  background-color: var(--color-surface);
56
56
  border: 1px solid var(--color-outline-variant);
57
57
  border-radius: 0.75rem;
58
- box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
58
+ box-shadow: var(--shadow-lg);
59
59
  opacity: 0;
60
60
  visibility: hidden;
61
61
  transition: opacity 150ms ease-out, visibility 150ms ease-out;
@@ -509,7 +509,7 @@
509
509
  background-color: var(--color-surface);
510
510
  border: 1px solid var(--color-outline-variant);
511
511
  border-radius: 0.75rem;
512
- box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
512
+ box-shadow: var(--shadow-lg);
513
513
  opacity: 0;
514
514
  transform: scale(0.95);
515
515
  transition: opacity 150ms ease-out, transform 150ms ease-out, overlay 150ms ease-out allow-discrete, display 150ms ease-out allow-discrete;
@@ -651,53 +651,65 @@
651
651
  style="anchor-name: --my-popover" */
652
652
  }
653
653
 
654
- /* Anchored popover positioning */
654
+ /* Anchored popover positioning
655
+ * Uses anchor() functions instead of position-area to avoid
656
+ * a Chrome rendering bug at HiDPI (DPR>=2) where position-area
657
+ * computes correct CSS-pixel offsets but renders at physical-pixel
658
+ * coordinates, doubling the distance from the anchor. */
655
659
  .popover[popover][style*="position-anchor"] {
656
- position: absolute;
657
- position-area: bottom;
660
+ inset: unset;
661
+ top: anchor(bottom);
662
+ justify-self: anchor-center;
658
663
  margin-top: 0.5rem;
659
664
  }
660
665
 
661
666
  /* Position variants for anchored popovers */
662
667
  .popover-top[popover][style*="position-anchor"] {
663
- position-area: top;
668
+ top: unset;
669
+ bottom: anchor(top);
664
670
  margin-top: 0;
665
671
  margin-bottom: 0.5rem;
666
672
  }
667
673
 
668
674
  .popover-bottom[popover][style*="position-anchor"] {
669
- position-area: bottom;
675
+ top: anchor(bottom);
670
676
  margin-top: 0.5rem;
671
677
  margin-bottom: 0;
672
678
  }
673
679
 
674
680
  .popover-left[popover][style*="position-anchor"] {
675
- position-area: left;
681
+ top: anchor(center);
682
+ right: anchor(left);
683
+ justify-self: unset;
684
+ translate: 0 -50%;
676
685
  margin-top: 0;
677
686
  margin-right: 0.5rem;
678
687
  }
679
688
 
680
689
  .popover-right[popover][style*="position-anchor"] {
681
- position-area: right;
690
+ top: anchor(center);
691
+ left: anchor(right);
692
+ justify-self: unset;
693
+ translate: 0 -50%;
682
694
  margin-top: 0;
683
695
  margin-left: 0.5rem;
684
696
  }
685
697
 
686
698
  /* Anchored popover alignment variants */
687
699
  .popover-start[popover][style*="position-anchor"] {
688
- position-area: bottom start;
700
+ justify-self: start;
689
701
  }
690
702
 
691
703
  .popover-end[popover][style*="position-anchor"] {
692
- position-area: bottom end;
704
+ justify-self: end;
693
705
  }
694
706
 
695
707
  .popover-top.popover-start[popover][style*="position-anchor"] {
696
- position-area: top start;
708
+ justify-self: start;
697
709
  }
698
710
 
699
711
  .popover-top.popover-end[popover][style*="position-anchor"] {
700
- position-area: top end;
712
+ justify-self: end;
701
713
  }
702
714
 
703
715
  /* Reduce Motion */
@@ -65,7 +65,7 @@
65
65
  background-color: var(--color-surface-container-highest);
66
66
  color: var(--color-on-surface);
67
67
  border-radius: 0.5rem;
68
- box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
68
+ box-shadow: var(--shadow-md);
69
69
  pointer-events: auto;
70
70
  opacity: 0;
71
71
  transform: translateY(100%);
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Theme Controller Component Styles
3
+ * DuskMoonUI - Two display modes for theme switching:
4
+ *
5
+ * 1. Switch (.theme-controller) — inline pill-shaped radio group, all options visible
6
+ * 2. Dropdown (.theme-controller-dropdown) — <details>/<summary> with floating menu
7
+ *
8
+ * Both modes reuse .theme-controller-item (hidden radio) and .theme-controller-label
9
+ * for CSS-only active state via :checked + label.
10
+ */
11
+
12
+ @layer components {
13
+ /* ========================================
14
+ * SHARED — Radio input & label (used in both modes)
15
+ * ======================================== */
16
+
17
+ /* Hidden Radio Input — visually hidden but accessible */
18
+ .theme-controller-item {
19
+ position: absolute;
20
+ width: 1px;
21
+ height: 1px;
22
+ padding: 0;
23
+ margin: -1px;
24
+ overflow: hidden;
25
+ clip: rect(0, 0, 0, 0);
26
+ white-space: nowrap;
27
+ border: 0;
28
+ }
29
+
30
+ /* Visible Label — the clickable option */
31
+ .theme-controller-label {
32
+ display: inline-flex;
33
+ align-items: center;
34
+ justify-content: center;
35
+ gap: 0.5rem;
36
+ padding: 0.5rem 1rem;
37
+ font-size: 0.875rem;
38
+ font-weight: 500;
39
+ line-height: 1.25rem;
40
+ color: var(--color-on-surface-variant);
41
+ background-color: transparent;
42
+ border-radius: calc(var(--radius-box, 1.5rem) - 0.25rem);
43
+ cursor: pointer;
44
+ transition: background-color 150ms ease-in-out, color 150ms ease-in-out,
45
+ box-shadow 150ms ease-in-out;
46
+ user-select: none;
47
+ white-space: nowrap;
48
+ }
49
+
50
+ /* Hover state */
51
+ .theme-controller-label:hover {
52
+ background-color: var(--color-surface-container-high);
53
+ }
54
+
55
+ /* Focus-visible ring on the label when its radio is focused */
56
+ .theme-controller-item:focus-visible + .theme-controller-label {
57
+ outline: 2px solid var(--color-primary);
58
+ outline-offset: 2px;
59
+ }
60
+
61
+ /* Active/checked state */
62
+ .theme-controller-item:checked + .theme-controller-label {
63
+ background-color: var(--color-primary-container);
64
+ color: var(--color-on-primary-container);
65
+ box-shadow: var(--shadow-xs);
66
+ }
67
+
68
+ .theme-controller-item:checked + .theme-controller-label:hover {
69
+ background-color: color-mix(in oklch, var(--color-primary-container), black 5%);
70
+ }
71
+
72
+ /* ========================================
73
+ * SWITCH MODE — inline pill radio group
74
+ * ======================================== */
75
+
76
+ .theme-controller {
77
+ display: inline-flex;
78
+ align-items: stretch;
79
+ background-color: var(--color-surface-container);
80
+ border: 1px solid var(--color-outline-variant);
81
+ border-radius: var(--radius-box, 1.5rem);
82
+ padding: 0.25rem;
83
+ gap: 0.125rem;
84
+ }
85
+
86
+ /* ── Switch Size Variants ── */
87
+
88
+ .theme-controller-sm {
89
+ padding: 0.125rem;
90
+ border-radius: calc(var(--radius-box, 1.5rem) * 0.75);
91
+ }
92
+
93
+ .theme-controller-sm .theme-controller-label {
94
+ padding: 0.375rem 0.75rem;
95
+ font-size: 0.75rem;
96
+ line-height: 1rem;
97
+ border-radius: calc(var(--radius-box, 1.5rem) * 0.75 - 0.125rem);
98
+ }
99
+
100
+ .theme-controller-lg {
101
+ padding: 0.375rem;
102
+ gap: 0.25rem;
103
+ border-radius: calc(var(--radius-box, 1.5rem) * 1.25);
104
+ }
105
+
106
+ .theme-controller-lg .theme-controller-label {
107
+ padding: 0.75rem 1.5rem;
108
+ font-size: 1rem;
109
+ line-height: 1.5rem;
110
+ border-radius: calc(var(--radius-box, 1.5rem) * 1.25 - 0.375rem);
111
+ }
112
+
113
+ /* ── Switch Icon-only Variant ── */
114
+
115
+ .theme-controller-icon .theme-controller-label {
116
+ padding: 0.5rem;
117
+ }
118
+
119
+ .theme-controller-icon.theme-controller-sm .theme-controller-label {
120
+ padding: 0.375rem;
121
+ }
122
+
123
+ .theme-controller-icon.theme-controller-lg .theme-controller-label {
124
+ padding: 0.75rem;
125
+ }
126
+
127
+ /* ========================================
128
+ * DROPDOWN MODE — <details>/<summary> with floating menu
129
+ * ======================================== */
130
+
131
+ .theme-controller-dropdown {
132
+ position: relative;
133
+ display: inline-block;
134
+ }
135
+
136
+ /* Trigger button (<summary>) */
137
+ .theme-controller-trigger {
138
+ display: inline-flex;
139
+ align-items: center;
140
+ gap: 0.5rem;
141
+ padding: 0.5rem 0.75rem;
142
+ font-size: 0.875rem;
143
+ font-weight: 500;
144
+ line-height: 1.25rem;
145
+ color: var(--color-on-surface);
146
+ background-color: var(--color-surface-container);
147
+ border: 1px solid var(--color-outline-variant);
148
+ border-radius: var(--radius-field, 0.5rem);
149
+ cursor: pointer;
150
+ user-select: none;
151
+ transition: background-color 150ms ease-in-out;
152
+ list-style: none;
153
+ }
154
+
155
+ .theme-controller-trigger::-webkit-details-marker {
156
+ display: none;
157
+ }
158
+
159
+ .theme-controller-trigger:hover {
160
+ background-color: var(--color-surface-container-high);
161
+ }
162
+
163
+ .theme-controller-trigger:focus-visible {
164
+ outline: 2px solid var(--color-primary);
165
+ outline-offset: 2px;
166
+ }
167
+
168
+ /* Chevron indicator */
169
+ .theme-controller-trigger::after {
170
+ content: '';
171
+ display: inline-block;
172
+ width: 0.5rem;
173
+ height: 0.5rem;
174
+ border-right: 2px solid currentColor;
175
+ border-bottom: 2px solid currentColor;
176
+ transform: rotate(45deg);
177
+ margin-top: -0.125rem;
178
+ transition: transform 150ms ease-in-out;
179
+ }
180
+
181
+ .theme-controller-dropdown[open] .theme-controller-trigger::after {
182
+ transform: rotate(-135deg);
183
+ margin-top: 0.125rem;
184
+ }
185
+
186
+ /* Floating menu */
187
+ .theme-controller-menu {
188
+ position: absolute;
189
+ top: calc(100% + 0.25rem);
190
+ left: 0;
191
+ z-index: 50;
192
+ min-width: 100%;
193
+ background-color: var(--color-surface-container);
194
+ border: 1px solid var(--color-outline-variant);
195
+ border-radius: var(--radius-field, 0.5rem);
196
+ padding: 0.25rem;
197
+ box-shadow: var(--shadow-md);
198
+ display: flex;
199
+ flex-direction: column;
200
+ gap: 0.125rem;
201
+ }
202
+
203
+ /* Menu labels are full-width and left-aligned */
204
+ .theme-controller-menu .theme-controller-label {
205
+ width: 100%;
206
+ justify-content: flex-start;
207
+ border-radius: calc(var(--radius-field, 0.5rem) - 0.25rem);
208
+ }
209
+
210
+ /* ── Dropdown Size Variants ── */
211
+
212
+ .theme-controller-dropdown-sm .theme-controller-trigger {
213
+ padding: 0.375rem 0.625rem;
214
+ font-size: 0.75rem;
215
+ line-height: 1rem;
216
+ }
217
+
218
+ .theme-controller-dropdown-sm .theme-controller-menu {
219
+ padding: 0.125rem;
220
+ }
221
+
222
+ .theme-controller-dropdown-sm .theme-controller-menu .theme-controller-label {
223
+ padding: 0.375rem 0.75rem;
224
+ font-size: 0.75rem;
225
+ line-height: 1rem;
226
+ }
227
+
228
+ .theme-controller-dropdown-lg .theme-controller-trigger {
229
+ padding: 0.75rem 1rem;
230
+ font-size: 1rem;
231
+ line-height: 1.5rem;
232
+ }
233
+
234
+ .theme-controller-dropdown-lg .theme-controller-menu {
235
+ padding: 0.375rem;
236
+ }
237
+
238
+ .theme-controller-dropdown-lg .theme-controller-menu .theme-controller-label {
239
+ padding: 0.75rem 1.5rem;
240
+ font-size: 1rem;
241
+ line-height: 1.5rem;
242
+ }
243
+
244
+ /* ── Dropdown Icon-only Trigger ── */
245
+
246
+ .theme-controller-dropdown-icon .theme-controller-trigger {
247
+ padding: 0.5rem;
248
+ }
249
+
250
+ /* Hide chevron for icon-only trigger */
251
+ .theme-controller-dropdown-icon .theme-controller-trigger::after {
252
+ display: none;
253
+ }
254
+
255
+ .theme-controller-dropdown-icon.theme-controller-dropdown-sm .theme-controller-trigger {
256
+ padding: 0.375rem;
257
+ }
258
+
259
+ .theme-controller-dropdown-icon.theme-controller-dropdown-lg .theme-controller-trigger {
260
+ padding: 0.75rem;
261
+ }
262
+
263
+ /* ── Dropdown Alignment ── */
264
+
265
+ .theme-controller-dropdown-end .theme-controller-menu {
266
+ left: auto;
267
+ right: 0;
268
+ }
269
+
270
+ /* ========================================
271
+ * REDUCED MOTION
272
+ * ======================================== */
273
+
274
+ @media (prefers-reduced-motion: reduce) {
275
+ .theme-controller-label,
276
+ .theme-controller-trigger,
277
+ .theme-controller-trigger::after {
278
+ transition: none;
279
+ }
280
+ }
281
+ }
@@ -198,7 +198,7 @@
198
198
  background-color: var(--color-surface);
199
199
  border: 1px solid var(--color-outline-variant);
200
200
  border-radius: 0.5rem;
201
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
201
+ box-shadow: var(--shadow-md);
202
202
  }
203
203
 
204
204
  .time-picker-dropdown-open {