@expressivecss/expressive 0.3.0 → 0.5.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 (96) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +4 -9
  3. package/dist/css/expressive.css +3183 -2150
  4. package/dist/css/expressive.css.map +1 -1
  5. package/dist/css/expressive.min.css +1 -1
  6. package/dist/css/expressive.min.css.map +1 -1
  7. package/dist/js/expressive.cjs +1254 -1567
  8. package/dist/js/expressive.cjs.map +4 -4
  9. package/dist/js/expressive.js +1254 -1567
  10. package/dist/js/expressive.js.map +4 -4
  11. package/dist/js/expressive.min.js +12 -22
  12. package/dist/js/expressive.min.js.map +4 -4
  13. package/dist/js/expressive.mjs +1254 -1568
  14. package/dist/js/expressive.mjs.map +4 -4
  15. package/dist/types/behaviors/bottomSheets.d.ts +18 -0
  16. package/dist/types/behaviors/sideSheets.d.ts +18 -0
  17. package/dist/types/components/autocomplete.d.ts +13 -20
  18. package/dist/types/components/buttons.d.ts +2 -2
  19. package/dist/types/components/cards.d.ts +3 -6
  20. package/dist/types/components/carousel.d.ts +3 -3
  21. package/dist/types/components/characterCounter.d.ts +3 -5
  22. package/dist/types/components/chips.d.ts +2 -2
  23. package/dist/types/components/datepicker.d.ts +2 -8
  24. package/dist/types/components/index.d.ts +3 -6
  25. package/dist/types/components/lightbox.d.ts +2 -2
  26. package/dist/types/components/{dropdown.d.ts → menu.d.ts} +48 -38
  27. package/dist/types/components/navigationRail.d.ts +53 -0
  28. package/dist/types/components/parallax.d.ts +2 -8
  29. package/dist/types/components/range.d.ts +5 -2
  30. package/dist/types/components/registry.d.ts +7 -19
  31. package/dist/types/components/scrollspy.d.ts +26 -50
  32. package/dist/types/components/select.d.ts +28 -14
  33. package/dist/types/components/sidenav.d.ts +40 -55
  34. package/dist/types/components/slider.d.ts +2 -2
  35. package/dist/types/components/{toasts.d.ts → snackbar.d.ts} +28 -25
  36. package/dist/types/components/tabs.d.ts +2 -2
  37. package/dist/types/components/timepicker.d.ts +2 -4
  38. package/dist/types/components/tooltip.d.ts +2 -2
  39. package/dist/types/core/component.d.ts +4 -4
  40. package/dist/types/index.d.ts +3 -1
  41. package/package.json +4 -3
  42. package/src/sass/README.md +13 -15
  43. package/src/sass/abstracts/_breakpoints.scss +14 -19
  44. package/src/sass/abstracts/_mixins.scss +3 -3
  45. package/src/sass/abstracts/_variables.scss +27 -23
  46. package/src/sass/base/_global.scss +1 -1
  47. package/src/sass/base/_grid.scss +64 -133
  48. package/src/sass/base/_index.scss +1 -1
  49. package/src/sass/components/_badges.scss +76 -61
  50. package/src/sass/components/_bottom-sheet.scss +137 -0
  51. package/src/sass/components/_buttons.scss +22 -54
  52. package/src/sass/components/_cards.scss +54 -127
  53. package/src/sass/components/_carousel.scss +4 -6
  54. package/src/sass/components/_chips.scss +6 -5
  55. package/src/sass/components/_datepicker.scss +1 -15
  56. package/src/sass/components/_dialog.scss +268 -0
  57. package/src/sass/components/_index.scss +9 -7
  58. package/src/sass/components/_list.scss +253 -0
  59. package/src/sass/components/_menu.scss +341 -0
  60. package/src/sass/components/_navbar.scss +68 -117
  61. package/src/sass/components/_navigation-bar.scss +165 -0
  62. package/src/sass/components/_navigation-rail.scss +308 -0
  63. package/src/sass/components/_page-footer.scss +138 -15
  64. package/src/sass/components/_parallax.scss +7 -28
  65. package/src/sass/components/_preloader.scss +145 -300
  66. package/src/sass/components/_scrollspy.scss +18 -0
  67. package/src/sass/components/_side-sheet.scss +193 -0
  68. package/src/sass/components/_sidenav.scss +281 -146
  69. package/src/sass/components/{_toast.scss → _snackbar.scss} +43 -43
  70. package/src/sass/components/_table_of_contents.scss +30 -14
  71. package/src/sass/components/_tabs.scss +43 -50
  72. package/src/sass/components/_toolbar.scss +93 -27
  73. package/src/sass/components/_tooltip.scss +5 -10
  74. package/src/sass/components/_transitions.scss +0 -5
  75. package/src/sass/components/forms/_fieldset.scss +1 -1
  76. package/src/sass/components/forms/_index.scss +0 -5
  77. package/src/sass/components/forms/_input-fields.scss +52 -55
  78. package/src/sass/components/forms/_range.scss +423 -98
  79. package/src/sass/components/forms/_select.scss +177 -60
  80. package/src/sass/components/forms/_switches.scss +21 -8
  81. package/src/sass/tokens/_reference.scss +37 -13
  82. package/src/sass/tokens/_theme.scss +5 -13
  83. package/src/sass/utilities/_colors.scss +16 -74
  84. package/src/sass/utilities/_helpers.scss +1 -3
  85. package/src/sass/utilities/_typescale.scss +0 -5
  86. package/src/sass/utilities/_visibility.scss +10 -2
  87. package/dist/types/components/collapsible.d.ts +0 -96
  88. package/dist/types/components/modal.d.ts +0 -45
  89. package/dist/types/components/pushpin.d.ts +0 -51
  90. package/dist/types/components/tapTarget.d.ts +0 -57
  91. package/src/sass/components/_collapsible.scss +0 -181
  92. package/src/sass/components/_collection.scss +0 -198
  93. package/src/sass/components/_dropdown.scss +0 -129
  94. package/src/sass/components/_modal.scss +0 -208
  95. package/src/sass/components/_pushpin.scss +0 -11
  96. package/src/sass/components/_tapTarget.scss +0 -191
