@expressivecss/expressive 0.1.0-alpha.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/LICENSE +82 -2
  2. package/README.md +153 -43
  3. package/dist/css/expressive.css +7066 -9658
  4. package/dist/css/expressive.css.map +1 -0
  5. package/dist/css/expressive.min.css +1 -1
  6. package/dist/css/expressive.min.css.map +1 -0
  7. package/dist/js/expressive.cjs +7451 -0
  8. package/dist/js/expressive.cjs.map +7 -0
  9. package/dist/js/expressive.js +7313 -8099
  10. package/dist/js/expressive.js.map +7 -1
  11. package/dist/js/expressive.min.js +75 -1
  12. package/dist/js/expressive.min.js.map +7 -1
  13. package/dist/js/expressive.mjs +7222 -7998
  14. package/dist/js/expressive.mjs.map +7 -1
  15. package/dist/{js → types}/components/autocomplete.d.ts +10 -1
  16. package/dist/{js → types}/components/buttons.d.ts +11 -1
  17. package/dist/{js → types}/components/cards.d.ts +10 -1
  18. package/dist/{js → types}/components/carousel.d.ts +4 -5
  19. package/dist/{js/forms/character-counter.d.ts → types/components/characterCounter.d.ts} +1 -1
  20. package/dist/{js → types}/components/chips.d.ts +1 -1
  21. package/dist/{js → types}/components/collapsible.d.ts +1 -1
  22. package/dist/{js → types}/components/datepicker.d.ts +63 -2
  23. package/dist/{js → types}/components/dropdown.d.ts +3 -3
  24. package/dist/types/components/index.d.ts +23 -0
  25. package/dist/{js/components/materialbox.d.ts → types/components/lightbox.d.ts} +21 -21
  26. package/dist/{js → types}/components/modal.d.ts +1 -1
  27. package/dist/{js → types}/components/parallax.d.ts +11 -5
  28. package/dist/{js → types}/components/pushpin.d.ts +1 -1
  29. package/dist/{js/forms → types/components}/range.d.ts +3 -3
  30. package/dist/types/components/registry.d.ts +107 -0
  31. package/dist/{js → types}/components/scrollspy.d.ts +6 -9
  32. package/dist/{js/forms → types/components}/select.d.ts +11 -2
  33. package/dist/{js → types}/components/sidenav.d.ts +1 -1
  34. package/dist/{js → types}/components/slider.d.ts +3 -2
  35. package/dist/{js → types}/components/tabs.d.ts +3 -2
  36. package/dist/{js/components/tap-target.d.ts → types/components/tapTarget.d.ts} +2 -2
  37. package/dist/{js → types}/components/timepicker.d.ts +13 -5
  38. package/dist/{js/components/toast.d.ts → types/components/toasts.d.ts} +28 -4
  39. package/dist/{js → types}/components/tooltip.d.ts +2 -2
  40. package/dist/types/core/bounding.d.ts +6 -0
  41. package/dist/{js/foundation → types/core}/component.d.ts +1 -1
  42. package/dist/types/core/edges.d.ts +6 -0
  43. package/dist/{js/foundation → types/core}/utils.d.ts +21 -14
  44. package/dist/types/index.d.ts +6 -0
  45. package/dist/{js/plugins/docked-display.d.ts → types/plugins/dockedDisplayPlugin.d.ts} +7 -0
  46. package/package.json +60 -36
  47. package/src/sass/README.md +200 -0
  48. package/src/sass/abstracts/_breakpoints.scss +69 -0
  49. package/src/sass/abstracts/_elevation.scss +34 -0
  50. package/src/sass/abstracts/_index.scss +7 -0
  51. package/src/sass/abstracts/_mixins.scss +171 -0
  52. package/src/sass/abstracts/_variables.scss +57 -0
  53. package/src/{scss/layout/_table.scss → sass/base/_global.scss} +64 -2
  54. package/src/{scss/layout → sass/base}/_grid.scss +6 -6
  55. package/src/sass/base/_index.scss +6 -0
  56. package/src/{scss/foundation → sass/base}/_normalize.scss +51 -139
  57. package/src/sass/base/_typography.scss +90 -0
  58. package/src/sass/components/_badges.scss +77 -0
  59. package/src/{scss → sass}/components/_breadcrumb.scss +2 -0
  60. package/src/sass/components/_buttons.scss +407 -0
  61. package/src/sass/components/_cards.scss +328 -0
  62. package/src/{scss → sass}/components/_carousel.scss +5 -3
  63. package/src/sass/components/_chips.scss +140 -0
  64. package/src/sass/components/_collapsible.scss +81 -0
  65. package/src/{scss → sass}/components/_collection.scss +2 -2
  66. package/src/{scss/components/_date-picker.scss → sass/components/_datepicker.scss} +51 -44
  67. package/src/sass/components/_docked-display.scss +11 -0
  68. package/src/sass/components/_dropdown.scss +129 -0
  69. package/src/{scss/components/_material-icons.scss → sass/components/_icons-material-design.scss} +2 -0
  70. package/src/sass/components/_index.scss +35 -0
  71. package/src/{scss/components/_material-box.scss → sass/components/_lightbox.scss} +6 -4
  72. package/src/sass/components/_modal.scss +144 -0
  73. package/src/sass/components/_navbar.scss +345 -0
  74. package/src/{scss/layout/_footer.scss → sass/components/_page-footer.scss} +7 -6
  75. package/src/{scss → sass}/components/_pagination.scss +4 -3
  76. package/src/{scss → sass}/components/_parallax.scss +4 -1
  77. package/src/{scss → sass}/components/_preloader.scss +19 -97
  78. package/src/{scss → sass}/components/_pulse.scss +2 -0
  79. package/src/sass/components/_pushpin.scss +11 -0
  80. package/src/{scss → sass}/components/_sidenav.scss +99 -82
  81. package/src/{scss → sass}/components/_slider.scss +3 -1
  82. package/src/{scss/components/_table-of-contents.scss → sass/components/_table_of_contents.scss} +2 -0
  83. package/src/sass/components/_tabs.scss +232 -0
  84. package/src/{scss/components/_tap-target.scss → sass/components/_tapTarget.scss} +24 -22
  85. package/src/{scss/components/_time-picker.scss → sass/components/_timepicker.scss} +56 -56
  86. package/src/sass/components/_toast.scss +260 -0
  87. package/src/sass/components/_toolbar.scss +192 -0
  88. package/src/sass/components/_tooltip.scss +166 -0
  89. package/src/{scss → sass}/components/_transitions.scss +4 -4
  90. package/src/sass/components/forms/_checkboxes.scss +288 -0
  91. package/src/sass/components/forms/_fieldset.scss +128 -0
  92. package/src/{scss → sass/components}/forms/_file-input.scss +11 -9
  93. package/src/{scss → sass/components}/forms/_index.scss +2 -0
  94. package/src/sass/components/forms/_input-fields.scss +326 -0
  95. package/src/sass/components/forms/_radio-buttons.scss +190 -0
  96. package/src/sass/components/forms/_range.scss +310 -0
  97. package/src/sass/components/forms/_select.scss +103 -0
  98. package/src/sass/components/forms/_switches.scss +239 -0
  99. package/src/sass/expressive.scss +60 -0
  100. package/src/sass/tokens/_index.scss +4 -0
  101. package/src/sass/tokens/_reference.scss +265 -0
  102. package/src/sass/tokens/_theme.scss +49 -0
  103. package/src/{scss → sass}/utilities/_helpers.scss +33 -30
  104. package/src/sass/utilities/_index.scss +8 -0
  105. package/src/{scss → sass}/utilities/_spacing.scss +4 -3
  106. package/src/sass/utilities/_typescale.scss +45 -0
  107. package/src/sass/utilities/_visibility.scss +63 -0
  108. package/src/sass/utilities/_z-depth.scss +18 -0
  109. package/dist/js/components/index.d.ts +0 -21
  110. package/dist/js/forms/index.d.ts +0 -4
  111. package/dist/js/foundation/index.d.ts +0 -2
  112. package/dist/js/index.d.ts +0 -52
  113. package/dist/js/plugins/index.d.ts +0 -1
  114. package/src/scss/components/_appbar.scss +0 -454
  115. package/src/scss/components/_badges.scss +0 -77
  116. package/src/scss/components/_buttons.scss +0 -412
  117. package/src/scss/components/_cards.scss +0 -267
  118. package/src/scss/components/_chips.scss +0 -147
  119. package/src/scss/components/_collapsible.scss +0 -84
  120. package/src/scss/components/_dropdown.scss +0 -98
  121. package/src/scss/components/_index.scss +0 -28
  122. package/src/scss/components/_modal.scss +0 -84
  123. package/src/scss/components/_tabs.scss +0 -176
  124. package/src/scss/components/_toast.scss +0 -70
  125. package/src/scss/components/_tooltip.scss +0 -49
  126. package/src/scss/components/_video.scss +0 -15
  127. package/src/scss/expressive.scss +0 -7
  128. package/src/scss/forms/_checkboxes.scss +0 -199
  129. package/src/scss/forms/_input-fields.scss +0 -360
  130. package/src/scss/forms/_radio-buttons.scss +0 -114
  131. package/src/scss/forms/_range.scss +0 -148
  132. package/src/scss/forms/_select.scss +0 -108
  133. package/src/scss/forms/_switches.scss +0 -127
  134. package/src/scss/foundation/_base.scss +0 -71
  135. package/src/scss/foundation/_color-palette.scss +0 -402
  136. package/src/scss/foundation/_index.scss +0 -10
  137. package/src/scss/foundation/_mixins.scss +0 -198
  138. package/src/scss/foundation/_motion.scss +0 -70
  139. package/src/scss/foundation/_shape.scss +0 -30
  140. package/src/scss/foundation/_state-layers.scss +0 -68
  141. package/src/scss/foundation/_theme.scss +0 -238
  142. package/src/scss/foundation/_tokens.scss +0 -511
  143. package/src/scss/foundation/_variables.scss +0 -57
  144. package/src/scss/layout/_index.scss +0 -3
  145. package/src/scss/utilities/_a11y.scss +0 -77
  146. package/src/scss/utilities/_elevation.scss +0 -63
  147. package/src/scss/utilities/_index.scss +0 -7
  148. package/src/scss/utilities/_responsive.scss +0 -62
  149. package/src/scss/utilities/_typography.scss +0 -115
  150. /package/dist/{js/forms → types/behaviors}/forms.d.ts +0 -0
  151. /package/dist/{js/components → types/behaviors}/waves.d.ts +0 -0
  152. /package/src/{scss → sass}/utilities/_colors.scss +0 -0
