@expressivecss/expressive 0.1.0-alpha.3 → 0.2.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 (154) hide show
  1. package/LICENSE +82 -2
  2. package/README.md +153 -43
  3. package/dist/css/expressive.css +7121 -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 +7521 -0
  8. package/dist/js/expressive.cjs.map +7 -0
  9. package/dist/js/expressive.js +7383 -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 +7292 -7998
  14. package/dist/js/expressive.mjs.map +7 -1
  15. package/dist/types/behaviors/dialogs.d.ts +25 -0
  16. package/dist/{js → types}/components/autocomplete.d.ts +10 -1
  17. package/dist/{js → types}/components/buttons.d.ts +11 -1
  18. package/dist/{js → types}/components/cards.d.ts +10 -1
  19. package/dist/{js → types}/components/carousel.d.ts +4 -5
  20. package/dist/{js/forms/character-counter.d.ts → types/components/characterCounter.d.ts} +1 -1
  21. package/dist/{js → types}/components/chips.d.ts +1 -1
  22. package/dist/{js → types}/components/collapsible.d.ts +1 -1
  23. package/dist/{js → types}/components/datepicker.d.ts +63 -2
  24. package/dist/{js → types}/components/dropdown.d.ts +3 -3
  25. package/dist/types/components/index.d.ts +23 -0
  26. package/dist/{js/components/materialbox.d.ts → types/components/lightbox.d.ts} +21 -21
  27. package/dist/{js → types}/components/modal.d.ts +1 -1
  28. package/dist/{js → types}/components/parallax.d.ts +11 -5
  29. package/dist/{js → types}/components/pushpin.d.ts +1 -1
  30. package/dist/{js/forms → types/components}/range.d.ts +3 -3
  31. package/dist/types/components/registry.d.ts +107 -0
  32. package/dist/{js → types}/components/scrollspy.d.ts +6 -9
  33. package/dist/{js/forms → types/components}/select.d.ts +11 -2
  34. package/dist/{js → types}/components/sidenav.d.ts +1 -1
  35. package/dist/{js → types}/components/slider.d.ts +3 -2
  36. package/dist/{js → types}/components/tabs.d.ts +3 -2
  37. package/dist/{js/components/tap-target.d.ts → types/components/tapTarget.d.ts} +2 -2
  38. package/dist/{js → types}/components/timepicker.d.ts +13 -5
  39. package/dist/{js/components/toast.d.ts → types/components/toasts.d.ts} +28 -4
  40. package/dist/{js → types}/components/tooltip.d.ts +2 -2
  41. package/dist/types/core/bounding.d.ts +6 -0
  42. package/dist/{js/foundation → types/core}/component.d.ts +1 -1
  43. package/dist/types/core/edges.d.ts +6 -0
  44. package/dist/{js/foundation → types/core}/utils.d.ts +21 -14
  45. package/dist/types/index.d.ts +7 -0
  46. package/dist/{js/plugins/docked-display.d.ts → types/plugins/dockedDisplayPlugin.d.ts} +7 -0
  47. package/package.json +60 -36
  48. package/src/sass/README.md +200 -0
  49. package/src/sass/abstracts/_breakpoints.scss +69 -0
  50. package/src/sass/abstracts/_elevation.scss +34 -0
  51. package/src/sass/abstracts/_index.scss +7 -0
  52. package/src/sass/abstracts/_mixins.scss +171 -0
  53. package/src/sass/abstracts/_variables.scss +57 -0
  54. package/src/{scss/layout/_table.scss → sass/base/_global.scss} +64 -2
  55. package/src/{scss/layout → sass/base}/_grid.scss +6 -6
  56. package/src/sass/base/_index.scss +6 -0
  57. package/src/{scss/foundation → sass/base}/_normalize.scss +51 -139
  58. package/src/sass/base/_typography.scss +90 -0
  59. package/src/sass/components/_badges.scss +77 -0
  60. package/src/{scss → sass}/components/_breadcrumb.scss +2 -0
  61. package/src/sass/components/_buttons.scss +407 -0
  62. package/src/sass/components/_cards.scss +328 -0
  63. package/src/{scss → sass}/components/_carousel.scss +5 -3
  64. package/src/sass/components/_chips.scss +140 -0
  65. package/src/sass/components/_collapsible.scss +81 -0
  66. package/src/{scss → sass}/components/_collection.scss +2 -2
  67. package/src/{scss/components/_date-picker.scss → sass/components/_datepicker.scss} +51 -44
  68. package/src/sass/components/_docked-display.scss +11 -0
  69. package/src/sass/components/_dropdown.scss +129 -0
  70. package/src/{scss/components/_material-icons.scss → sass/components/_icons-material-design.scss} +2 -0
  71. package/src/sass/components/_index.scss +35 -0
  72. package/src/{scss/components/_material-box.scss → sass/components/_lightbox.scss} +6 -4
  73. package/src/sass/components/_modal.scss +208 -0
  74. package/src/sass/components/_navbar.scss +345 -0
  75. package/src/{scss/layout/_footer.scss → sass/components/_page-footer.scss} +7 -6
  76. package/src/{scss → sass}/components/_pagination.scss +4 -3
  77. package/src/{scss → sass}/components/_parallax.scss +4 -1
  78. package/src/{scss → sass}/components/_preloader.scss +19 -97
  79. package/src/{scss → sass}/components/_pulse.scss +2 -0
  80. package/src/sass/components/_pushpin.scss +11 -0
  81. package/src/{scss → sass}/components/_sidenav.scss +99 -82
  82. package/src/{scss → sass}/components/_slider.scss +3 -1
  83. package/src/{scss/components/_table-of-contents.scss → sass/components/_table_of_contents.scss} +2 -0
  84. package/src/sass/components/_tabs.scss +232 -0
  85. package/src/{scss/components/_tap-target.scss → sass/components/_tapTarget.scss} +24 -22
  86. package/src/{scss/components/_time-picker.scss → sass/components/_timepicker.scss} +56 -56
  87. package/src/sass/components/_toast.scss +260 -0
  88. package/src/sass/components/_toolbar.scss +192 -0
  89. package/src/sass/components/_tooltip.scss +166 -0
  90. package/src/{scss → sass}/components/_transitions.scss +4 -4
  91. package/src/sass/components/forms/_checkboxes.scss +288 -0
  92. package/src/sass/components/forms/_fieldset.scss +128 -0
  93. package/src/{scss → sass/components}/forms/_file-input.scss +11 -9
  94. package/src/{scss → sass/components}/forms/_index.scss +2 -0
  95. package/src/sass/components/forms/_input-fields.scss +326 -0
  96. package/src/sass/components/forms/_radio-buttons.scss +190 -0
  97. package/src/sass/components/forms/_range.scss +310 -0
  98. package/src/sass/components/forms/_select.scss +103 -0
  99. package/src/sass/components/forms/_switches.scss +239 -0
  100. package/src/sass/expressive.scss +60 -0
  101. package/src/sass/tokens/_index.scss +4 -0
  102. package/src/sass/tokens/_reference.scss +265 -0
  103. package/src/sass/tokens/_theme.scss +49 -0
  104. package/src/sass/utilities/_helpers.scss +63 -0
  105. package/src/sass/utilities/_index.scss +8 -0
  106. package/src/{scss → sass}/utilities/_spacing.scss +4 -3
  107. package/src/sass/utilities/_typescale.scss +45 -0
  108. package/src/sass/utilities/_visibility.scss +63 -0
  109. package/src/sass/utilities/_z-depth.scss +18 -0
  110. package/dist/js/components/index.d.ts +0 -21
  111. package/dist/js/forms/index.d.ts +0 -4
  112. package/dist/js/foundation/index.d.ts +0 -2
  113. package/dist/js/index.d.ts +0 -52
  114. package/dist/js/plugins/index.d.ts +0 -1
  115. package/src/scss/components/_appbar.scss +0 -454
  116. package/src/scss/components/_badges.scss +0 -77
  117. package/src/scss/components/_buttons.scss +0 -412
  118. package/src/scss/components/_cards.scss +0 -267
  119. package/src/scss/components/_chips.scss +0 -147
  120. package/src/scss/components/_collapsible.scss +0 -84
  121. package/src/scss/components/_dropdown.scss +0 -98
  122. package/src/scss/components/_index.scss +0 -28
  123. package/src/scss/components/_modal.scss +0 -84
  124. package/src/scss/components/_tabs.scss +0 -176
  125. package/src/scss/components/_toast.scss +0 -70
  126. package/src/scss/components/_tooltip.scss +0 -49
  127. package/src/scss/components/_video.scss +0 -15
  128. package/src/scss/expressive.scss +0 -7
  129. package/src/scss/forms/_checkboxes.scss +0 -199
  130. package/src/scss/forms/_input-fields.scss +0 -360
  131. package/src/scss/forms/_radio-buttons.scss +0 -114
  132. package/src/scss/forms/_range.scss +0 -148
  133. package/src/scss/forms/_select.scss +0 -108
  134. package/src/scss/forms/_switches.scss +0 -127
  135. package/src/scss/foundation/_base.scss +0 -71
  136. package/src/scss/foundation/_color-palette.scss +0 -402
  137. package/src/scss/foundation/_index.scss +0 -10
  138. package/src/scss/foundation/_mixins.scss +0 -198
  139. package/src/scss/foundation/_motion.scss +0 -70
  140. package/src/scss/foundation/_shape.scss +0 -30
  141. package/src/scss/foundation/_state-layers.scss +0 -68
  142. package/src/scss/foundation/_theme.scss +0 -238
  143. package/src/scss/foundation/_tokens.scss +0 -511
  144. package/src/scss/foundation/_variables.scss +0 -57
  145. package/src/scss/layout/_index.scss +0 -3
  146. package/src/scss/utilities/_a11y.scss +0 -77
  147. package/src/scss/utilities/_elevation.scss +0 -63
  148. package/src/scss/utilities/_helpers.scss +0 -50
  149. package/src/scss/utilities/_index.scss +0 -7
  150. package/src/scss/utilities/_responsive.scss +0 -62
  151. package/src/scss/utilities/_typography.scss +0 -115
  152. /package/dist/{js/forms → types/behaviors}/forms.d.ts +0 -0
  153. /package/dist/{js/components → types/behaviors}/waves.d.ts +0 -0
  154. /package/src/{scss → sass}/utilities/_colors.scss +0 -0