@@ -0,0 +1,165 @@
1
+ @use "../abstracts" as *;
2
+
3
+ // Navigation bar. Destinations, not the app bar (header:has(> nav)).
4
+ // Anatomy is the HTML: a nav.navigation-bar of <a> or <button> items.
5
+ // A leading <i> is the icon; the remaining text is the label.
6
+ // aria-current (or .active) is the selected destination.
7
+ //
8
+ // Two layouts (M3 Expressive):
9
+ // (default) stacked — icon above label, pill on the icon
10
+ // .horizontal icon beside label, pill around both (medium windows)
11
+ //
12
+ // 3–5 destinations of equal importance. They do not change per screen.
13
+ //
14
+ // Tokens:
15
+ // --md-comp-nav-bar-container-color
16
+ // --md-comp-nav-bar-container-height 64px
17
+ // --md-comp-nav-bar-icon-size 24px
18
+ // --md-comp-nav-bar-indicator-width 56px
19
+ // --md-comp-nav-bar-indicator-height 32px
20
+ // --md-comp-nav-bar-indicator-shape 16px / 100px horizontal
21
+ // --md-comp-nav-bar-active-indicator-color secondary-container
22
+ // --md-comp-nav-bar-active-color on-secondary-container
23
+ //
24
+ // Nest descendants inside this block.
25
+
26
+ .navigation-bar {
27
+ --md-comp-nav-bar-container-color: var(--md-sys-color-surface-container);
28
+ --md-comp-nav-bar-container-height: 64px;
29
+ --md-comp-nav-bar-icon-size: 24px;
30
+ --md-comp-nav-bar-indicator-width: 56px;
31
+ --md-comp-nav-bar-indicator-height: 32px;
32
+ --md-comp-nav-bar-indicator-shape: 16px;
33
+ --md-comp-nav-bar-active-indicator-color: var(--md-sys-color-secondary-container);
34
+ --md-comp-nav-bar-active-color: var(--md-sys-color-on-secondary-container);
35
+
36
+ box-sizing: border-box;
37
+ display: flex;
38
+ align-items: center;
39
+ justify-content: space-evenly;
40
+ width: 100%;
41
+ min-height: var(--md-comp-nav-bar-container-height);
42
+ margin: 0;
43
+ padding: 6px 8px;
44
+ padding-bottom: max(6px, env(safe-area-inset-bottom, 0px));
45
+ background-color: var(--md-comp-nav-bar-container-color);
46
+ color: var(--md-sys-color-on-surface);
47
+
48
+ > :is(a, button) {
49
+ position: relative;
50
+ box-sizing: border-box;
51
+ display: flex;
52
+ flex: 1 1 0;
53
+ flex-direction: column;
54
+ align-items: center;
55
+ justify-content: center;
56
+ gap: 4px;
57
+ min-width: 0;
58
+ margin: 0;
59
+ padding: 4px 0 6px;
60
+ border: 0;
61
+ background: transparent;
62
+ color: var(--md-sys-color-on-surface-variant);
63
+ cursor: pointer;
64
+ appearance: none;
65
+ text-decoration: none;
66
+ @include typescale("label-medium");
67
+ @include focus-visible;
68
+
69
+ > i {
70
+ display: flex;
71
+ flex-shrink: 0;
72
+ align-items: center;
73
+ justify-content: center;
74
+ box-sizing: border-box;
75
+ width: var(--md-comp-nav-bar-indicator-width);
76
+ height: var(--md-comp-nav-bar-indicator-height);
77
+ border-radius: var(--md-comp-nav-bar-indicator-shape);
78
+ font-size: var(--md-comp-nav-bar-icon-size);
79
+ color: inherit;
80
+ transition: background-color 0.2s ease-out;
81
+ }
82
+
83
+ &:hover:not(.active, [aria-current]) > i {
84
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
85
+ }
86
+
87
+ &.active,
88
+ &[aria-current] {
89
+ color: var(--md-sys-color-on-surface);
90
+
91
+ > i {
92
+ background-color: var(--md-comp-nav-bar-active-indicator-color);
93
+ color: var(--md-comp-nav-bar-active-color);
94
+ --md-icon-fill: 1;
95
+ }
96
+ }
97
+
98
+ &.disabled,
99
+ &[aria-disabled="true"] {
100
+ pointer-events: none;
101
+ color: color-mix(in oklab, var(--md-sys-color-on-surface) 38%, transparent);
102
+ }
103
+
104
+ // Sibling badge. Child-of-icon is handled in _badges.scss.
105
+ > .badge {
106
+ position: absolute;
107
+ z-index: 1;
108
+ top: calc(4px + (var(--md-comp-nav-bar-indicator-height) - 24px) / 2);
109
+ left: calc(50% + 12px);
110
+ transform: translate(-50%, -50%);
111
+ }
112
+ }
113
+
114
+ &.horizontal {
115
+ --md-comp-nav-bar-indicator-shape: 100px;
116
+ min-height: 56px;
117
+
118
+ > :is(a, button) {
119
+ flex: 0 1 auto;
120
+ flex-direction: row;
121
+ gap: 8px;
122
+ min-height: 40px;
123
+ padding: 8px 16px;
124
+ border-radius: var(--md-comp-nav-bar-indicator-shape);
125
+
126
+ > i {
127
+ width: var(--md-comp-nav-bar-icon-size);
128
+ height: var(--md-comp-nav-bar-icon-size);
129
+ border-radius: 0;
130
+ }
131
+
132
+ > .badge {
133
+ top: calc(50% - 12px);
134
+ left: auto;
135
+ inset-inline-start: calc(16px + 24px);
136
+ transform: translate(-50%, -50%);
137
+ }
138
+
139
+ &:hover:not(.active, [aria-current]) {
140
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
141
+
142
+ > i {
143
+ background-color: transparent;
144
+ }
145
+ }
146
+
147
+ &.active,
148
+ &[aria-current] {
149
+ background-color: var(--md-comp-nav-bar-active-indicator-color);
150
+ color: var(--md-comp-nav-bar-active-color);
151
+
152
+ > i {
153
+ background-color: transparent;
154
+ color: inherit;
155
+ }
156
+ }
157
+ }
158
+ }
159
+
160
+ &.fixed {
161
+ position: sticky;
162
+ bottom: 0;
163
+ z-index: 997;
164
+ }
165
+ }
@@ -0,0 +1,308 @@
1
+ @use "../abstracts" as *;
2
+
3
+ // Navigation rail. Destinations on mid-size screens, not the bottom
4
+ // navigation bar and not the sidenav drawer.
5
+ //
6
+ // Anatomy is the HTML: a nav.navigation-rail. The first
7
+ // button:not(.button) is the menu toggle. A .button child is the
8
+ // optional FAB. Other <a>/<button> are destinations (leading <i>,
9
+ // remaining text is the label, optional .badge). A heading is a
10
+ // section header (expanded only). aria-current / .active is selected.
11
+ //
12
+ // .expanded widens the rail (icon+label on one row, extended FAB).
13
+ // Below `small`, .expanded is modal (scrim). .modal forces that
14
+ // overlay at every breakpoint. JS toggles .expanded from the menu
15
+ // button; the class is also valid set by the author.
16
+ //
17
+ // Tokens:
18
+ // --md-comp-nav-rail-collapsed-width 96px
19
+ // --md-comp-nav-rail-expanded-width 280px (clamped 220–360)
20
+ // --md-comp-nav-rail-icon-size 24px
21
+ // --md-comp-nav-rail-indicator-width 56px
22
+ // --md-comp-nav-rail-indicator-height 32px / 56px expanded
23
+ // --md-comp-nav-rail-fab-size 56px
24
+ //
25
+ // Nest descendants inside this block.
26
+
27
+ :root {
28
+ --md-comp-nav-rail-collapsed-width: 96px;
29
+ --md-comp-nav-rail-expanded-width: 280px;
30
+ }
31
+
32
+ .navigation-rail {
33
+ --md-comp-nav-rail-icon-size: 24px;
34
+ --md-comp-nav-rail-indicator-width: 56px;
35
+ --md-comp-nav-rail-indicator-height: 32px;
36
+ --md-comp-nav-rail-indicator-shape: 16px;
37
+ --md-comp-nav-rail-fab-size: 56px;
38
+ --md-comp-nav-rail-active-indicator-color: var(--md-sys-color-secondary-container);
39
+ --md-comp-nav-rail-active-color: var(--md-sys-color-on-secondary-container);
40
+ --md-comp-nav-rail-duration: 250ms;
41
+
42
+ box-sizing: border-box;
43
+ display: flex;
44
+ flex-direction: column;
45
+ align-items: center;
46
+ gap: 4px;
47
+ width: var(--md-comp-nav-rail-collapsed-width);
48
+ min-width: var(--md-comp-nav-rail-collapsed-width);
49
+ min-height: 100dvh;
50
+ margin: 0;
51
+ padding: 20px 8px 16px;
52
+ overflow-x: hidden;
53
+ overflow-y: auto;
54
+ overscroll-behavior: contain;
55
+ background-color: var(--md-sys-color-surface-container);
56
+ color: var(--md-sys-color-on-surface);
57
+ transition: width var(--md-comp-nav-rail-duration) ease,
58
+ min-width var(--md-comp-nav-rail-duration) ease,
59
+ padding var(--md-comp-nav-rail-duration) ease;
60
+
61
+ // Menu toggle.
62
+ > button:not(.button):first-child {
63
+ display: flex;
64
+ flex: 0 0 auto;
65
+ align-items: center;
66
+ justify-content: center;
67
+ width: var(--md-comp-nav-rail-indicator-width);
68
+ height: 48px;
69
+ margin: 0 0 8px;
70
+ padding: 0;
71
+ border: 0;
72
+ border-radius: var(--md-comp-nav-rail-indicator-shape);
73
+ background: transparent;
74
+ color: var(--md-sys-color-on-surface-variant);
75
+ cursor: pointer;
76
+ appearance: none;
77
+ @include focus-visible;
78
+
79
+ > i {
80
+ font-size: var(--md-comp-nav-rail-icon-size);
81
+ width: var(--md-comp-nav-rail-icon-size);
82
+ height: var(--md-comp-nav-rail-icon-size);
83
+ }
84
+
85
+ &:hover {
86
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
87
+ }
88
+ }
89
+
90
+ // Optional FAB. Collapsed: icon-only 56dp. Expanded: extended.
91
+ > :is(a, button).button {
92
+ display: inline-flex;
93
+ flex: 0 0 auto;
94
+ align-items: center;
95
+ justify-content: center;
96
+ gap: 8px;
97
+ box-sizing: border-box;
98
+ width: var(--md-comp-nav-rail-fab-size);
99
+ height: var(--md-comp-nav-rail-fab-size);
100
+ margin: 4px 0 16px;
101
+ padding: 0;
102
+ overflow: hidden;
103
+ border-radius: 16px;
104
+ color: var(--md-sys-color-on-primary-container);
105
+ background-color: var(--md-sys-color-primary-container);
106
+ text-decoration: none;
107
+
108
+ > :not(i) {
109
+ position: absolute;
110
+ width: 1px;
111
+ height: 1px;
112
+ overflow: hidden;
113
+ clip-path: inset(50%);
114
+ }
115
+ }
116
+
117
+ // Destinations.
118
+ > a:not(.button),
119
+ > button:not(.button):not(:first-child) {
120
+ position: relative;
121
+ display: flex;
122
+ flex: 0 0 auto;
123
+ flex-direction: column;
124
+ align-items: center;
125
+ justify-content: center;
126
+ gap: 4px;
127
+ box-sizing: border-box;
128
+ width: 100%;
129
+ margin: 0;
130
+ padding: 6px 0;
131
+ border: 0;
132
+ background: transparent;
133
+ color: var(--md-sys-color-on-surface-variant);
134
+ cursor: pointer;
135
+ appearance: none;
136
+ text-decoration: none;
137
+ text-align: center;
138
+ @include typescale("label-medium");
139
+ @include focus-visible;
140
+
141
+ > i {
142
+ display: flex;
143
+ flex-shrink: 0;
144
+ align-items: center;
145
+ justify-content: center;
146
+ box-sizing: border-box;
147
+ width: var(--md-comp-nav-rail-indicator-width);
148
+ height: var(--md-comp-nav-rail-indicator-height);
149
+ border-radius: var(--md-comp-nav-rail-indicator-shape);
150
+ font-size: var(--md-comp-nav-rail-icon-size);
151
+ color: inherit;
152
+ transition: background-color var(--md-comp-nav-rail-duration) ease;
153
+ }
154
+
155
+ &:hover:not(.active, [aria-current]) > i {
156
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
157
+ }
158
+
159
+ &.active,
160
+ &[aria-current] {
161
+ color: var(--md-sys-color-on-surface);
162
+
163
+ > i {
164
+ background-color: var(--md-comp-nav-rail-active-indicator-color);
165
+ color: var(--md-comp-nav-rail-active-color);
166
+ --md-icon-fill: 1;
167
+ }
168
+ }
169
+
170
+ // Sibling badge (icon + label + .badge). Child-of-icon is handled
171
+ // in _badges.scss. Sit on the upper trailing corner of the 24dp glyph.
172
+ > .badge {
173
+ position: absolute;
174
+ z-index: 1;
175
+ top: calc(6px + (var(--md-comp-nav-rail-indicator-height) - 24px) / 2);
176
+ left: calc(50% + 12px);
177
+ transform: translate(-50%, -50%);
178
+ }
179
+ }
180
+
181
+ > :is(h1, h2, h3, h4, h5, h6) {
182
+ display: none;
183
+ box-sizing: border-box;
184
+ width: 100%;
185
+ margin: 0;
186
+ padding: 12px 16px 8px;
187
+ color: var(--md-sys-color-on-surface-variant);
188
+ @include typescale("title-small");
189
+ }
190
+
191
+ &.expanded {
192
+ --md-comp-nav-rail-indicator-height: 56px;
193
+ --md-comp-nav-rail-indicator-shape: 28px;
194
+
195
+ align-items: stretch;
196
+ width: clamp(220px, var(--md-comp-nav-rail-expanded-width), 360px);
197
+ min-width: 220px;
198
+ padding-inline: 16px;
199
+
200
+ > button:not(.button):first-child {
201
+ justify-content: flex-start;
202
+ width: auto;
203
+ padding-inline: 16px;
204
+ }
205
+
206
+ > :is(a, button).button {
207
+ width: 100%;
208
+ justify-content: flex-start;
209
+ padding-inline: 16px 20px;
210
+ color: var(--md-sys-color-on-primary-container);
211
+ background-color: var(--md-sys-color-primary-container);
212
+
213
+ > :not(i) {
214
+ position: static;
215
+ width: auto;
216
+ height: auto;
217
+ overflow: visible;
218
+ clip-path: none;
219
+ @include typescale("label-large");
220
+ }
221
+ }
222
+
223
+ > a:not(.button),
224
+ > button:not(.button):not(:first-child) {
225
+ flex-direction: row;
226
+ justify-content: flex-start;
227
+ gap: 12px;
228
+ min-height: var(--md-comp-nav-rail-indicator-height);
229
+ padding: 0 16px;
230
+ border-radius: var(--md-comp-nav-rail-indicator-shape);
231
+ text-align: start;
232
+
233
+ > i {
234
+ width: var(--md-comp-nav-rail-icon-size);
235
+ height: var(--md-comp-nav-rail-icon-size);
236
+ border-radius: 0;
237
+ }
238
+
239
+ &:hover:not(.active, [aria-current]) {
240
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
241
+
242
+ > i {
243
+ background-color: transparent;
244
+ }
245
+ }
246
+
247
+ &.active,
248
+ &[aria-current] {
249
+ background-color: var(--md-comp-nav-rail-active-indicator-color);
250
+ color: var(--md-comp-nav-rail-active-color);
251
+
252
+ > i {
253
+ background-color: transparent;
254
+ color: inherit;
255
+ }
256
+ }
257
+
258
+ > .badge {
259
+ top: calc((var(--md-comp-nav-rail-indicator-height) - 24px) / 2);
260
+ left: auto;
261
+ inset-inline-start: calc(16px + 24px);
262
+ transform: translate(-50%, -50%);
263
+ }
264
+ }
265
+
266
+ > :is(h1, h2, h3, h4, h5, h6) {
267
+ display: block;
268
+ }
269
+ }
270
+
271
+ &.expanded.modal {
272
+ position: fixed;
273
+ inset: 0 auto 0 0;
274
+ z-index: 998;
275
+ @include z-depth("1");
276
+
277
+ &::before {
278
+ content: "";
279
+ position: fixed;
280
+ inset: 0;
281
+ background-color: color-mix(in oklab, var(--md-sys-color-scrim) 32%, transparent);
282
+ z-index: -1;
283
+ }
284
+ }
285
+
286
+ @include bp-down("small") {
287
+ &.expanded:not(.modal) {
288
+ position: fixed;
289
+ inset: 0 auto 0 0;
290
+ z-index: 998;
291
+ @include z-depth("1");
292
+
293
+ &::before {
294
+ content: "";
295
+ position: fixed;
296
+ inset: 0;
297
+ background-color: color-mix(in oklab, var(--md-sys-color-scrim) 32%, transparent);
298
+ z-index: -1;
299
+ }
300
+ }
301
+ }
302
+ }
303
+
304
+ @media (prefers-reduced-motion: reduce) {
305
+ .navigation-rail {
306
+ transition: none;
307
+ }
308
+ }
@@ -1,27 +1,150 @@
1
1
  @use "../abstracts" as *;
