@duskmoon-dev/core 1.19.3 → 1.19.4

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 (101) hide show
  1. package/README.md +1 -1
  2. package/dist/base.css +484 -0
  3. package/dist/components/accordion.css +33 -9
  4. package/dist/components/autocomplete.css +67 -13
  5. package/dist/components/avatar.css +39 -15
  6. package/dist/components/badge.css +15 -3
  7. package/dist/components/card.css +12 -0
  8. package/dist/components/carousel.css +28 -0
  9. package/dist/components/chat.css +15 -11
  10. package/dist/components/checkbox.css +83 -13
  11. package/dist/components/collapse.css +67 -16
  12. package/dist/components/countdown.css +22 -0
  13. package/dist/components/datepicker.css +76 -0
  14. package/dist/components/diff.css +33 -0
  15. package/dist/components/file-input.css +107 -0
  16. package/dist/components/filter-group.css +452 -0
  17. package/dist/components/form-group.css +95 -204
  18. package/dist/components/form.css +1551 -421
  19. package/dist/components/index.css +5991 -6060
  20. package/dist/components/input.css +114 -31
  21. package/dist/components/kbd.css +28 -0
  22. package/dist/components/list.css +22 -3
  23. package/dist/components/otp-input.css +124 -6
  24. package/dist/components/radio.css +70 -0
  25. package/dist/components/range.css +41 -0
  26. package/dist/components/rating.css +39 -12
  27. package/dist/components/select.css +74 -0
  28. package/dist/components/stat.css +40 -0
  29. package/dist/components/switch.css +70 -0
  30. package/dist/components/table.css +8 -0
  31. package/dist/components/textarea.css +74 -0
  32. package/dist/components/timeline.css +40 -25
  33. package/dist/components/toggle-switch.css +165 -0
  34. package/dist/components/toggle.css +198 -32
  35. package/dist/components/validator.css +66 -0
  36. package/dist/effects/aura.css +22 -0
  37. package/dist/effects/hover-3d.css +8 -0
  38. package/dist/effects/hover-gallery.css +14 -0
  39. package/dist/effects/index.css +65 -0
  40. package/dist/effects/text-rotate.css +16 -0
  41. package/dist/esm/components/accordion.js +33 -9
  42. package/dist/esm/components/autocomplete.js +67 -13
  43. package/dist/esm/components/avatar.js +39 -15
  44. package/dist/esm/components/badge.js +15 -3
  45. package/dist/esm/components/card.js +12 -0
  46. package/dist/esm/components/carousel.d.ts +5 -0
  47. package/dist/esm/components/carousel.js +37 -0
  48. package/dist/esm/components/chat.js +15 -11
  49. package/dist/esm/components/checkbox.js +84 -14
  50. package/dist/esm/components/collapse.js +67 -16
  51. package/dist/esm/components/countdown.d.ts +5 -0
  52. package/dist/esm/components/countdown.js +31 -0
  53. package/dist/esm/components/datepicker.js +77 -1
  54. package/dist/esm/components/diff.d.ts +5 -0
  55. package/dist/esm/components/diff.js +42 -0
  56. package/dist/esm/components/file-input.d.ts +5 -0
  57. package/dist/esm/components/file-input.js +116 -0
  58. package/dist/esm/components/filter-group.d.ts +5 -0
  59. package/dist/esm/components/filter-group.js +461 -0
  60. package/dist/esm/components/form-group.js +96 -205
  61. package/dist/esm/components/form.js +1539 -409
  62. package/dist/esm/components/input.js +115 -32
  63. package/dist/esm/components/kbd.d.ts +5 -0
  64. package/dist/esm/components/kbd.js +37 -0
  65. package/dist/esm/components/list.js +22 -3
  66. package/dist/esm/components/otp-input.js +125 -7
  67. package/dist/esm/components/radio.js +71 -1
  68. package/dist/esm/components/range.d.ts +5 -0
  69. package/dist/esm/components/range.js +50 -0
  70. package/dist/esm/components/rating.js +39 -12
  71. package/dist/esm/components/select.js +75 -1
  72. package/dist/esm/components/stat.d.ts +5 -0
  73. package/dist/esm/components/stat.js +49 -0
  74. package/dist/esm/components/switch.js +71 -1
  75. package/dist/esm/components/table.js +8 -0
  76. package/dist/esm/components/textarea.js +75 -1
  77. package/dist/esm/components/timeline.js +40 -25
  78. package/dist/esm/components/toggle-switch.d.ts +5 -0
  79. package/dist/esm/components/toggle-switch.js +174 -0
  80. package/dist/esm/components/toggle.js +198 -32
  81. package/dist/esm/components/validator.d.ts +5 -0
  82. package/dist/esm/components/validator.js +75 -0
  83. package/dist/esm/effects/aura.d.ts +5 -0
  84. package/dist/esm/effects/aura.js +31 -0
  85. package/dist/esm/effects/hover-3d.d.ts +5 -0
  86. package/dist/esm/effects/hover-3d.js +17 -0
  87. package/dist/esm/effects/hover-gallery.d.ts +5 -0
  88. package/dist/esm/effects/hover-gallery.js +23 -0
  89. package/dist/esm/effects/index.d.ts +5 -0
  90. package/dist/esm/effects/index.js +74 -0
  91. package/dist/esm/effects/text-rotate.d.ts +5 -0
  92. package/dist/esm/effects/text-rotate.js +25 -0
  93. package/dist/index.css +5977 -6047
  94. package/dist/index.min.css +1 -1
  95. package/dist/standalone/duskmoonui-themes.css +1 -1
  96. package/dist/standalone/duskmoonui.css +6967 -7028
  97. package/dist/standalone/duskmoonui.js +11 -12
  98. package/dist/standalone/duskmoonui.mjs +11 -12
  99. package/dist/types/types/plugin.d.ts +1 -1
  100. package/dist/types/types/plugin.d.ts.map +1 -1
  101. package/package.json +98 -1