@@ -0,0 +1,326 @@
1
+ @use "../../abstracts" as *;
2
+
3
+ // Text fields.
4
+ //
5
+ // Anatomy is the HTML. .field (or .input-field) is the container. The
6
+ // <label> after the control is the floating label. A leading <i> is the
7
+ // leading icon. <small> is supporting text. .outlined / .border is the
8
+ // outlined variant; the default is filled.
9
+ //
10
+ // Tokens follow https://m3.material.io/components/text-fields/specs
11
+ // filled surface-variant well, 4dp top corners, 1dp/2dp bottom indicator
12
+ // outlined 1dp/2dp outline, 4dp corners
13
+ // height 56dp
14
+ // label body-large rest, body-small floated
15
+ // input body-large / on-surface
16
+ // supporting body-small / on-surface-variant
17
+ // icons 24dp, 12dp from the edge
18
+ //
19
+ // placeholder=" " (one space) lets the label float with CSS only.
20
+
21
+ ::placeholder {
22
+ color: var(--md-sys-color-on-surface-variant);
23
+ }
24
+
25
+ $_text-inputs: "input:not([type]):not(.browser-default), input[type=text]:not(.browser-default), input[type=password]:not(.browser-default), input[type=email]:not(.browser-default), input[type=url]:not(.browser-default), input[type=time]:not(.browser-default), input[type=date]:not(.browser-default), input[type=datetime]:not(.browser-default), input[type=datetime-local]:not(.browser-default), input[type=month]:not(.browser-default), input[type=tel]:not(.browser-default), input[type=number]:not(.browser-default), input[type=search]:not(.browser-default), textarea.expressive-textarea";
26
+
27
+ #{$_text-inputs} {
28
+ outline: none;
29
+ color: var(--md-sys-color-on-surface);
30
+ width: 100%;
31
+ height: 56px;
32
+ background-color: transparent;
33
+ @include typescale("body-large");
34
+ font-family: $font-stack;
35
+ }
36
+
37
+ .field,
38
+ .input-field {
39
+ --md-comp-filled-text-field-container-color: var(--md-sys-color-surface-variant);
40
+ --md-comp-filled-text-field-caret-color: var(--md-sys-color-primary);
41
+ --input-color: var(--md-comp-filled-text-field-caret-color);
42
+
43
+ position: relative;
44
+ clear: both;
45
+
46
+ input:not([type="range"]),
47
+ textarea {
48
+ box-sizing: border-box;
49
+ padding: 20px 16px 8px;
50
+ border: none;
51
+ border-radius: 4px 4px 0 0;
52
+ border-bottom: 1px solid var(--md-sys-color-on-surface-variant);
53
+ background-color: var(--md-comp-filled-text-field-container-color);
54
+ caret-color: var(--input-color);
55
+
56
+ &:focus:not([readonly]) {
57
+ border-bottom-width: 2px;
58
+ border-bottom-color: var(--input-color);
59
+ padding-bottom: 7px;
60
+ }
61
+
62
+ &:disabled,
63
+ &[readonly="readonly"] {
64
+ color: color-mix(in oklab, var(--md-sys-color-on-surface) 38%, transparent);
65
+ border-color: color-mix(in oklab, var(--md-sys-color-on-surface) 12%, transparent);
66
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 4%, transparent);
67
+ }
68
+
69
+ &:focus:not([readonly]) + label,
70
+ &:focus:not([readonly]) + span:not(.supporting-text, .character-counter) {
71
+ color: var(--input-color);
72
+ }
73
+
74
+ &:focus:not([readonly]) + label,
75
+ &:not([placeholder=" "]) + label,
76
+ &:not(:placeholder-shown) + label,
77
+ &:focus:not([readonly]) + span:not(.supporting-text, .character-counter),
78
+ &:not([placeholder=" "]) + span:not(.supporting-text, .character-counter),
79
+ &:not(:placeholder-shown) + span:not(.supporting-text, .character-counter) {
80
+ transform: scale(calc(12 / 16));
81
+ top: 8px;
82
+ }
83
+
84
+ &:disabled + label,
85
+ &[readonly="readonly"] + label {
86
+ color: color-mix(in oklab, var(--md-sys-color-on-surface) 38%, transparent);
87
+ }
88
+
89
+ &.invalid ~ .supporting-text[data-error],
90
+ &[aria-invalid="true"] ~ .supporting-text[data-error],
91
+ &.invalid ~ small[data-error],
92
+ &[aria-invalid="true"] ~ small[data-error] {
93
+ > span { display: none; }
94
+ }
95
+
96
+ &.invalid,
97
+ &[aria-invalid="true"] {
98
+ border-bottom-color: var(--md-sys-color-error);
99
+ box-shadow: 0 1px 0 0 var(--md-sys-color-error);
100
+ }
101
+
102
+ &.invalid ~ .supporting-text::after,
103
+ &[aria-invalid="true"] ~ .supporting-text::after,
104
+ &.invalid ~ small::after,
105
+ &[aria-invalid="true"] ~ small::after {
106
+ content: attr(data-error);
107
+ color: var(--md-sys-color-error);
108
+ }
109
+
110
+ &.invalid ~ label,
111
+ &:focus.invalid ~ label,
112
+ &[aria-invalid="true"] ~ label {
113
+ color: var(--md-sys-color-error);
114
+ }
115
+ }
116
+
117
+ input::placeholder {
118
+ user-select: none;
119
+ }
120
+
121
+ > label,
122
+ > span:not(.supporting-text, .character-counter, .file-path) {
123
+ color: var(--md-sys-color-on-surface-variant);
124
+ user-select: none;
125
+ position: absolute;
126
+ left: 16px;
127
+ top: 16px;
128
+ cursor: text;
129
+ transform-origin: top left;
130
+ pointer-events: none;
131
+ @include typescale("body-large");
132
+ font-family: $font-stack;
133
+ transition: left 0.2s ease-out, top 0.2s ease-out, transform 0.2s ease-out, color 0.2s ease-out;
134
+ }
135
+
136
+ > small,
137
+ > .supporting-text {
138
+ display: block;
139
+ margin-top: 4px;
140
+ padding: 0 16px;
141
+ color: var(--md-sys-color-on-surface-variant);
142
+ @include typescale("body-small");
143
+ font-family: $font-stack;
144
+ }
145
+
146
+ > .character-counter {
147
+ float: right;
148
+ margin-top: 4px;
149
+ padding: 0 16px;
150
+ color: var(--md-sys-color-on-surface-variant);
151
+ @include typescale("body-small");
152
+ font-family: $font-stack;
153
+ }
154
+
155
+ > i:first-child:not(.suffix),
156
+ > .prefix {
157
+ position: absolute;
158
+ left: 12px;
159
+ top: 16px;
160
+ display: flex;
161
+ align-items: center;
162
+ font-size: 24px;
163
+ width: 24px;
164
+ height: 24px;
165
+ line-height: 24px;
166
+ color: var(--md-sys-color-on-surface-variant);
167
+ user-select: none;
168
+ pointer-events: none;
169
+ }
170
+
171
+ > .suffix,
172
+ > i.suffix {
173
+ position: absolute;
174
+ right: 12px;
175
+ top: 16px;
176
+ display: flex;
177
+ align-items: center;
178
+ font-size: 24px;
179
+ width: 24px;
180
+ height: 24px;
181
+ line-height: 24px;
182
+ color: var(--md-sys-color-on-surface-variant);
183
+ user-select: none;
184
+ }
185
+
186
+ > i:first-child:not(.suffix) ~ input,
187
+ > i:first-child:not(.suffix) ~ textarea,
188
+ > .prefix ~ input,
189
+ > .prefix ~ textarea {
190
+ padding-left: 52px;
191
+ }
192
+
193
+ > .suffix ~ input,
194
+ > .suffix ~ textarea,
195
+ > i.suffix ~ input,
196
+ > i.suffix ~ textarea {
197
+ padding-right: 52px;
198
+ }
199
+
200
+ > i:first-child:not(.suffix) ~ label,
201
+ > i:first-child:not(.suffix) ~ span:not(.supporting-text, .character-counter),
202
+ > .prefix ~ label {
203
+ left: 52px;
204
+ }
205
+
206
+ &.outlined,
207
+ &.border {
208
+ > input,
209
+ > textarea {
210
+ padding-top: 8px;
211
+ padding-bottom: 8px;
212
+ background-color: transparent;
213
+ border: 1px solid var(--md-sys-color-outline);
214
+ border-radius: 4px;
215
+
216
+ &:focus:not([readonly]) {
217
+ border-width: 2px;
218
+ border-color: var(--input-color);
219
+ padding-top: 7px;
220
+ padding-bottom: 7px;
221
+ }
222
+
223
+ &:focus:not([readonly]) + label,
224
+ &:not([placeholder=" "]) + label,
225
+ &:not(:placeholder-shown) + label,
226
+ &:focus:not([readonly]) + span:not(.supporting-text, .character-counter),
227
+ &:not([placeholder=" "]) + span:not(.supporting-text, .character-counter),
228
+ &:not(:placeholder-shown) + span:not(.supporting-text, .character-counter) {
229
+ top: -8px;
230
+ left: 16px;
231
+ margin-left: -4px;
232
+ padding: 0 4px;
233
+ background-color: var(--md-sys-color-background);
234
+ }
235
+
236
+ &:disabled,
237
+ &[readonly="readonly"] {
238
+ border-color: color-mix(in oklab, var(--md-sys-color-on-surface) 12%, transparent);
239
+ background-color: transparent;
240
+ }
241
+
242
+ &.invalid,
243
+ &[aria-invalid="true"] {
244
+ border-color: var(--md-sys-color-error);
245
+ box-shadow: none;
246
+ }
247
+ }
248
+ }
249
+ }
250
+
251
+ .inline {
252
+ display: inline-block;
253
+ }
254
+
255
+ .searchbar {
256
+ .prefix {
257
+ position: absolute;
258
+ padding-left: 1rem;
259
+ top: 0;
260
+ user-select: none;
261
+ display: flex;
262
+ align-self: center;
263
+ }
264
+
265
+ > input {
266
+ border-width: 0;
267
+ background-color: transparent;
268
+ padding-left: 3rem;
269
+ }
270
+ }
271
+
272
+ .searchbar.has-sidebar {
273
+ margin-left: 0;
274
+ @include bp-up("large") {
275
+ margin-left: 300px;
276
+ }
277
+ }
278
+
279
+ textarea {
280
+ width: 100%;
281
+ height: 3rem;
282
+ background-color: transparent;
283
+
284
+ &.expressive-textarea {
285
+ padding-top: 24px !important;
286
+ padding-bottom: 8px !important;
287
+ line-height: 24px;
288
+ overflow-y: hidden;
289
+ resize: none;
290
+ min-height: 56px;
291
+ box-sizing: border-box;
292
+ }
293
+ }
294
+
295
+ .autocomplete-content {
296
+ li {
297
+ .highlight { color: var(--md-sys-color-on-surface); }
298
+ img {
299
+ height: $dropdown-item-height - 10;
300
+ width: $dropdown-item-height - 10;
301
+ margin: 5px 15px;
302
+ }
303
+ }
304
+ }
305
+
306
+ .datepicker-date-input {
307
+ position: relative;
308
+ text-indent: -9999px;
309
+
310
+ &::after {
311
+ display: block;
312
+ position: absolute;
313
+ top: 1.1rem;
314
+ content: attr(data-date);
315
+ color: var(--input-color);
316
+ text-indent: 0;
317
+ }
318
+
319
+ &:focus-visible {
320
+ text-indent: 0;
321
+ }
322
+
323
+ &:focus-visible:after {
324
+ text-indent: -9999px;
325
+ }
326
+ }
@@ -0,0 +1,190 @@
1
+ @use "../../abstracts" as *;
2
+
3
+ // Radio buttons.
4
+ //
5
+ // Anatomy is the HTML. A <label> wrapping <input type="radio"> is the
6
+ // control. The label text is a sibling of the input — no extra class, no
7
+ // required <span>. input + span still works (legacy / BeerCSS).
8
+ //
9
+ // Tokens follow https://m3.material.io/components/radio-button/specs
10
+ // icon 20dp ring, 2dp stroke, on-surface-variant
11
+ // selected primary ring + 10dp primary inner (the M3 "gap")
12
+ // state layer 40dp, 8% hover / 10% focus
13
+ // touch target 48dp
14
+ // label body-large / on-surface
15
+ // disabled on-surface 38%
16
+ //
17
+ // .with-gap is a no-op: the selected state is always the ring + inner.
18
+
19
+ label:has(> [type="radio"]),
20
+ .radio {
21
+ --md-comp-radio-button-icon-size: 20px;
22
+ --md-comp-radio-button-state-layer-size: 40px;
23
+
24
+ display: flex;
25
+ align-items: center;
26
+ gap: 12px;
27
+ min-height: 48px;
28
+ margin: 0;
29
+ cursor: pointer;
30
+ user-select: none;
31
+ color: var(--md-sys-color-on-surface);
32
+ @include typescale("body-large");
33
+ font-family: $font-stack;
34
+ }
35
+
36
+ nav:has(> label > [type="radio"]) {
37
+ display: flex;
38
+ flex-wrap: wrap;
39
+ align-items: center;
40
+ gap: 8px 24px;
41
+ }
42
+
43
+ nav > label:has(> [type="radio"]),
44
+ nav > .radio {
45
+ display: inline-flex;
46
+ }
47
+
48
+ // Paint the radio on the input. A following span (legacy) hides this
49
+ // control and draws the same anatomy. Nested :has() is invalid, so
50
+ // do not write :has(:not(:has(+ span))).
51
+ label:has(> [type="radio"]) > [type="radio"],
52
+ .radio > [type="radio"] {
53
+ appearance: none;
54
+ flex: 0 0 var(--md-comp-radio-button-icon-size);
55
+ box-sizing: border-box;
56
+ width: var(--md-comp-radio-button-icon-size);
57
+ height: var(--md-comp-radio-button-icon-size);
58
+ margin: 0;
59
+ padding: 0;
60
+ border: 2px solid var(--md-sys-color-on-surface-variant);
61
+ border-radius: 50%;
62
+ background-color: transparent;
63
+ cursor: pointer;
64
+ transition: border-color .2s ease, background-color .2s ease, box-shadow .2s ease;
65
+
66
+ &:checked {
67
+ border-color: var(--md-sys-color-primary);
68
+ background-image: radial-gradient(
69
+ circle at center,
70
+ var(--md-sys-color-primary) 0 5px,
71
+ transparent 5.5px
72
+ );
73
+ }
74
+
75
+ &:hover {
76
+ box-shadow: 0 0 0 10px color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
77
+ }
78
+
79
+ &:checked:hover {
80
+ box-shadow: 0 0 0 10px color-mix(in oklab, var(--md-sys-color-primary) 8%, transparent);
81
+ }
82
+
83
+ &:focus-visible,
84
+ &.tabbed:focus {
85
+ box-shadow: 0 0 0 10px color-mix(in oklab, var(--md-sys-color-primary) 10%, transparent);
86
+ outline: none;
87
+ }
88
+
89
+ &:disabled {
90
+ border-color: color-mix(in oklab, var(--md-sys-color-on-surface) 38%, transparent);
91
+ background-image: none;
92
+ box-shadow: none;
93
+ cursor: default;
94
+ }
95
+
96
+ &:disabled:checked {
97
+ background-image: radial-gradient(
98
+ circle at center,
99
+ color-mix(in oklab, var(--md-sys-color-on-surface) 38%, transparent) 0 5px,
100
+ transparent 5.5px
101
+ );
102
+ }
103
+
104
+ &:has(+ span) {
105
+ position: absolute;
106
+ opacity: 0;
107
+ width: 0;
108
+ height: 0;
109
+ border: 0;
110
+ background: none;
111
+ box-shadow: none;
112
+ pointer-events: none;
113
+ }
114
+ }
115
+
116
+ label:has(> [type="radio"]:disabled),
117
+ .radio:has([type="radio"]:disabled) {
118
+ color: color-mix(in oklab, var(--md-sys-color-on-surface) 38%, transparent);
119
+ cursor: default;
120
+ }
121
+
122
+ // Legacy / BeerCSS: input + span draws the same 20/10 anatomy.
123
+ [type="radio"] + span {
124
+ position: relative;
125
+ display: inline-flex;
126
+ align-items: center;
127
+ min-height: 48px;
128
+ padding-left: 32px;
129
+ cursor: pointer;
130
+ user-select: none;
131
+ }
132
+
133
+ [type="radio"] + span::before,
134
+ [type="radio"] + span::after {
135
+ content: "";
136
+ position: absolute;
137
+ left: 0;
138
+ top: 50%;
139
+ box-sizing: border-box;
140
+ width: 20px;
141
+ height: 20px;
142
+ margin-top: -10px;
143
+ border-radius: 50%;
144
+ }
145
+
146
+ [type="radio"] + span::before {
147
+ border: 2px solid var(--md-sys-color-on-surface-variant);
148
+ transition: border-color .2s ease, box-shadow .2s ease;
149
+ }
150
+
151
+ [type="radio"] + span::after {
152
+ background-color: var(--md-sys-color-primary);
153
+ transform: scale(0);
154
+ transition: transform .2s ease;
155
+ }
156
+
157
+ [type="radio"]:checked + span::before {
158
+ border-color: var(--md-sys-color-primary);
159
+ }
160
+
161
+ [type="radio"]:checked + span::after {
162
+ transform: scale(0.5);
163
+ }
164
+
165
+ [type="radio"]:hover + span::before {
166
+ box-shadow: 0 0 0 10px color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
167
+ }
168
+
169
+ [type="radio"]:checked:hover + span::before {
170
+ box-shadow: 0 0 0 10px color-mix(in oklab, var(--md-sys-color-primary) 8%, transparent);
171
+ }
172
+
173
+ [type="radio"]:focus-visible + span::before,
174
+ [type="radio"].tabbed:focus + span::before {
175
+ box-shadow: 0 0 0 10px color-mix(in oklab, var(--md-sys-color-primary) 10%, transparent);
176
+ }
177
+
178
+ [type="radio"]:disabled + span {
179
+ color: color-mix(in oklab, var(--md-sys-color-on-surface) 38%, transparent);
180
+ cursor: default;
181
+ }
182
+
183
+ [type="radio"]:disabled + span::before {
184
+ border-color: color-mix(in oklab, var(--md-sys-color-on-surface) 38%, transparent);
185
+ box-shadow: none;
186
+ }
187
+
188
+ [type="radio"]:disabled:checked + span::after {
189
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 38%, transparent);
190
+ }