@@ -0,0 +1,407 @@
1
+ @use "../abstracts" as *;
2
+
3
+ // Common buttons and FABs.
4
+ //
5
+ // Anatomy is the HTML. A <button> (or <a class="button"> / .btn) is a filled
6
+ // common button. Put an <i> first or last for a leading/trailing icon — no
7
+ // icon-left / icon-right required. Icon-only is a 40dp icon button. Helpers
8
+ // switch the M3 variant (tonal, outlined, elevated, text) or the size.
9
+ //
10
+ // Tokens follow https://m3.material.io/components/buttons/specs
11
+ // height 40 / 32 small / 56 large, label-large, 20dp stadium
12
+ // icon 18dp, 8dp gap, 24dp inset (16dp next to an icon)
13
+ // state layer 8% hover / 10% focus+press
14
+ // FAB 56dp (extra/large icon-only), primary-container, 16dp corners
15
+
16
+ :root {
17
+ --md-comp-filled-button-container-color: var(--md-sys-color-primary);
18
+ --md-comp-filled-button-label-text-color: var(--md-sys-color-on-primary);
19
+ --md-comp-filled-button-container-height: 40px;
20
+ --md-comp-filled-button-container-shape: 20px;
21
+ --md-comp-filled-button-leading-space: 24px;
22
+ --md-comp-filled-button-trailing-space: 24px;
23
+ --md-comp-filled-button-with-icon-leading-space: 16px;
24
+ --md-comp-filled-button-icon-size: 18px;
25
+ --md-comp-filled-button-icon-label-space: 8px;
26
+ }
27
+
28
+ // Widget chrome that happens to be a <button> — not a common button.
29
+ $_not-btn: ".datepicker-day-button, .month-prev, .month-next, .indicator-item-btn";
30
+
31
+ $_btn: "button:not(#{$_not-btn}), a.button, .btn, .btn-flat, .btn-large, .btn-small";
32
+
33
+ :where(#{$_btn}) {
34
+ @include btn;
35
+
36
+ > i {
37
+ flex: 0 0 auto;
38
+ font-size: var(--md-comp-filled-button-icon-size);
39
+ width: var(--md-comp-filled-button-icon-size);
40
+ height: var(--md-comp-filled-button-icon-size);
41
+ line-height: var(--md-comp-filled-button-icon-size);
42
+ overflow: hidden;
43
+ }
44
+
45
+ // :only-child ignores text nodes, so "<i>add</i>Create" would look like
46
+ // an icon button. Wrap the label in a <span> (BeerCSS) for the 16dp
47
+ // leading inset; otherwise the icon still sits on the flex gap.
48
+ &:has(> i + span) {
49
+ padding-inline-start: var(--md-comp-filled-button-with-icon-leading-space);
50
+ }
51
+
52
+ &:has(> span + i) {
53
+ padding-inline-end: var(--md-comp-filled-button-with-icon-leading-space);
54
+ }
55
+
56
+ // Icon button — opt in with .circle. Do not infer from :only-child.
57
+ &.circle {
58
+ width: var(--md-comp-filled-button-container-height);
59
+ padding: 0;
60
+ border-radius: 50%;
61
+
62
+ > i {
63
+ font-size: 24px;
64
+ width: 24px;
65
+ height: 24px;
66
+ line-height: 24px;
67
+ }
68
+ }
69
+ }
70
+
71
+ // Default variant is filled. :where() keeps specificity at zero so .tonal etc. win.
72
+ :where(#{$_btn}):not(.tonal, .outlined, .border, .elevated, .text, .transparent, .btn-flat) {
73
+ @include btn-filled;
74
+ }
75
+
76
+ :where(#{$_btn}).tonal {
77
+ @include btn-tonal;
78
+ }
79
+
80
+ :where(#{$_btn}).outlined,
81
+ :where(#{$_btn}).border {
82
+ @include btn-outlined;
83
+ }
84
+
85
+ :where(#{$_btn}).elevated {
86
+ @include btn-elevated;
87
+ }
88
+
89
+ :where(#{$_btn}).text,
90
+ :where(#{$_btn}).transparent,
91
+ .btn-flat {
92
+ @include btn-flat;
93
+ }
94
+
95
+ // icon-right is a compat alias: new markup puts the icon last in the DOM.
96
+ :where(#{$_btn}).icon-right {
97
+ flex-direction: row-reverse;
98
+ }
99
+
100
+ // Sizes. small = 32dp, large/extra = 56dp (M3 extra-large / FAB height).
101
+ :where(#{$_btn}).small,
102
+ .btn-small {
103
+ --md-comp-filled-button-container-height: 32px;
104
+ --md-comp-filled-button-container-shape: 16px;
105
+ --md-comp-filled-button-leading-space: 16px;
106
+ --md-comp-filled-button-trailing-space: 16px;
107
+ --md-comp-filled-button-with-icon-leading-space: 12px;
108
+ --md-comp-filled-button-icon-size: 16px;
109
+ height: 32px;
110
+ font-size: var(--md-sys-typescale-label-medium-font-size);
111
+ }
112
+
113
+ :where(#{$_btn}).large,
114
+ :where(#{$_btn}).extra,
115
+ .btn-large {
116
+ --md-comp-filled-button-container-height: 56px;
117
+ --md-comp-filled-button-container-shape: 28px;
118
+ --md-comp-filled-button-leading-space: 24px;
119
+ --md-comp-filled-button-trailing-space: 24px;
120
+ --md-comp-filled-button-with-icon-leading-space: 16px;
121
+ --md-comp-filled-button-icon-size: 24px;
122
+ height: 56px;
123
+ }
124
+
125
+ :where(#{$_btn}).rounded {
126
+ border-radius: 9999px;
127
+ }
128
+
129
+ .btn-block {
130
+ display: flex;
131
+ width: 100%;
132
+ }
133
+
134
+ // Extended FAB: 56dp, large corners, primary-container, icon + label.
135
+ :where(#{$_btn}).extend {
136
+ height: 56px;
137
+ padding-inline: 16px 20px;
138
+ border-radius: 16px;
139
+ color: var(--md-sys-color-on-primary-container);
140
+ background-color: var(--md-sys-color-primary-container);
141
+ @include z-depth("3");
142
+
143
+ &:hover {
144
+ @include z-depth("4");
145
+ background-color: color-mix(
146
+ in oklab,
147
+ var(--md-sys-color-on-primary-container) 8%,
148
+ var(--md-sys-color-primary-container)
149
+ );
150
+ }
151
+
152
+ &:active,
153
+ &:focus {
154
+ background-color: color-mix(
155
+ in oklab,
156
+ var(--md-sys-color-on-primary-container) 10%,
157
+ var(--md-sys-color-primary-container)
158
+ );
159
+ }
160
+
161
+ @include focus-visible;
162
+
163
+ > i {
164
+ font-size: 24px;
165
+ width: 24px;
166
+ height: 24px;
167
+ line-height: 24px;
168
+ }
169
+ }
170
+
171
+ // FAB. .btn-floating is the JS contract (FloatingActionButton looks it up).
172
+ // Icon-only .extra / .large is the same 56dp regular FAB. Bare .btn-floating
173
+ // is the 40dp small FAB.
174
+ .btn-floating,
175
+ :where(#{$_btn}).extra.circle,
176
+ :where(#{$_btn}).large.circle,
177
+ :where(#{$_btn}).btn-large.circle {
178
+ display: inline-flex;
179
+ align-items: center;
180
+ justify-content: center;
181
+ width: 56px;
182
+ height: 56px;
183
+ padding: 0;
184
+ border: none;
185
+ border-radius: 16px;
186
+ color: var(--md-sys-color-on-primary-container);
187
+ background-color: var(--md-sys-color-primary-container);
188
+ text-decoration: none;
189
+ cursor: pointer;
190
+ appearance: none;
191
+ vertical-align: middle;
192
+ @include z-depth("3");
193
+ @include focus-visible;
194
+ transition: background-color .2s ease-out, box-shadow .2s ease-out;
195
+
196
+ > i {
197
+ font-size: 24px;
198
+ width: 24px;
199
+ height: 24px;
200
+ line-height: 24px;
201
+ color: inherit;
202
+ }
203
+
204
+ &:hover {
205
+ @include z-depth("4");
206
+ background-color: color-mix(
207
+ in oklab,
208
+ var(--md-sys-color-on-primary-container) 8%,
209
+ var(--md-sys-color-primary-container)
210
+ );
211
+ }
212
+
213
+ &:active,
214
+ &:focus {
215
+ background-color: color-mix(
216
+ in oklab,
217
+ var(--md-sys-color-on-primary-container) 10%,
218
+ var(--md-sys-color-primary-container)
219
+ );
220
+ }
221
+
222
+ &.small,
223
+ &.btn-small {
224
+ width: 40px;
225
+ height: 40px;
226
+ border-radius: 12px;
227
+
228
+ > i {
229
+ font-size: 24px;
230
+ }
231
+ }
232
+
233
+ &.halfway-fab {
234
+ position: absolute;
235
+ right: 24px;
236
+ bottom: -28px;
237
+
238
+ &.left {
239
+ right: auto;
240
+ left: 24px;
241
+ }
242
+ }
243
+ }
244
+
245
+ // Small FAB alias: .btn-floating alone is 40dp (historical size + M3 small).
246
+ .btn-floating:not(.large, .btn-large, .extra, .small, .btn-small) {
247
+ width: 40px;
248
+ height: 40px;
249
+ border-radius: 12px;
250
+
251
+ &.halfway-fab {
252
+ bottom: -20px;
253
+ }
254
+ }
255
+
256
+ :where(#{$_btn}):disabled,
257
+ :where(#{$_btn})[disabled],
258
+ :where(#{$_btn}).disabled,
259
+ .btn-floating:disabled,
260
+ .btn-floating[disabled],
261
+ .btn-floating.disabled {
262
+ @include btn-disabled;
263
+ }
264
+
265
+ // Fixed Action Button — JS-driven menu around a FAB.
266
+ .fixed-action-btn {
267
+ position: fixed;
268
+ right: 23px;
269
+ bottom: 23px;
270
+ padding-top: 15px;
271
+ margin-bottom: 0;
272
+ z-index: 997;
273
+
274
+ &.active {
275
+ ul {
276
+ visibility: visible;
277
+ padding-left: 0;
278
+ list-style-type: none;
279
+ }
280
+ }
281
+
282
+ &.direction-left,
283
+ &.direction-right {
284
+ padding: 0 0 0 15px;
285
+
286
+ ul {
287
+ text-align: right;
288
+ right: 64px;
289
+ top: 50%;
290
+ transform: translateY(-50%);
291
+ height: 100%;
292
+ left: auto;
293
+ width: 500px;
294
+
295
+ li {
296
+ display: inline-block;
297
+ margin: 7.5px 15px 0 0;
298
+ }
299
+ }
300
+ }
301
+
302
+ &.direction-right {
303
+ padding: 0 15px 0 0;
304
+
305
+ ul {
306
+ text-align: left;
307
+ direction: rtl;
308
+ left: 64px;
309
+ right: auto;
310
+
311
+ li {
312
+ margin: 7.5px 0 0 15px;
313
+ }
314
+ }
315
+ }
316
+
317
+ &.direction-bottom {
318
+ padding: 0 0 15px 0;
319
+
320
+ ul {
321
+ top: 64px;
322
+ bottom: auto;
323
+ display: flex;
324
+ flex-direction: column-reverse;
325
+
326
+ li {
327
+ margin: 15px 0 0 0;
328
+ }
329
+ }
330
+ }
331
+
332
+ &.toolbar {
333
+ padding: 0;
334
+ height: 56px;
335
+
336
+ &.active {
337
+ & > a i,
338
+ & > button i {
339
+ opacity: 0;
340
+ }
341
+ }
342
+
343
+ ul {
344
+ display: flex;
345
+ top: 0;
346
+ bottom: 0;
347
+ z-index: 1;
348
+
349
+ li {
350
+ flex: 1;
351
+ display: inline-block;
352
+ margin: 0;
353
+ height: 100%;
354
+ transition: none;
355
+
356
+ a,
357
+ button {
358
+ display: block;
359
+ overflow: hidden;
360
+ position: relative;
361
+ width: 100%;
362
+ height: 100%;
363
+ background-color: transparent;
364
+ box-shadow: none;
365
+ color: var(--md-sys-color-on-primary-container);
366
+ line-height: 56px;
367
+ z-index: 1;
368
+
369
+ i {
370
+ line-height: inherit;
371
+ }
372
+ }
373
+ }
374
+ }
375
+ }
376
+
377
+ ul {
378
+ left: 0;
379
+ right: 0;
380
+ text-align: center;
381
+ position: absolute;
382
+ bottom: 64px;
383
+ margin: 0;
384
+ visibility: hidden;
385
+
386
+ li {
387
+ margin-bottom: 15px;
388
+ }
389
+
390
+ a.btn-floating,
391
+ button.btn-floating {
392
+ opacity: 0;
393
+ }
394
+ }
395
+
396
+ .fab-backdrop {
397
+ position: absolute;
398
+ top: 0;
399
+ left: 0;
400
+ z-index: -1;
401
+ width: 56px;
402
+ height: 56px;
403
+ background-color: var(--md-sys-color-primary-container);
404
+ border-radius: 16px;
405
+ transform: scale(0);
406
+ }
407
+ }
@@ -0,0 +1,328 @@
1
+ @use "../abstracts" as *;
2
+
3
+ // Cards.
4
+ //
5
+ // Anatomy is the HTML. An <article> is an elevated card. A heading is the
6
+ // headline, a <p> is supporting text, a direct <nav> is the action row,
7
+ // <img> / <figure> is media. Helpers switch the M3 variant (filled, outlined)
8
+ // or the layout (horizontal). .card and .card-panel stay as aliases.
9
+ //
10
+ // Tokens follow https://m3.material.io/components/cards/specs
11
+ // container surface, 12dp corners
12
+ // elevated level 1, hover level 2
13
+ // filled surface-variant, level 0
14
+ // outlined surface + 1dp outline, level 0
15
+ // headline title-medium / on-surface
16
+ // body body-medium / on-surface-variant
17
+ // padding 16dp
18
+
19
+ $_card: "article, .card, .card-panel";
20
+
21
+ :where(#{$_card}) {
22
+ --md-comp-elevated-card-container-color: var(--md-sys-color-surface);
23
+ --md-comp-elevated-card-container-shape: 12px;
24
+
25
+ position: relative;
26
+ box-sizing: border-box;
27
+ background-color: var(--md-comp-elevated-card-container-color);
28
+ color: var(--md-sys-color-on-surface);
29
+ border-radius: var(--md-comp-elevated-card-container-shape);
30
+ overflow: hidden;
31
+ transition: box-shadow .2s ease-out;
32
+ }
33
+
34
+ // Default is elevated. :where() keeps specificity at zero so .outlined wins.
35
+ :where(#{$_card}):not(.filled, .outlined, .border) {
36
+ @include z-depth("1");
37
+
38
+ &:hover {
39
+ @include z-depth("2");
40
+ }
41
+ }
42
+
43
+ :where(#{$_card}).filled {
44
+ @include z-depth("0");
45
+ background-color: var(--md-sys-color-surface-variant);
46
+ }
47
+
48
+ :where(#{$_card}).outlined,
49
+ :where(#{$_card}).border {
50
+ @include z-depth("0");
51
+ border: 1px solid var(--md-sys-color-outline-variant);
52
+ }
53
+
54
+ // --- Semantic children ----------------------------------------------------
55
+
56
+ article > :is(h1, h2, h3, h4, h5, h6),
57
+ article > header > :is(h1, h2, h3, h4, h5, h6) {
58
+ margin: 0;
59
+ padding: 16px 16px 0;
60
+ font-family: var(--md-sys-typescale-title-medium-font-family-name);
61
+ font-size: var(--md-sys-typescale-title-medium-font-size);
62
+ font-weight: var(--md-sys-typescale-title-medium-font-weight);
63
+ line-height: var(--md-sys-typescale-title-medium-line-height);
64
+ letter-spacing: var(--md-sys-typescale-title-medium-letter-spacing);
65
+ color: var(--md-sys-color-on-surface);
66
+ }
67
+
68
+ article > p,
69
+ article > header > p {
70
+ margin: 0;
71
+ padding: 8px 16px 16px;
72
+ font-family: var(--md-sys-typescale-body-medium-font-family-name);
73
+ font-size: var(--md-sys-typescale-body-medium-font-size);
74
+ font-weight: var(--md-sys-typescale-body-medium-font-weight);
75
+ line-height: var(--md-sys-typescale-body-medium-line-height);
76
+ letter-spacing: var(--md-sys-typescale-body-medium-letter-spacing);
77
+ color: color-mix(in oklab, currentColor 72%, transparent);
78
+ }
79
+
80
+ article > :is(h1, h2, h3, h4, h5, h6) + p,
81
+ article > header > :is(h1, h2, h3, h4, h5, h6) + p {
82
+ padding-top: 0;
83
+ }
84
+
85
+ article > header {
86
+ padding: 0;
87
+ background: none;
88
+ color: inherit;
89
+ }
90
+
91
+ article > nav {
92
+ display: flex;
93
+ flex-wrap: wrap;
94
+ align-items: center;
95
+ gap: 8px;
96
+ padding: 4px 8px 8px 8px;
97
+ margin: 0;
98
+ }
99
+
100
+ article > img,
101
+ article > picture,
102
+ article > figure {
103
+ display: block;
104
+ width: 100%;
105
+ margin: 0;
106
+ }
107
+
108
+ article > img,
109
+ article > picture img,
110
+ article > figure img {
111
+ display: block;
112
+ width: 100%;
113
+ object-fit: cover;
114
+ }
115
+
116
+ article > figure {
117
+ position: relative;
118
+ }
119
+
120
+ article > figure > figcaption {
121
+ position: absolute;
122
+ inset-inline: 0;
123
+ bottom: 0;
124
+ margin: 0;
125
+ padding: 16px;
126
+ color: var(--md-sys-color-on-surface);
127
+ background: color-mix(in oklab, var(--md-sys-color-surface) 72%, transparent);
128
+ font-family: var(--md-sys-typescale-title-medium-font-family-name);
129
+ font-size: var(--md-sys-typescale-title-medium-font-size);
130
+ font-weight: var(--md-sys-typescale-title-medium-font-weight);
131
+ line-height: var(--md-sys-typescale-title-medium-line-height);
132
+ }
133
+
134
+ // Horizontal: media on the start, body stacked beside it.
135
+ article.horizontal,
136
+ .card.horizontal {
137
+ display: flex;
138
+ flex-direction: row;
139
+ align-items: stretch;
140
+ overflow: hidden;
141
+
142
+ > img,
143
+ > picture,
144
+ > figure,
145
+ > .card-image {
146
+ flex: 0 0 40%;
147
+ max-width: 40%;
148
+ width: 40%;
149
+ align-self: stretch;
150
+ }
151
+
152
+ > img,
153
+ > picture img,
154
+ > figure img,
155
+ > .card-image img {
156
+ height: 100%;
157
+ object-fit: cover;
158
+ }
159
+
160
+ > div {
161
+ flex: 1 1 auto;
162
+ min-width: 0;
163
+ display: flex;
164
+ flex-direction: column;
165
+ }
166
+ }
167
+
168
+ // Fixed heights (Materialize sizes, still useful for uniform grids).
169
+ article.small, .card.small { height: 300px; }
170
+ article.medium, .card.medium { height: 400px; }
171
+ article.large, .card.large { height: 500px; }
172
+
173
+ article.small, article.medium, article.large,
174
+ .card.small, .card.medium, .card.large {
175
+ display: flex;
176
+ flex-direction: column;
177
+
178
+ > img, > picture, > figure, > .card-image {
179
+ flex: 0 1 60%;
180
+ min-height: 0;
181
+ overflow: hidden;
182
+ }
183
+
184
+ > img, > figure img, > .card-image img {
185
+ height: 100%;
186
+ }
187
+
188
+ > p, > .card-content {
189
+ flex: 1 1 auto;
190
+ min-height: 0;
191
+ overflow: hidden;
192
+ }
193
+
194
+ > nav, > .card-action {
195
+ margin-top: auto;
196
+ }
197
+ }
198
+
199
+ article.horizontal.small,
200
+ article.horizontal.medium,
201
+ article.horizontal.large,
202
+ .card.horizontal.small,
203
+ .card.horizontal.medium,
204
+ .card.horizontal.large {
205
+ flex-direction: row;
206
+
207
+ > img, > picture, > figure, > .card-image {
208
+ flex: 0 0 40%;
209
+ max-height: none;
210
+ }
211
+ }
212
+
213
+ // Reveal overlay. aside is the semantic name; .card-reveal is the JS alias.
214
+ article > aside,
215
+ .card-reveal {
216
+ display: none;
217
+ position: absolute;
218
+ inset: 0;
219
+ z-index: 3;
220
+ box-sizing: border-box;
221
+ padding: 16px;
222
+ overflow-y: auto;
223
+ background-color: var(--md-sys-color-surface);
224
+ color: var(--md-sys-color-on-surface);
225
+ }
226
+
227
+ article.sticky > nav,
228
+ .card.sticky-action > .card-action {
229
+ position: relative;
230
+ z-index: 4;
231
+ background-color: inherit;
232
+ }
233
+
234
+ article.sticky > aside,
235
+ .card.sticky-action > .card-reveal {
236
+ bottom: auto;
237
+ height: calc(100% - 52px);
238
+ }
239
+
240
+ // Simple padded surface. Same tokens as a card with no slots.
241
+ .card-panel {
242
+ padding: 16px;
243
+ margin: $element-top-margin 0 $element-bottom-margin 0;
244
+ }
245
+
246
+ // --- Legacy slots (.card-*) so existing markup keeps working --------------
247
+
248
+ .card-title {
249
+ font-family: var(--md-sys-typescale-title-medium-font-family-name);
250
+ font-size: var(--md-sys-typescale-title-medium-font-size);
251
+ font-weight: var(--md-sys-typescale-title-medium-font-weight);
252
+ line-height: var(--md-sys-typescale-title-medium-line-height);
253
+ letter-spacing: var(--md-sys-typescale-title-medium-letter-spacing);
254
+ }
255
+
256
+ .card .card-image {
257
+ position: relative;
258
+
259
+ img {
260
+ display: block;
261
+ width: 100%;
262
+ object-fit: cover;
263
+ }
264
+
265
+ .card-title {
266
+ position: absolute;
267
+ bottom: 0;
268
+ left: 0;
269
+ max-width: 100%;
270
+ padding: 16px;
271
+ color: var(--md-sys-color-on-surface);
272
+ background: color-mix(in oklab, var(--md-sys-color-surface) 72%, transparent);
273
+ }
274
+
275
+ .activator {
276
+ position: absolute;
277
+ inset: 0;
278
+ cursor: pointer;
279
+ }
280
+
281
+ img.activator {
282
+ position: relative;
283
+ }
284
+ }
285
+
286
+ .card .card-content {
287
+ padding: 16px;
288
+ border-radius: 0;
289
+
290
+ p { margin: 0; }
291
+
292
+ .card-title {
293
+ display: block;
294
+ margin-bottom: 8px;
295
+
296
+ &.activator { cursor: pointer; }
297
+ }
298
+ }
299
+
300
+ .card .card-action {
301
+ display: flex;
302
+ flex-wrap: wrap;
303
+ align-items: center;
304
+ gap: 8px;
305
+ padding: 4px 8px 8px;
306
+
307
+ a:not(.button):not(.btn):not(.btn-floating) {
308
+ @include btn-flat;
309
+ height: auto;
310
+ padding: 8px 12px;
311
+ min-height: 40px;
312
+ }
313
+ }
314
+
315
+ .card .card-stacked {
316
+ display: flex;
317
+ flex-direction: column;
318
+ flex: 1;
319
+ min-width: 0;
320
+
321
+ .card-content { flex-grow: 1; }
322
+ }
323
+
324
+ .card .card-image .activator {
325
+ cursor: pointer;
326
+ }
327
+
328
+ .no-padding { padding: 0 !important; }