@@ -3,6 +3,172 @@
3
3
  * DuskMoonUI - Material Design 3 inspired toggle button
4
4
  * Used for selecting between multiple options or toggling states
5
5
  */
6
+ /** Opt-in native presentation. Applications own errors, messages and announcements. */
7
+ @layer components {
8
+ /* Compatibility wrapper states are intentionally immediate. */
9
+ :is(.form-group-info, .form-control.info) { --dm-validation-color: var(--color-info); }
10
+ :is(.form-group-warning, .form-control.warning) { --dm-validation-color: var(--color-warning); }
11
+ :is(.form-group-success, .form-control.success) { --dm-validation-color: var(--color-success); }
12
+
13
+ :is(.input, .select, .textarea, .checkbox, .radio, .switch, .toggle, .file-input, .otp-input-field, .otp-code, .datepicker-input):is(.validate :valid, .validate:valid, .validator.validator-success:user-valid):not([aria-invalid="true"]):not(:where(.form-group-error *, .form-control.error *)):not(:disabled) {
14
+ --dm-validation-color: var(--color-success);
15
+ --dm-validation-content: var(--color-success-content);
16
+ }
17
+
18
+ :is(.input, .select, .textarea, .checkbox, .radio, .switch, .toggle, .file-input, .otp-input-field, .otp-code, .datepicker-input):is(.validate :invalid, .validate:invalid, .validator:user-invalid):not(:disabled) {
19
+ --dm-validation-color: var(--color-error);
20
+ --dm-validation-content: var(--color-error-content);
21
+ }
22
+
23
+ :is(.form-group-error, .form-control.error) {
24
+ --dm-validation-color: var(--color-error);
25
+ --dm-validation-content: var(--color-error-content);
26
+ }
27
+
28
+ /* Higher specificity than native states, including server-invalid + user-valid. */
29
+ :is(.input, .select, .textarea, .checkbox, .radio, .switch, .toggle, .file-input, .otp-input-field, .otp-code, .datepicker-input):is([aria-invalid="true"], .form-group-error *, .form-control.error *):not(:disabled):is(:focus, :not(:focus)) {
30
+ --dm-validation-color: var(--color-error);
31
+ --dm-validation-content: var(--color-error-content);
32
+ }
33
+
34
+ /* This shared selector wins over filled/ghost focus and semantic modifiers. */
35
+ :is(.input, .select, .textarea, .checkbox, .radio, .switch, .toggle, .file-input, .otp-input-field, .otp-code, .datepicker-input):is([aria-invalid="true"], .validator:user-invalid, .validator.validator-success:user-valid, .validate :invalid, .validate :valid, .validate:invalid, .validate:valid, .form-group-error *, .form-group-success *, .form-group-warning *, .form-group-info *, .form-control.error *, .form-control.success *, .form-control.warning *, .form-control.info *):not(:disabled) {
36
+ color: var(--dm-validation-color);
37
+ border-color: var(--dm-validation-color);
38
+ --checkbox-color: var(--dm-validation-color);
39
+ --radio-color: var(--dm-validation-color);
40
+ --switch-color: var(--dm-validation-color);
41
+ --switch-content-color: var(--dm-validation-content, var(--color-primary-content));
42
+ --toggle-color: var(--dm-validation-color);
43
+ }
44
+
45
+ :is(.input, .select, .textarea, .checkbox, .radio, .switch, .toggle, .file-input, .otp-input-field, .otp-code, .datepicker-input):is([aria-invalid="true"], .validator:user-invalid, .validator.validator-success:user-valid, .validate :invalid, .validate :valid, .validate:invalid, .validate:valid, .form-group-error *, .form-group-success *, .form-group-warning *, .form-group-info *, .form-control.error *, .form-control.success *, .form-control.warning *, .form-control.info *):not(:disabled):focus {
46
+ border-color: var(--dm-validation-color);
47
+ box-shadow: 0 0 0 3px color-mix(in oklch, var(--dm-validation-color) 20%, transparent);
48
+ }
49
+
50
+ :is(.form-group-error, .form-control.error) :is(.form-label, .label-text) { color: var(--color-error); }
51
+ :is(.form-group-success, .form-control.success) :is(.form-label, .label-text) { color: var(--color-success); }
52
+ :is(.form-group-warning, .form-control.warning) :is(.form-label, .label-text) { color: var(--color-warning); }
53
+ :is(.form-group-info, .form-control.info) :is(.form-label, .label-text) { color: var(--color-info); }
54
+
55
+ .validator-hint { font-size: 0.75rem; color: var(--color-on-surface-variant); }
56
+ .validator-error { display: none; font-size: 0.75rem; color: var(--color-error); }
57
+ /* Keep OTP actions stationary when blur reveals an error during a click. */
58
+ .otp-code ~ .validator-error { display: block; visibility: hidden; }
59
+ :is(.form-group, .form-control):has(:is([aria-invalid="true"], .validator:user-invalid, .validate :invalid, .validate:invalid):not(:disabled)) > .validator-error,
60
+ :is(.form-group-error, .form-control.error) > .validator-error { display: block; visibility: visible; }
61
+
62
+ @media (forced-colors: active) {
63
+ :is(input, select, textarea):is(.input, .select, .textarea, .checkbox, .radio, .switch, .toggle, .file-input, .otp-input-field, .otp-code, .datepicker-input):focus-visible {
64
+ outline: 2px solid Highlight;
65
+ outline-offset: 2px;
66
+ }
67
+ input:is(.checkbox, .radio, .switch, .toggle) { appearance: auto; }
68
+ input:is(.checkbox, .radio, .switch, .toggle)::before,
69
+ input:is(.checkbox, .radio, .switch, .toggle)::after { content: none; }
70
+ }
71
+ }
72
+
73
+
74
+ @layer components {
75
+ /* Toggle/Switch */
76
+ .toggle {
77
+ --toggle-color: var(--color-primary);
78
+ box-sizing: border-box;
79
+ color: var(--color-on-surface);
80
+ border: 1px solid currentColor;
81
+ appearance: none;
82
+ width: 3rem;
83
+ height: 1.5rem;
84
+ border-radius: var(--radius-lg);
85
+ background-color: var(--color-surface-container-highest);
86
+ cursor: pointer;
87
+ transition: all 150ms ease-in-out;
88
+ position: relative;
89
+ }
90
+
91
+ .toggle::after {
92
+ content: '';
93
+ position: absolute;
94
+ inset-inline-start: 0.25rem;
95
+ top: 50%;
96
+ transform: translateY(-50%);
97
+ width: 1rem;
98
+ height: 1rem;
99
+ background-color: var(--color-on-surface-variant);
100
+ border-radius: var(--radius-full);
101
+ transition: all 150ms ease-in-out;
102
+ }
103
+
104
+ .toggle:checked {
105
+ background-color: var(--toggle-color);
106
+ }
107
+
108
+ .toggle:checked::after {
109
+ inset-inline-start: calc(100% - 1.25rem);
110
+ background-color: var(--dm-validation-content, var(--color-primary-content));
111
+ }
112
+
113
+ .toggle:focus-visible {
114
+ outline: none;
115
+ box-shadow: 0 0 0 3px color-mix(in oklch, currentColor 20%, transparent);
116
+ }
117
+
118
+ .toggle:disabled {
119
+ cursor: not-allowed;
120
+ opacity: 0.5;
121
+ }
122
+
123
+ /* Toggle Sizes */
124
+ .toggle-xs {
125
+ width: 2rem;
126
+ height: 1rem;
127
+ }
128
+
129
+ .toggle-xs::after {
130
+ width: 0.625rem;
131
+ height: 0.625rem;
132
+ inset-inline-start: 0.1875rem;
133
+ }
134
+
135
+ .toggle-xs:checked::after {
136
+ inset-inline-start: calc(100% - 0.8125rem);
137
+ }
138
+
139
+ .toggle-sm {
140
+ width: 2.5rem;
141
+ height: 1.25rem;
142
+ }
143
+
144
+ .toggle-sm::after {
145
+ width: 0.75rem;
146
+ height: 0.75rem;
147
+ }
148
+
149
+ .toggle-lg {
150
+ width: 4rem;
151
+ height: 2rem;
152
+ }
153
+
154
+ .toggle-lg::after {
155
+ width: 1.5rem;
156
+ height: 1.5rem;
157
+ }
158
+
159
+ .toggle-sm:checked::after { inset-inline-start: calc(100% - 1rem); }
160
+ .toggle-lg:checked::after { inset-inline-start: calc(100% - 1.75rem); }
161
+ .toggle-primary { --toggle-color: var(--color-primary); }
162
+ .toggle-secondary { --toggle-color: var(--color-secondary); }
163
+ .toggle-tertiary { --toggle-color: var(--color-tertiary); }
164
+ .toggle-info { --toggle-color: var(--color-info); }
165
+ .toggle-success { --toggle-color: var(--color-success); }
166
+ .toggle-warning { --toggle-color: var(--color-warning); }
167
+ .toggle-error { --toggle-color: var(--color-error); }
168
+ .toggle-ghost { border-color: transparent; }
169
+ @media (prefers-reduced-motion: reduce) { .toggle, .toggle::after { transition: none; } }
170
+ }
171
+
6
172
 