2
2
 
3
- .page-footer {
3
+ // Site footer.
4
+ //
5
+ // Anatomy is the HTML. A <footer> is the landmark. A heading is a column
6
+ // title. A <nav> (or ul) is a link list. The last child <small> is the
7
+ // legal bar. A footer whose only child is nav.navigation-bar is the
8
+ // navigation bar, not this component.
9
+ //
10
+ // Tokens:
11
+ // --md-comp-footer-padding-block 3rem
12
+ // --md-comp-footer-padding-inline 1rem
13
+ // --md-comp-footer-gap 2rem
14
+ // --md-comp-footer-legal-height 48px
15
+ //
16
+ // Unfilled by default (dashed hairline). .filled uses surface-container.
17
+ // There is no JavaScript.
18
+
19
+ footer:not(:has(> .navigation-bar:only-child)) {
20
+ --md-comp-footer-padding-block: 3rem;
21
+ --md-comp-footer-padding-inline: 1rem;
22
+ --md-comp-footer-gap: 2rem;
23
+ --md-comp-footer-legal-height: 48px;
24
+
25
+ box-sizing: border-box;
4
26
  margin-top: 5rem;
5
- padding-top: 3rem;
27
+ padding: var(--md-comp-footer-padding-block) var(--md-comp-footer-padding-inline) 1rem;
6
28
  border-top: 1px dashed var(--md-sys-color-outline-variant);
29
+ color: var(--md-sys-color-on-surface);
30
+
7
31
  p {
8
- color: var(--md-sys-color-outline);
32
+ margin: 0 0 8px;
33
+ color: var(--md-sys-color-on-surface-variant);
34
+ @include typescale("body-medium");
35
+ font-family: $font-stack;
9
36
  }
10
- a {
37
+
38
+ a:not(.button, .circle, .extra) {
11
39
  color: var(--md-sys-color-primary);
40
+ text-decoration: none;
41
+ @include focus-visible;
42
+ }
43
+
44
+ :is(h1, h2, h3, h4, h5, h6) {
45
+ margin: 0 0 8px;
46
+ color: var(--md-sys-color-on-surface);
47
+ @include typescale("title-small");
48
+ font-family: $font-stack;
49
+ }
50
+
51
+ ul {
52
+ margin: 0;
53
+ padding: 0;
54
+ list-style: none;
55
+ }
56
+ }
57
+
58
+ footer:not(:has(> nav:only-child)).filled,
59
+ footer:not(:has(> nav:only-child)).surface {
60
+ background-color: var(--md-sys-color-surface-container);
61
+ border-top: 1px solid var(--md-sys-color-outline-variant);
62
+ }
63
+
64
+ // Columns: direct <nav> children. A wrapping .container is the grid
65
+ // when the author uses one. Legacy .row still spans the full measure.
66
+ footer:not(:has(> nav:only-child)) > .container,
67
+ footer:not(:has(> nav:only-child)):not(:has(> .container)) {
68
+ display: grid;
69
+ gap: var(--md-comp-footer-gap);
70
+ grid-template-columns: 1fr;
71
+
72
+ @include bp-up("small") {
73
+ grid-template-columns: repeat(2, 1fr);
74
+ }
75
+
76
+ @include bp-up("large") {
77
+ grid-template-columns: repeat(4, 1fr);
78
+ }
79
+
80
+ @include bp-up("xlarge") {
81
+ grid-template-columns: repeat(5, 1fr);
12
82
  }
13
- .footer-copyright,
14
- .footer-copyright a {
15
- overflow: hidden;
16
- min-height: 50px;
17
- display: flex;
18
- align-items: center;
19
- justify-content: space-between;
20
- padding: 10px 0px;
83
+
84
+ @include bp-up("xxlarge") {
85
+ grid-template-columns: repeat(6, 1fr);
21
86
  }
22
87
  }
23
88
 
24
- .page-footer ul {
25
- padding-left: 0;
26
- list-style-type: none;
89
+ footer:not(:has(> nav:only-child)) > .container > .row,
90
+ footer:not(:has(> nav:only-child)) > .row {
91
+ grid-column: 1 / -1;
92
+ }
93
+
94
+ footer:not(:has(> nav:only-child)) nav {
95
+ display: flex;
96
+ flex-direction: column;
97
+ align-items: flex-start;
98
+ gap: 0;
99
+ min-width: 0;
100
+ }
101
+
102
+ footer:not(:has(> nav:only-child)) nav > a:not(.button, .circle, .extra),
103
+ footer:not(:has(> nav:only-child)) ul a:not(.button, .circle, .extra) {
104
+ display: inline-flex;
105
+ align-items: center;
106
+ box-sizing: border-box;
107
+ min-height: 48px;
108
+ padding: 0 12px;
109
+ margin-inline-start: -12px;
110
+ border-radius: 2rem;
111
+ @include typescale("label-large");
112
+ font-family: $font-stack;
113
+
114
+ &:hover {
115
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
116
+ }
117
+ }
118
+
119
+ footer:not(:has(> nav:only-child)) > small:last-child {
120
+ display: flex;
121
+ flex-wrap: wrap;
122
+ align-items: center;
123
+ justify-content: space-between;
124
+ gap: 8px 16px;
125
+ box-sizing: border-box;
126
+ min-height: var(--md-comp-footer-legal-height);
127
+ margin: 0;
128
+ padding-block: 12px;
129
+ grid-column: 1 / -1;
130
+ border-top: 1px solid var(--md-sys-color-outline-variant);
131
+ color: var(--md-sys-color-on-surface-variant);
132
+ @include typescale("body-small");
133
+ font-family: $font-stack;
134
+
135
+ a:not(.button) {
136
+ color: var(--md-sys-color-primary);
137
+ }
138
+ }
139
+
140
+ // Sticky: pin the footer to the bottom of a short page. Only when the
141
+ // landmark is a direct child of body — not a footer nested in a demo.
142
+ body:has(> footer:not(:has(> nav:only-child))) {
143
+ min-height: 100dvh;
144
+ display: flex;
145
+ flex-direction: column;
146
+ }
147
+
148
+ body:has(> footer:not(:has(> nav:only-child))) > main {
149
+ flex: 1 0 auto;
27
150
  }