7
173
  @layer components {
8
174
  /* Base toggle button */
@@ -30,93 +196,93 @@
30
196
  }
31
197
 
32
198
  /* Active/Selected state */
33
- .toggle-btn-active,
34
- .toggle-btn.active {
199
+ :is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
200
+ .toggle-btn.active:not([aria-pressed]) {
35
201
  color: var(--color-on-primary-container);
36
202
  background-color: var(--color-primary-container);
37
203
  border-color: var(--color-primary);
38
204
  }
39
205
 
40
- .toggle-btn-active:hover:not(:disabled),
41
- .toggle-btn.active:hover:not(:disabled) {
206
+ :is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]):hover:not(:disabled),
207
+ .toggle-btn.active:not([aria-pressed]):hover:not(:disabled) {
42
208
  background-color: color-mix(in oklch, var(--color-primary-container) 90%, transparent);
43
209
  }
44
210
 
45
211
  /* Primary variant */
46
- .toggle-btn-primary.toggle-btn-active,
47
- .toggle-btn-primary.active {
212
+ .toggle-btn-primary:is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
213
+ .toggle-btn-primary.active:not([aria-pressed]) {
48
214
  color: var(--color-on-primary-container);
49
215
  background-color: var(--color-primary-container);
50
216
  border-color: var(--color-primary);
51
217
  }
52
218
 
53
219
  /* Secondary variant */
54
- .toggle-btn-secondary.toggle-btn-active,
55
- .toggle-btn-secondary.active {
220
+ .toggle-btn-secondary:is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
221
+ .toggle-btn-secondary.active:not([aria-pressed]) {
56
222
  color: var(--color-on-secondary-container);
57
223
  background-color: var(--color-secondary-container);
58
224
  border-color: var(--color-secondary);
59
225
  }
60
226
 
61
227
  /* Tertiary variant */
62
- .toggle-btn-tertiary.toggle-btn-active,
63
- .toggle-btn-tertiary.active {
228
+ .toggle-btn-tertiary:is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
229
+ .toggle-btn-tertiary.active:not([aria-pressed]) {
64
230
  color: var(--color-on-tertiary-container);
65
231
  background-color: var(--color-tertiary-container);
66
232
  border-color: var(--color-tertiary);
67
233
  }
68
234
 
69
235
  /* Info variant */
70
- .toggle-btn-info.toggle-btn-active,
71
- .toggle-btn-info.active {
236
+ .toggle-btn-info:is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
237
+ .toggle-btn-info.active:not([aria-pressed]) {
72
238
  color: var(--color-on-info-container);
73
239
  background-color: var(--color-info-container);
74
240
  border-color: var(--color-info);
75
241
  }
76
242
 
77
243
  /* Success variant */
78
- .toggle-btn-success.toggle-btn-active,
79
- .toggle-btn-success.active {
244
+ .toggle-btn-success:is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
245
+ .toggle-btn-success.active:not([aria-pressed]) {
80
246
  color: var(--color-on-success-container);
81
247
  background-color: var(--color-success-container);
82
248
  border-color: var(--color-success);
83
249
  }
84
250
 
85
251
  /* Warning variant */
86
- .toggle-btn-warning.toggle-btn-active,
87
- .toggle-btn-warning.active {
252
+ .toggle-btn-warning:is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
253
+ .toggle-btn-warning.active:not([aria-pressed]) {
88
254
  color: var(--color-on-warning-container);
89
255
  background-color: var(--color-warning-container);
90
256
  border-color: var(--color-warning);
91
257
  }
92
258
 
93
259
  /* Error variant */
94
- .toggle-btn-error.toggle-btn-active,
95
- .toggle-btn-error.active {
260
+ .toggle-btn-error:is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
261
+ .toggle-btn-error.active:not([aria-pressed]) {
96
262
  color: var(--color-on-error-container);
97
263
  background-color: var(--color-error-container);
98
264
  border-color: var(--color-error);
99
265
  }
100
266
 
101
267
  /* Accent variant */
102
- .toggle-btn-accent.toggle-btn-active,
103
- .toggle-btn-accent.active {
268
+ .toggle-btn-accent:is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
269
+ .toggle-btn-accent.active:not([aria-pressed]) {
104
270
  color: var(--color-on-surface);
105
271
  background-color: color-mix(in oklch, var(--color-accent) 15%, var(--color-surface));
106
272
  border-color: var(--color-accent);
107
273
  }
108
274
 
109
275
  /* Neutral variant */
110
- .toggle-btn-neutral.toggle-btn-active,
111
- .toggle-btn-neutral.active {
276
+ .toggle-btn-neutral:is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
277
+ .toggle-btn-neutral.active:not([aria-pressed]) {
112
278
  color: var(--color-on-surface);
113
279
  background-color: color-mix(in oklch, var(--color-neutral) 15%, var(--color-surface));
114
280
  border-color: var(--color-neutral);
115
281
  }
116
282
 
117
283
  /* Base variant */
118
- .toggle-btn-base.toggle-btn-active,
119
- .toggle-btn-base.active {
284
+ .toggle-btn-base:is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
285
+ .toggle-btn-base.active:not([aria-pressed]) {
120
286
  color: var(--color-base-content);
121
287
  background-color: var(--color-base-200);
122
288
  border-color: var(--color-base-content);
@@ -245,8 +411,8 @@
245
411
  border-radius: var(--radius-xs);
246
412
  }
247
413
 
248
- .toggle-segmented .toggle-btn.toggle-btn-active,
249
- .toggle-segmented .toggle-btn.active {
414
+ .toggle-segmented .toggle-btn:is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
415
+ .toggle-segmented .toggle-btn.active:not([aria-pressed]) {
250
416
  background-color: var(--color-surface-variant);
251
417
  border-color: transparent;
252
418
  box-shadow: var(--shadow-sm);
@@ -258,8 +424,8 @@
258
424
  padding: 0.5rem 1rem;
259
425
  }
260
426
 
261
- .toggle-chip.toggle-btn-active,
262
- .toggle-chip.active {
427
+ .toggle-chip:is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
428
+ .toggle-chip.active:not([aria-pressed]) {
263
429
  background-color: var(--color-primary-container);
264
430
  border-color: var(--color-primary-container);
265
431
  }
@@ -269,8 +435,8 @@
269
435
  background-color: transparent;
270
436
  }
271
437
 
272
- .toggle-outlined.toggle-btn-active,
273
- .toggle-outlined.active {
438
+ .toggle-outlined:is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
439
+ .toggle-outlined.active:not([aria-pressed]) {
274
440
  background-color: color-mix(in oklch, var(--color-primary) 10%, transparent);
275
441
  }
276
442
 
@@ -280,8 +446,8 @@
280
446
  border: none;
281
447
  }
282
448
 
283
- .toggle-filled.toggle-btn-active,
284
- .toggle-filled.active {
449
+ .toggle-filled:is(.toggle-btn-active:not([aria-pressed]), .toggle-btn[aria-pressed="true"]),
450
+ .toggle-filled.active:not([aria-pressed]) {
285
451
  background-color: var(--color-primary);
286
452
  color: var(--color-primary-content);
287
453
  }
@@ -0,0 +1,66 @@
1
+ /** Opt-in native presentation. Applications own errors, messages and announcements. */
2
+ @layer components {
3
+ /* Compatibility wrapper states are intentionally immediate. */
4
+ :is(.form-group-info, .form-control.info) { --dm-validation-color: var(--color-info); }
5
+ :is(.form-group-warning, .form-control.warning) { --dm-validation-color: var(--color-warning); }
6
+ :is(.form-group-success, .form-control.success) { --dm-validation-color: var(--color-success); }
7
+
8
+ :is(.input, .select, .textarea, .checkbox, .radio, .switch, .toggle, .file-input, .otp-input-field, .otp-code, .datepicker-input):is(.validate :valid, .validate:valid, .validator.validator-success:user-valid):not([aria-invalid="true"]):not(:where(.form-group-error *, .form-control.error *)):not(:disabled) {
9
+ --dm-validation-color: var(--color-success);
10
+ --dm-validation-content: var(--color-success-content);
11
+ }
12
+
13
+ :is(.input, .select, .textarea, .checkbox, .radio, .switch, .toggle, .file-input, .otp-input-field, .otp-code, .datepicker-input):is(.validate :invalid, .validate:invalid, .validator:user-invalid):not(:disabled) {
14
+ --dm-validation-color: var(--color-error);
15
+ --dm-validation-content: var(--color-error-content);
16
+ }
17
+
18
+ :is(.form-group-error, .form-control.error) {
19
+ --dm-validation-color: var(--color-error);
20
+ --dm-validation-content: var(--color-error-content);
21
+ }
22
+
23
+ /* Higher specificity than native states, including server-invalid + user-valid. */
24
+ :is(.input, .select, .textarea, .checkbox, .radio, .switch, .toggle, .file-input, .otp-input-field, .otp-code, .datepicker-input):is([aria-invalid="true"], .form-group-error *, .form-control.error *):not(:disabled):is(:focus, :not(:focus)) {
25
+ --dm-validation-color: var(--color-error);
26
+ --dm-validation-content: var(--color-error-content);
27
+ }
28
+
29
+ /* This shared selector wins over filled/ghost focus and semantic modifiers. */
30
+ :is(.input, .select, .textarea, .checkbox, .radio, .switch, .toggle, .file-input, .otp-input-field, .otp-code, .datepicker-input):is([aria-invalid="true"], .validator:user-invalid, .validator.validator-success:user-valid, .validate :invalid, .validate :valid, .validate:invalid, .validate:valid, .form-group-error *, .form-group-success *, .form-group-warning *, .form-group-info *, .form-control.error *, .form-control.success *, .form-control.warning *, .form-control.info *):not(:disabled) {
31
+ color: var(--dm-validation-color);
32
+ border-color: var(--dm-validation-color);
33
+ --checkbox-color: var(--dm-validation-color);
34
+ --radio-color: var(--dm-validation-color);
35
+ --switch-color: var(--dm-validation-color);
36
+ --switch-content-color: var(--dm-validation-content, var(--color-primary-content));
37
+ --toggle-color: var(--dm-validation-color);
38
+ }
39
+
40
+ :is(.input, .select, .textarea, .checkbox, .radio, .switch, .toggle, .file-input, .otp-input-field, .otp-code, .datepicker-input):is([aria-invalid="true"], .validator:user-invalid, .validator.validator-success:user-valid, .validate :invalid, .validate :valid, .validate:invalid, .validate:valid, .form-group-error *, .form-group-success *, .form-group-warning *, .form-group-info *, .form-control.error *, .form-control.success *, .form-control.warning *, .form-control.info *):not(:disabled):focus {
41
+ border-color: var(--dm-validation-color);
42
+ box-shadow: 0 0 0 3px color-mix(in oklch, var(--dm-validation-color) 20%, transparent);
43
+ }
44
+
45
+ :is(.form-group-error, .form-control.error) :is(.form-label, .label-text) { color: var(--color-error); }
46
+ :is(.form-group-success, .form-control.success) :is(.form-label, .label-text) { color: var(--color-success); }
47
+ :is(.form-group-warning, .form-control.warning) :is(.form-label, .label-text) { color: var(--color-warning); }
48
+ :is(.form-group-info, .form-control.info) :is(.form-label, .label-text) { color: var(--color-info); }
49
+
50
+ .validator-hint { font-size: 0.75rem; color: var(--color-on-surface-variant); }
51
+ .validator-error { display: none; font-size: 0.75rem; color: var(--color-error); }
52
+ /* Keep OTP actions stationary when blur reveals an error during a click. */
53
+ .otp-code ~ .validator-error { display: block; visibility: hidden; }
54
+ :is(.form-group, .form-control):has(:is([aria-invalid="true"], .validator:user-invalid, .validate :invalid, .validate:invalid):not(:disabled)) > .validator-error,
55
+ :is(.form-group-error, .form-control.error) > .validator-error { display: block; visibility: visible; }
56
+
57
+ @media (forced-colors: active) {
58
+ :is(input, select, textarea):is(.input, .select, .textarea, .checkbox, .radio, .switch, .toggle, .file-input, .otp-input-field, .otp-code, .datepicker-input):focus-visible {
59
+ outline: 2px solid Highlight;
60
+ outline-offset: 2px;
61
+ }
62
+ input:is(.checkbox, .radio, .switch, .toggle) { appearance: auto; }
63
+ input:is(.checkbox, .radio, .switch, .toggle)::before,
64
+ input:is(.checkbox, .radio, .switch, .toggle)::after { content: none; }
65
+ }
66
+ }
@@ -0,0 +1,22 @@
1
+ @layer components {
2
+ .aura {
3
+ position: relative;
4
+ isolation: isolate;
5
+ border-radius: var(--radius-md);
6
+ outline: 1px solid var(--color-primary);
7
+ }
8
+ .aura::before {
9
+ content: '';
10
+ position: absolute;
11
+ inset: 0;
12
+ z-index: -1;
13
+ border-radius: inherit;
14
+ box-shadow: 0 0 1rem color-mix(in oklch, var(--color-primary) 35%, transparent);
15
+ pointer-events: none;
16
+ }
17
+ @media (prefers-reduced-motion: no-preference) {
18
+ .aura-animated::before { animation: dm-aura 4s ease-in-out infinite; }
19
+ }
20
+ @keyframes dm-aura { 50% { opacity: 0.4; } }
21
+ @media print { .aura::before { display: none; } }
22
+ }
@@ -0,0 +1,8 @@
1
+ @layer components {
2
+ .hover-3d { border-radius: var(--radius-md); }
3
+ @media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
4
+ .hover-3d { transition: transform 200ms ease; }
5
+ .hover-3d:hover:not(:focus-within) { transform: perspective(60rem) rotateX(var(--hover-3d-x, 2deg)) rotateY(var(--hover-3d-y, -2deg)); }
6
+ }
7
+ @media print { .hover-3d { transform: none; } }
8
+ }
@@ -0,0 +1,14 @@
1
+ @layer components {
2
+ .hover-gallery { display: grid; gap: 0.5rem; min-inline-size: 0; color: var(--color-on-surface); }
3
+ .hover-gallery-stage { aspect-ratio: var(--hover-gallery-ratio, 4 / 3); overflow: hidden; border-radius: var(--radius-md); }
4
+ .hover-gallery-stage img { inline-size: 100%; block-size: 100%; object-fit: cover; }
5
+ .hover-gallery-controls { display: flex; flex-wrap: wrap; gap: 0.5rem; }
6
+ .hover-gallery-controls > button { border: 1px solid currentColor; color: inherit; background: var(--color-surface-container); padding: 0.25rem; border-radius: var(--radius-sm); cursor: pointer; }
7
+ .hover-gallery-controls img { display: block; inline-size: 3rem; block-size: 3rem; object-fit: cover; }
8
+ .hover-gallery-controls > button[aria-pressed="true"] { color: var(--color-primary); outline: 2px solid currentColor; }
9
+ .hover-gallery-controls > button:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
10
+ @media (hover: hover) and (prefers-reduced-motion: no-preference) {
11
+ .hover-gallery-controls > button:hover { background: var(--color-primary-container); }
12
+ }
13
+ @media print { .hover-gallery-controls { display: none; } }
14
+ }
@@ -0,0 +1,65 @@
1
+ /* Explicitly opt-in. Not imported by core or components/index.css. */
2
+ @layer components {
3
+ .aura {
4
+ position: relative;
5
+ isolation: isolate;
6
+ border-radius: var(--radius-md);
7
+ outline: 1px solid var(--color-primary);
8
+ }
9
+ .aura::before {
10
+ content: '';
11
+ position: absolute;
12
+ inset: 0;
13
+ z-index: -1;
14
+ border-radius: inherit;
15
+ box-shadow: 0 0 1rem color-mix(in oklch, var(--color-primary) 35%, transparent);
16
+ pointer-events: none;
17
+ }
18
+ @media (prefers-reduced-motion: no-preference) {
19
+ .aura-animated::before { animation: dm-aura 4s ease-in-out infinite; }
20
+ }
21
+ @keyframes dm-aura { 50% { opacity: 0.4; } }
22
+ @media print { .aura::before { display: none; } }
23
+ }
24
+
25
+ @layer components {
26
+ .hover-3d { border-radius: var(--radius-md); }
27
+ @media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
28
+ .hover-3d { transition: transform 200ms ease; }
29
+ .hover-3d:hover:not(:focus-within) { transform: perspective(60rem) rotateX(var(--hover-3d-x, 2deg)) rotateY(var(--hover-3d-y, -2deg)); }
30
+ }
31
+ @media print { .hover-3d { transform: none; } }
32
+ }
33
+
34
+ @layer components {
35
+ .hover-gallery { display: grid; gap: 0.5rem; min-inline-size: 0; color: var(--color-on-surface); }
36
+ .hover-gallery-stage { aspect-ratio: var(--hover-gallery-ratio, 4 / 3); overflow: hidden; border-radius: var(--radius-md); }
37
+ .hover-gallery-stage img { inline-size: 100%; block-size: 100%; object-fit: cover; }
38
+ .hover-gallery-controls { display: flex; flex-wrap: wrap; gap: 0.5rem; }
39
+ .hover-gallery-controls > button { border: 1px solid currentColor; color: inherit; background: var(--color-surface-container); padding: 0.25rem; border-radius: var(--radius-sm); cursor: pointer; }
40
+ .hover-gallery-controls img { display: block; inline-size: 3rem; block-size: 3rem; object-fit: cover; }
41
+ .hover-gallery-controls > button[aria-pressed="true"] { color: var(--color-primary); outline: 2px solid currentColor; }
42
+ .hover-gallery-controls > button:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
43
+ @media (hover: hover) and (prefers-reduced-motion: no-preference) {
44
+ .hover-gallery-controls > button:hover { background: var(--color-primary-container); }
45
+ }
46
+ @media print { .hover-gallery-controls { display: none; } }
47
+ }
48
+
49
+ @layer components {
50
+ .text-rotate { display: inline-grid; color: var(--color-on-surface); vertical-align: baseline; }
51
+ .text-rotate > span { grid-area: 1 / 1; visibility: hidden; }
52
+ .text-rotate > span:first-child { visibility: visible; }
53
+ @media (prefers-reduced-motion: no-preference) {
54
+ .text-rotate-animated > span { animation: dm-text-rotate var(--text-rotate-duration, 6s) steps(1, end) infinite; }
55
+ .text-rotate-animated > span:nth-child(2) { animation-delay: calc(var(--text-rotate-duration, 6s) / -3); }
56
+ .text-rotate-animated > span:nth-child(3) { animation-delay: calc(var(--text-rotate-duration, 6s) / -3 * 2); }
57
+ .text-rotate-animated:is(:hover, :focus-within, .text-rotate-paused) > span { animation-play-state: paused; }
58
+ }
59
+ @keyframes dm-text-rotate { 0%, 33.32% { visibility: visible; } 33.33%, 100% { visibility: hidden; } }
60
+ @media print {
61
+ .text-rotate > span { animation: none; visibility: hidden; }
62
+ .text-rotate > span:first-child { visibility: visible; }
63
+ }
64
+ }
65
+
@@ -0,0 +1,16 @@
1
+ @layer components {
2
+ .text-rotate { display: inline-grid; color: var(--color-on-surface); vertical-align: baseline; }
3
+ .text-rotate > span { grid-area: 1 / 1; visibility: hidden; }
4
+ .text-rotate > span:first-child { visibility: visible; }
5
+ @media (prefers-reduced-motion: no-preference) {
6
+ .text-rotate-animated > span { animation: dm-text-rotate var(--text-rotate-duration, 6s) steps(1, end) infinite; }
7
+ .text-rotate-animated > span:nth-child(2) { animation-delay: calc(var(--text-rotate-duration, 6s) / -3); }
8
+ .text-rotate-animated > span:nth-child(3) { animation-delay: calc(var(--text-rotate-duration, 6s) / -3 * 2); }
9
+ .text-rotate-animated:is(:hover, :focus-within, .text-rotate-paused) > span { animation-play-state: paused; }
10
+ }
11
+ @keyframes dm-text-rotate { 0%, 33.32% { visibility: visible; } 33.33%, 100% { visibility: hidden; } }
12
+ @media print {
13
+ .text-rotate > span { animation: none; visibility: hidden; }
14
+ .text-rotate > span:first-child { visibility: visible; }
15
+ }
16
+ }
@@ -43,7 +43,7 @@ export const css = `/**
43
43
  background-color: transparent;
44
44
  border: none;
45
45
  cursor: pointer;
46
- text-align: left;
46
+ text-align: start;
47
47
  transition: background-color 150ms ease-in-out;
48
48
  }
49
49
 
@@ -57,7 +57,8 @@ export const css = `/**
57
57
  box-shadow: 0 0 0 3px color-mix(in oklch, currentColor 20%, transparent);
58
58
  }
59
59
 
60
- .accordion-item.open .accordion-header {
60
+ .accordion-item:not(details):is(.open, .accordion-item-open) > .accordion-header,
61
+ details.accordion-item[open] > .accordion-header {
61
62
  background-color: var(--color-surface-container);
62
63
  }
63
64
 
@@ -68,7 +69,7 @@ export const css = `/**
68
69
  justify-content: center;
69
70
  width: 1.5rem;
70
71
  height: 1.5rem;
71
- margin-right: 0.75rem;
72
+ margin-inline-end: 0.75rem;
72
73
  color: var(--color-on-surface-variant);
73
74
  flex-shrink: 0;
74
75
  }
@@ -93,13 +94,14 @@ export const css = `/**
93
94
  justify-content: center;
94
95
  width: 1.5rem;
95
96
  height: 1.5rem;
96
- margin-left: auto;
97
+ margin-inline-start: auto;
97
98
  color: var(--color-on-surface-variant);
98
99
  transition: transform 200ms ease-in-out;
99
100
  flex-shrink: 0;
100
101
  }
101
102
 
102
- .accordion-item.open .accordion-expand {
103
+ .accordion-item:not(details):is(.open, .accordion-item-open) > .accordion-header > .accordion-expand,
104
+ details.accordion-item[open] > .accordion-header > .accordion-expand {
103
105
  transform: rotate(180deg);
104
106
  }
105
107
 
@@ -110,12 +112,14 @@ export const css = `/**
110
112
  transition: grid-template-rows 200ms ease-in-out;
111
113
  }
112
114
 
113
- .accordion-item.open .accordion-content {
115
+ .accordion-item:not(details):is(.open, .accordion-item-open) > .accordion-content,
116
+ details.accordion-item[open] > .accordion-content {
114
117
  grid-template-rows: 1fr;
115
118
  }
116
119
 
117
120
  .accordion-body {
118
121
  overflow: hidden;
122
+ min-block-size: 0;
119
123
  }
120
124
 
121
125
  .accordion-body-inner {
@@ -153,7 +157,8 @@ export const css = `/**
153
157
  }
154
158
 
155
159
  .accordion-filled .accordion-header:hover,
156
- .accordion-filled .accordion-item.open .accordion-header {
160
+ .accordion-filled > .accordion-item:not(details):is(.open, .accordion-item-open) > .accordion-header,
161
+ .accordion-filled > details.accordion-item[open] > .accordion-header {
157
162
  background-color: var(--color-surface-container-high);
158
163
  }
159
164
 
@@ -225,15 +230,34 @@ export const css = `/**
225
230
  }
226
231
 
227
232
  /* Color Variants */
228
- .accordion-primary .accordion-item.open .accordion-header {
233
+ .accordion-primary > .accordion-item:not(details):is(.open, .accordion-item-open) > .accordion-header,
234
+ .accordion-primary > details.accordion-item[open] > .accordion-header {
229
235
  background-color: var(--color-primary-container);
230
236
  color: var(--color-on-primary-container);
231
237
  }
232
238
 
233
- .accordion-primary .accordion-item.open .accordion-expand {
239
+ .accordion-primary > .accordion-item:not(details):is(.open, .accordion-item-open) > .accordion-header > .accordion-expand,
240
+ .accordion-primary > details.accordion-item[open] > .accordion-header > .accordion-expand {
234
241
  color: var(--color-on-primary-container);
235
242
  }
236
243
 
244
+ .accordion-outlined { border: 1px solid var(--color-outline-variant); }
245
+ .accordion-comfortable .accordion-header { padding: 1.25rem; }
246
+ .accordion-header-icon { display: flex; align-items: center; gap: 0.75rem; }
247
+ .accordion-header-icon-leading { inline-size: 1.25rem; block-size: 1.25rem; flex: none; }
248
+ .accordion-item-disabled > .accordion-header { opacity: 0.6; cursor: not-allowed; }
249
+ .accordion-no-animation .accordion-content, .accordion-no-animation .accordion-expand { transition: none; }
250
+ .accordion-secondary > .accordion-item:not(details):is(.open, .accordion-item-open) > .accordion-header,
251
+ .accordion-secondary > details.accordion-item[open] > .accordion-header { color: var(--color-secondary); }
252
+ .accordion-tertiary > .accordion-item:not(details):is(.open, .accordion-item-open) > .accordion-header,
253
+ .accordion-tertiary > details.accordion-item[open] > .accordion-header { color: var(--color-tertiary); }
254
+ details.accordion-item > summary { list-style: none; }
255
+ details.accordion-item > summary::-webkit-details-marker { display: none; }
256
+ details.accordion-item:not([open]) > .accordion-content,
257
+ .accordion-item:not(details):not(.open):not(.accordion-item-open) > .accordion-content,
258
+ .accordion-content[hidden] { display: none; }
259
+ .accordion-title, .accordion-body-inner { min-inline-size: 0; overflow-wrap: anywhere; }
260
+
237
261
  /* Reduce Motion */
238
262
  @media (prefers-reduced-motion: reduce) {
239
263
  .accordion-content,