maverick-wave 5.38.0 → 6.0.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.
- package/README.md +63 -47
- package/maverick-wave.min.css +94 -68
- package/maverick-wave.min.js +1 -1
- package/package.json +7 -7
- package/src/js/main.js +382 -57
- package/src/scss/abstracts/_mixins.scss +35 -24
- package/src/scss/abstracts/_variables.scss +15 -0
- package/src/scss/base/_base.scss +107 -64
- package/src/scss/base/_index.scss +1 -0
- package/src/scss/base/_page-transitions.scss +29 -0
- package/src/scss/base/_reset.scss +0 -8
- package/src/scss/components/_accordions.scss +23 -18
- package/src/scss/components/_action-bar.scss +143 -0
- package/src/scss/components/_alerts.scss +13 -1
- package/src/scss/components/_avatars.scss +17 -0
- package/src/scss/components/_badge.scss +12 -0
- package/src/scss/components/_breadcrumbs.scss +10 -2
- package/src/scss/components/_chat.scss +250 -0
- package/src/scss/components/_code.scss +3 -1
- package/src/scss/components/_compare.scss +135 -0
- package/src/scss/components/_deck.scss +8 -14
- package/src/scss/components/_devices.scss +323 -0
- package/src/scss/components/_dropdown.scss +43 -2
- package/src/scss/components/_empty-state.scss +43 -0
- package/src/scss/components/_flag.scss +16 -0
- package/src/scss/components/_index.scss +6 -0
- package/src/scss/components/_lightbox.scss +1 -1
- package/src/scss/components/_marquee.scss +132 -0
- package/src/scss/components/_modals.scss +112 -83
- package/src/scss/components/_occasions.scss +62 -11
- package/src/scss/components/_pagination.scss +91 -0
- package/src/scss/components/_portrait-gallery.scss +1 -1
- package/src/scss/components/_progress.scss +122 -2
- package/src/scss/components/_segmented.scss +65 -2
- package/src/scss/components/_skeleton.scss +8 -0
- package/src/scss/components/_spinners.scss +38 -0
- package/src/scss/components/_stat.scss +232 -0
- package/src/scss/components/_stepper.scss +42 -2
- package/src/scss/components/_stories.scss +36 -22
- package/src/scss/components/_tables.scss +160 -17
- package/src/scss/components/_tabs.scss +42 -4
- package/src/scss/components/_tags.scss +39 -4
- package/src/scss/components/_tiles.scss +1 -1
- package/src/scss/components/_timelines.scss +138 -1
- package/src/scss/components/_toasts.scss +5 -1
- package/src/scss/components/_tooltip.scss +13 -0
- package/src/scss/form-elements/_checkbox.scss +40 -7
- package/src/scss/form-elements/_form.scss +2 -4
- package/src/scss/form-elements/_input.scss +9 -6
- package/src/scss/form-elements/_radio.scss +32 -3
- package/src/scss/form-elements/_select.scss +44 -1
- package/src/scss/form-elements/_slider.scss +18 -0
- package/src/scss/form-elements/_textarea.scss +9 -6
- package/src/scss/form-elements/_toggle.scss +37 -4
- package/src/scss/layout/_app-shell.scss +661 -0
- package/src/scss/layout/_bento.scss +43 -0
- package/src/scss/layout/_footer.scss +114 -2
- package/src/scss/layout/_grid.scss +7 -2
- package/src/scss/layout/_header-reveal.scss +30 -17
- package/src/scss/layout/_header.scss +21 -4
- package/src/scss/layout/_index.scss +2 -0
- package/src/scss/layout/_parallax.scss +13 -11
- package/src/scss/utilities/_accessibility.scss +4 -19
- package/src/scss/utilities/_index.scss +1 -0
- package/src/scss/utilities/_print.scss +7 -3
- package/src/scss/utilities/_reveal.scss +25 -17
- package/src/scss/utilities/_shape.scss +24 -0
- package/src/scss/utilities/_touch-targets.scss +23 -0
- package/src/scss/utilities/_variants.scss +25 -6
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
@layer mw.layout {
|
|
6
6
|
.mw-footer {
|
|
7
7
|
background: var(--mw-footer-background);
|
|
8
|
-
padding: spacing('7') spacing('0')
|
|
8
|
+
padding: spacing('7') spacing('0')
|
|
9
|
+
calc(#{spacing('7')} + env(safe-area-inset-bottom, 0px));
|
|
9
10
|
border-top: 1px solid var(--mw-border-accent);
|
|
10
11
|
|
|
11
12
|
// The same ramp .mw-grid-4 rides, read from the one place it is written
|
|
@@ -15,10 +16,21 @@
|
|
|
15
16
|
margin-bottom: spacing('6');
|
|
16
17
|
|
|
17
18
|
@include grid.column-grid(map.get(grid.$column-steps, 4));
|
|
19
|
+
|
|
20
|
+
// Two or three columns fill the row instead of leaving a slot empty
|
|
21
|
+
@include media-up('lg') {
|
|
22
|
+
&:has(> :nth-child(2):last-child) {
|
|
23
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
&:has(> :nth-child(3):last-child) {
|
|
27
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
18
30
|
}
|
|
19
31
|
|
|
20
32
|
&-column {
|
|
21
|
-
h3 {
|
|
33
|
+
:is(h2, h3, h4, .mw-footer-title) {
|
|
22
34
|
font-size: font-size('md');
|
|
23
35
|
margin-bottom: spacing('3');
|
|
24
36
|
color: var(--mw-primary-text-color);
|
|
@@ -51,6 +63,7 @@
|
|
|
51
63
|
color: var(--mw-text-muted-color);
|
|
52
64
|
text-decoration: none;
|
|
53
65
|
padding-bottom: 2px;
|
|
66
|
+
@include focus-ring;
|
|
54
67
|
|
|
55
68
|
// Always drawn, unlike the navbar's: a footer link sits in a list of
|
|
56
69
|
// them and needs to read as a link without being pointed at first
|
|
@@ -108,6 +121,7 @@
|
|
|
108
121
|
border: 1px solid var(--mw-border-accent);
|
|
109
122
|
box-shadow: var(--mw-elevation-3);
|
|
110
123
|
text-decoration: none;
|
|
124
|
+
@include focus-ring;
|
|
111
125
|
|
|
112
126
|
&:hover {
|
|
113
127
|
background: var(--mw-primary-color);
|
|
@@ -168,6 +182,78 @@
|
|
|
168
182
|
}
|
|
169
183
|
}
|
|
170
184
|
|
|
185
|
+
// Imprint, privacy, cookie settings - the links a German site must carry
|
|
186
|
+
.mw-footer-links {
|
|
187
|
+
display: flex;
|
|
188
|
+
flex-wrap: wrap;
|
|
189
|
+
justify-content: center;
|
|
190
|
+
gap: spacing('1') spacing('5');
|
|
191
|
+
margin: 0;
|
|
192
|
+
padding: 0;
|
|
193
|
+
list-style: none;
|
|
194
|
+
font-size: font-size('xs');
|
|
195
|
+
|
|
196
|
+
@include media-up('sm') {
|
|
197
|
+
font-size: font-size('sm');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
a {
|
|
201
|
+
color: var(--mw-text-muted-color);
|
|
202
|
+
text-decoration: underline;
|
|
203
|
+
text-decoration-color: color-mix(
|
|
204
|
+
in srgb,
|
|
205
|
+
currentColor 40%,
|
|
206
|
+
transparent
|
|
207
|
+
);
|
|
208
|
+
text-underline-offset: 0.25em;
|
|
209
|
+
@include focus-ring;
|
|
210
|
+
|
|
211
|
+
&:hover {
|
|
212
|
+
color: var(--mw-primary-text-color);
|
|
213
|
+
text-decoration-color: currentColor;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Copyright at one end, the links at the other; stacked and centred on a phone
|
|
219
|
+
.mw-footer-bottom {
|
|
220
|
+
display: flex;
|
|
221
|
+
flex-direction: column;
|
|
222
|
+
align-items: center;
|
|
223
|
+
gap: spacing('3');
|
|
224
|
+
margin-top: spacing('5');
|
|
225
|
+
padding-top: spacing('4');
|
|
226
|
+
border-top: 1px solid var(--mw-border-accent);
|
|
227
|
+
text-align: center;
|
|
228
|
+
|
|
229
|
+
// Also inside a wrapper that stacks the copyright over the date
|
|
230
|
+
:is(.mw-copyright, .mw-last-updated) {
|
|
231
|
+
width: auto;
|
|
232
|
+
margin: 0;
|
|
233
|
+
padding: 0;
|
|
234
|
+
border: 0;
|
|
235
|
+
text-align: inherit;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.mw-copyright + .mw-last-updated {
|
|
239
|
+
margin-top: spacing('1');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Nothing above it to set off
|
|
243
|
+
&:first-child {
|
|
244
|
+
margin-top: 0;
|
|
245
|
+
padding-top: 0;
|
|
246
|
+
border-top: 0;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
@include media-up('md') {
|
|
250
|
+
flex-direction: row;
|
|
251
|
+
flex-wrap: wrap;
|
|
252
|
+
justify-content: space-between;
|
|
253
|
+
text-align: start;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
171
257
|
.mw-last-updated {
|
|
172
258
|
text-align: center;
|
|
173
259
|
color: var(--mw-text-muted-color);
|
|
@@ -180,4 +266,30 @@
|
|
|
180
266
|
}
|
|
181
267
|
}
|
|
182
268
|
}
|
|
269
|
+
|
|
270
|
+
// An application's footer: the bottom bar alone, under the content
|
|
271
|
+
.mw-footer-compact {
|
|
272
|
+
padding-block: spacing('4')
|
|
273
|
+
calc(#{spacing('4')} + env(safe-area-inset-bottom, 0px));
|
|
274
|
+
|
|
275
|
+
.mw-footer-bottom {
|
|
276
|
+
margin-top: 0;
|
|
277
|
+
padding-top: 0;
|
|
278
|
+
border-top: 0;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// The header bar's colours, so it bookends the page in either theme
|
|
283
|
+
.mw-footer-dark {
|
|
284
|
+
--mw-footer-background: var(--mw-header-background);
|
|
285
|
+
--mw-text-color: var(--mw-header-text-color);
|
|
286
|
+
--mw-text-muted-color: var(--mw-header-navbar-list-color);
|
|
287
|
+
--mw-primary-text-color: var(--mw-header-navbar-list-active-color);
|
|
288
|
+
--mw-card-background: var(--mw-dark-card-background);
|
|
289
|
+
--mw-border-accent: var(--mw-header-border);
|
|
290
|
+
--mw-focus-ring-color: var(--mw-header-navbar-list-active-color);
|
|
291
|
+
|
|
292
|
+
color: var(--mw-text-color);
|
|
293
|
+
color-scheme: dark;
|
|
294
|
+
}
|
|
183
295
|
}
|
|
@@ -350,9 +350,12 @@ $_grid-from: ('sm', 'md', 'lg', 'xl');
|
|
|
350
350
|
@layer mw.utilities {
|
|
351
351
|
// The `:nth-child(n)` reset carries the same specificity as the cycle rules,
|
|
352
352
|
// so a narrower breakpoint can override the wider one's cycle for every child.
|
|
353
|
+
// Behind motion-safe too, or the cycle's :root guard outweighs these
|
|
353
354
|
@mixin _reveal-stagger($cols) {
|
|
354
355
|
&.mw-reveal-stagger > :nth-child(n) {
|
|
355
|
-
@include
|
|
356
|
+
@include motion-safe {
|
|
357
|
+
@include reveal-range(1);
|
|
358
|
+
}
|
|
356
359
|
}
|
|
357
360
|
|
|
358
361
|
// Guarded: Sass counts `from 2 through 1` downwards and would emit a rule
|
|
@@ -360,7 +363,9 @@ $_grid-from: ('sm', 'md', 'lg', 'xl');
|
|
|
360
363
|
@if $cols > 1 {
|
|
361
364
|
@for $i from 2 through $cols {
|
|
362
365
|
&.mw-reveal-stagger > :nth-child(#{$cols}n + #{$i}) {
|
|
363
|
-
@include
|
|
366
|
+
@include motion-safe {
|
|
367
|
+
@include reveal-range($i);
|
|
368
|
+
}
|
|
364
369
|
}
|
|
365
370
|
}
|
|
366
371
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@use '../abstracts' as *;
|
|
2
|
+
|
|
1
3
|
// Carried by the float and not by the class, or the ring would still be there in
|
|
2
4
|
// the arrived bar. Fixed values and not the elevation ramp: this lands on a
|
|
3
5
|
// picture, not on a theme surface, and the light theme cuts its shadows for paper.
|
|
@@ -9,35 +11,40 @@ $float-edge: (0 0 0 1px rgb(255 255 255 / 0.22), 0 4px 14px rgb(0 0 0 / 0.4));
|
|
|
9
11
|
// shorthand, which a consumer bundler folds together with a timeline into a
|
|
10
12
|
// declaration no browser accepts.
|
|
11
13
|
@supports (animation-timeline: scroll()) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
.mw-header-reveal {
|
|
15
|
+
@include motion-safe {
|
|
14
16
|
animation-name: mw-header-reveal;
|
|
15
17
|
animation-timing-function: var(--mw-ease-out);
|
|
16
18
|
animation-fill-mode: both;
|
|
17
19
|
animation-timeline: scroll(root);
|
|
18
20
|
animation-range: 0 420px;
|
|
19
21
|
}
|
|
22
|
+
}
|
|
20
23
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
// The bar travels, a keep element travels the same distance back and stays
|
|
25
|
+
// put - for a burger that has to be reachable while the hero is untouched.
|
|
26
|
+
.mw-header-reveal .mw-header-keep {
|
|
27
|
+
@include motion-safe {
|
|
24
28
|
animation-name: mw-header-keep;
|
|
25
29
|
animation-timing-function: var(--mw-ease-out);
|
|
26
30
|
animation-fill-mode: both;
|
|
27
31
|
animation-timeline: scroll(root);
|
|
28
32
|
animation-range: 0 420px;
|
|
29
33
|
}
|
|
34
|
+
}
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
// A group's opacity cannot be taken back by a child, so the fade goes as
|
|
37
|
+
// soon as something is meant to stay visible through it.
|
|
38
|
+
.mw-header-reveal:has(.mw-header-keep) {
|
|
39
|
+
@include motion-safe {
|
|
34
40
|
animation-name: mw-header-slide;
|
|
35
41
|
}
|
|
42
|
+
}
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
// Glued under the bar, so it leaves and arrives with it. No class of its
|
|
45
|
+
// own: a ribbon under a revealing header has no other sensible behaviour.
|
|
46
|
+
body:has(.mw-header-reveal) .mw-announcement:not(.mw-announcement-static) {
|
|
47
|
+
@include motion-safe {
|
|
41
48
|
animation-name: mw-announcement-reveal;
|
|
42
49
|
animation-timing-function: var(--mw-ease-out);
|
|
43
50
|
animation-fill-mode: both;
|
|
@@ -115,8 +122,8 @@ $float-edge: (0 0 0 1px rgb(255 255 255 / 0.22), 0 4px 14px rgb(0 0 0 / 0.4));
|
|
|
115
122
|
// No scroll timelines: the script toggles these classes instead (main.js).
|
|
116
123
|
// State and transition are separate because the script sets the state a frame
|
|
117
124
|
// earlier - together the bar would slide away in front of the reader.
|
|
118
|
-
|
|
119
|
-
|
|
125
|
+
.mw-header-reveal.mw-header-away {
|
|
126
|
+
@include motion-safe {
|
|
120
127
|
top: calc(-1 * var(--mw-header-reveal-offset));
|
|
121
128
|
opacity: 0;
|
|
122
129
|
|
|
@@ -129,8 +136,10 @@ $float-edge: (0 0 0 1px rgb(255 255 255 / 0.22), 0 4px 14px rgb(0 0 0 / 0.4));
|
|
|
129
136
|
box-shadow: $float-edge;
|
|
130
137
|
}
|
|
131
138
|
}
|
|
139
|
+
}
|
|
132
140
|
|
|
133
|
-
|
|
141
|
+
.mw-header-driven {
|
|
142
|
+
@include motion-safe {
|
|
134
143
|
// The shared list plus `top`: writing only `top` drops the bar's own.
|
|
135
144
|
transition:
|
|
136
145
|
var(--mw-transition),
|
|
@@ -142,15 +151,19 @@ $float-edge: (0 0 0 1px rgb(255 255 255 / 0.22), 0 4px 14px rgb(0 0 0 / 0.4));
|
|
|
142
151
|
box-shadow var(--mw-duration-slow) var(--mw-ease-out);
|
|
143
152
|
}
|
|
144
153
|
}
|
|
154
|
+
}
|
|
145
155
|
|
|
146
|
-
|
|
156
|
+
.mw-announcement.mw-announcement-away {
|
|
157
|
+
@include motion-safe {
|
|
147
158
|
transform: translateY(
|
|
148
159
|
calc(-1 * (var(--mw-header-height) + var(--mw-announcement-height)))
|
|
149
160
|
);
|
|
150
161
|
opacity: 0;
|
|
151
162
|
}
|
|
163
|
+
}
|
|
152
164
|
|
|
153
|
-
|
|
165
|
+
.mw-announcement-driven {
|
|
166
|
+
@include motion-safe {
|
|
154
167
|
transition:
|
|
155
168
|
transform var(--mw-duration-slow) var(--mw-ease-out),
|
|
156
169
|
opacity var(--mw-duration-slow) var(--mw-ease-out);
|
|
@@ -10,6 +10,8 @@ $_control-size: 40px;
|
|
|
10
10
|
left: spacing('0');
|
|
11
11
|
width: 100%;
|
|
12
12
|
z-index: z-index('header');
|
|
13
|
+
// Dark in both themes, fixed light included, where no light-dark() flips
|
|
14
|
+
--mw-focus-ring-color: var(--mw-header-navbar-list-active-color);
|
|
13
15
|
background: var(--mw-header-background);
|
|
14
16
|
backdrop-filter: blur(7px);
|
|
15
17
|
border-bottom: 1px solid var(--mw-header-border);
|
|
@@ -338,7 +340,7 @@ $_control-size: 40px;
|
|
|
338
340
|
}
|
|
339
341
|
|
|
340
342
|
// Last, so the current page keeps its look while being hovered
|
|
341
|
-
|
|
343
|
+
&:is(.mw-active, .active, [aria-current='page']) {
|
|
342
344
|
color: var(--mw-header-navbar-list-active-color);
|
|
343
345
|
background: var(--mw-primary-background);
|
|
344
346
|
// Marks the left edge of a stacked list. In a row the links are pills
|
|
@@ -369,7 +371,7 @@ $_control-size: 40px;
|
|
|
369
371
|
}
|
|
370
372
|
}
|
|
371
373
|
|
|
372
|
-
@
|
|
374
|
+
@include motion-reduced {
|
|
373
375
|
transition-duration: 0.01ms;
|
|
374
376
|
|
|
375
377
|
.mw-navbar-item {
|
|
@@ -470,13 +472,15 @@ $_control-size: 40px;
|
|
|
470
472
|
|
|
471
473
|
&:hover,
|
|
472
474
|
&.mw-active,
|
|
473
|
-
&.active
|
|
475
|
+
&.active,
|
|
476
|
+
&[aria-current='page'] {
|
|
474
477
|
color: var(--mw-header-navbar-list-active-color);
|
|
475
478
|
}
|
|
476
479
|
|
|
477
480
|
&:hover::after,
|
|
478
481
|
&.mw-active::after,
|
|
479
|
-
&.active::after
|
|
482
|
+
&.active::after,
|
|
483
|
+
&[aria-current='page']::after {
|
|
480
484
|
transform: scaleX(1);
|
|
481
485
|
opacity: 1;
|
|
482
486
|
}
|
|
@@ -573,4 +577,17 @@ $_control-size: 40px;
|
|
|
573
577
|
}
|
|
574
578
|
}
|
|
575
579
|
}
|
|
580
|
+
|
|
581
|
+
// Menus in the bar lie on the page's card, so their ring is the page's
|
|
582
|
+
.mw-header .mw-dropdown-menu {
|
|
583
|
+
--mw-focus-ring-color: var(--mw-primary-text-color);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Forced colours paint the drawn line away; the current page gets a real one
|
|
587
|
+
@media (forced-colors: active) {
|
|
588
|
+
.mw-navbar-link:is(.mw-active, .active, [aria-current='page']) {
|
|
589
|
+
text-decoration: underline 2px;
|
|
590
|
+
text-underline-offset: 0.35em;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
576
593
|
}
|
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
@supports (animation-timeline: view()) {
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
.mw-parallax-slow {
|
|
108
|
+
@include motion-safe {
|
|
109
109
|
animation-name: mw-parallax-band;
|
|
110
110
|
animation-timing-function: linear;
|
|
111
111
|
animation-fill-mode: both;
|
|
@@ -188,19 +188,21 @@
|
|
|
188
188
|
// `animation:` that cannot carry a timeline. The default range is the whole
|
|
189
189
|
// cover pass, so the band keeps moving as long as any part of it is on screen.
|
|
190
190
|
@supports (animation-timeline: view()) {
|
|
191
|
-
|
|
192
|
-
|
|
191
|
+
.mw-parallax-media {
|
|
192
|
+
@include motion-safe {
|
|
193
193
|
animation-name: mw-parallax;
|
|
194
194
|
animation-timing-function: linear;
|
|
195
195
|
animation-fill-mode: both;
|
|
196
196
|
animation-timeline: view();
|
|
197
197
|
}
|
|
198
|
+
}
|
|
198
199
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
200
|
+
// A pinned block does not travel through the viewport, so its view()
|
|
201
|
+
// timeline stands still with it. The document's own scroll is what the
|
|
202
|
+
// picture has left to play against - over the first screen, because after
|
|
203
|
+
// that the page has covered it anyway.
|
|
204
|
+
.mw-parallax-sticky .mw-parallax-media {
|
|
205
|
+
@include motion-safe {
|
|
204
206
|
animation-timeline: scroll(root);
|
|
205
207
|
animation-range: 0 100dvh;
|
|
206
208
|
}
|
|
@@ -213,8 +215,8 @@
|
|
|
213
215
|
// inline `--mw-parallax-depth` - go on working untouched.
|
|
214
216
|
//
|
|
215
217
|
// 0 puts the layer at +depth and 1 at -depth, the two ends of the keyframes.
|
|
216
|
-
|
|
217
|
-
|
|
218
|
+
.mw-parallax-driven {
|
|
219
|
+
@include motion-safe {
|
|
218
220
|
transform: translate3d(
|
|
219
221
|
0,
|
|
220
222
|
calc(var(--mw-parallax-depth) * (1 - 2 * var(--mw-parallax-progress))),
|
|
@@ -2,15 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
@layer mw.utilities {
|
|
4
4
|
.mw-sr-only {
|
|
5
|
-
|
|
6
|
-
width: 1px;
|
|
7
|
-
height: 1px;
|
|
8
|
-
padding: 0;
|
|
9
|
-
margin: -1px;
|
|
10
|
-
overflow: hidden;
|
|
11
|
-
clip-path: inset(50%);
|
|
12
|
-
white-space: nowrap;
|
|
13
|
-
border: 0;
|
|
5
|
+
@include visually-hidden;
|
|
14
6
|
}
|
|
15
7
|
|
|
16
8
|
// The first thing a keyboard user meets on the page: a link that jumps past the
|
|
@@ -28,11 +20,12 @@
|
|
|
28
20
|
background: var(--mw-primary-color);
|
|
29
21
|
color: var(--mw-primary-accent-text-color);
|
|
30
22
|
font-weight: font-weight('medium');
|
|
31
|
-
box-shadow: var(--mw-elevation-3);
|
|
32
23
|
transform: translateY(calc(-100% - #{spacing('5')}));
|
|
33
24
|
transition: transform var(--mw-duration-fast) var(--mw-ease-out);
|
|
34
25
|
|
|
26
|
+
// Only on focus: parked above the edge, the shadow still reached into view
|
|
35
27
|
&:focus-visible {
|
|
28
|
+
box-shadow: var(--mw-elevation-3);
|
|
36
29
|
transform: translateY(0);
|
|
37
30
|
}
|
|
38
31
|
}
|
|
@@ -40,14 +33,6 @@
|
|
|
40
33
|
// Content that is there for a screen reader but comes back on focus - the same
|
|
41
34
|
// idea as sr-only, for something that has to be reachable by tab.
|
|
42
35
|
.mw-sr-only-focusable:not(:focus):not(:focus-within) {
|
|
43
|
-
|
|
44
|
-
width: 1px;
|
|
45
|
-
height: 1px;
|
|
46
|
-
padding: 0;
|
|
47
|
-
margin: -1px;
|
|
48
|
-
overflow: hidden;
|
|
49
|
-
clip-path: inset(50%);
|
|
50
|
-
white-space: nowrap;
|
|
51
|
-
border: 0;
|
|
36
|
+
@include visually-hidden;
|
|
52
37
|
}
|
|
53
38
|
}
|
|
@@ -12,10 +12,9 @@
|
|
|
12
12
|
|
|
13
13
|
@media print {
|
|
14
14
|
// Paper is white and ink is black, whatever the screen was told to be. The
|
|
15
|
-
//
|
|
16
|
-
// down the tree and would otherwise shadow the one on :root.
|
|
15
|
+
// dark footer brings its own copy of these, which would shadow the root's.
|
|
17
16
|
:root,
|
|
18
|
-
.mw-
|
|
17
|
+
.mw-footer-dark {
|
|
19
18
|
--mw-page-background: #fff;
|
|
20
19
|
--mw-card-background: #fff;
|
|
21
20
|
--mw-footer-background: #fff;
|
|
@@ -38,6 +37,11 @@
|
|
|
38
37
|
color: #000;
|
|
39
38
|
}
|
|
40
39
|
|
|
40
|
+
.mw-footer-dark {
|
|
41
|
+
--mw-primary-text-color: inherit;
|
|
42
|
+
color-scheme: light;
|
|
43
|
+
}
|
|
44
|
+
|
|
41
45
|
// Chrome that is fixed on screen would print on the first page and cover
|
|
42
46
|
// what is underneath, and navigation is useless on paper either way.
|
|
43
47
|
.mw-header,
|
|
@@ -10,26 +10,30 @@
|
|
|
10
10
|
// context. Longhands and never the shorthand, which esbuild collapses into one
|
|
11
11
|
// `animation:` that cannot carry a timeline.
|
|
12
12
|
@supports (animation-timeline: view()) {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
:root:not(.mw-scroll-static) :is(.mw-reveal, .mw-reveal-stagger > *) {
|
|
14
|
+
@include motion-safe {
|
|
15
15
|
animation-name: mw-reveal;
|
|
16
16
|
animation-timing-function: var(--mw-ease-out);
|
|
17
17
|
animation-fill-mode: backwards;
|
|
18
18
|
animation-timeline: view();
|
|
19
19
|
@include reveal-range(1);
|
|
20
20
|
}
|
|
21
|
+
}
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
// A row crosses the viewport edge on one scroll step, so mw-reveal on each
|
|
24
|
+
// card rises as one slab. This shifts every second and third child instead -
|
|
25
|
+
// a wave. On the grid and not the cards, because the grid knows the columns.
|
|
26
|
+
//
|
|
27
|
+
// Cycles of three are the fallback for anything that is not one of the fixed
|
|
28
|
+
// grids; mw-grid-2 to -5 restate the cycle to their own count in _grid.scss.
|
|
29
|
+
.mw-reveal-stagger > :nth-child(3n + 2) {
|
|
30
|
+
@include motion-safe {
|
|
29
31
|
@include reveal-range(2);
|
|
30
32
|
}
|
|
33
|
+
}
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
.mw-reveal-stagger > :nth-child(3n + 3) {
|
|
36
|
+
@include motion-safe {
|
|
33
37
|
@include reveal-range(3);
|
|
34
38
|
}
|
|
35
39
|
}
|
|
@@ -40,21 +44,25 @@
|
|
|
40
44
|
// waits below the fold, `mw-reveal-run` once it enters. Both classes are
|
|
41
45
|
// added by the script and never by the markup - a page without JS keeps
|
|
42
46
|
// everything visible, which is what the guard above is for.
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
.mw-reveal-hidden {
|
|
48
|
+
@include motion-safe {
|
|
45
49
|
opacity: 0;
|
|
46
50
|
transform: translateY(40px);
|
|
47
51
|
}
|
|
52
|
+
}
|
|
48
53
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
// The script has already hidden whatever was below the fold when the class
|
|
55
|
+
// arrives, and it only ever un-hides on intersection - without this the
|
|
56
|
+
// switch would leave those elements invisible instead of static.
|
|
57
|
+
:root.mw-scroll-static .mw-reveal-hidden {
|
|
58
|
+
@include motion-safe {
|
|
53
59
|
opacity: 1;
|
|
54
60
|
transform: none;
|
|
55
61
|
}
|
|
62
|
+
}
|
|
56
63
|
|
|
57
|
-
|
|
64
|
+
.mw-reveal-run {
|
|
65
|
+
@include motion-safe {
|
|
58
66
|
// `backwards` for the reason above - a forwards fill would pin the
|
|
59
67
|
// transform and cost the card its hover lift. The delay comes inline,
|
|
60
68
|
// from the element's column.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
@use '../abstracts' as *;
|
|
2
|
+
|
|
3
|
+
@layer mw.utilities {
|
|
4
|
+
// `clip`, not `hidden`: a wrapper clips without becoming a scroll container
|
|
5
|
+
.mw-shape-arch,
|
|
6
|
+
.mw-shape-signature,
|
|
7
|
+
.mw-shape-leaf {
|
|
8
|
+
overflow: clip;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Oversized radii are scaled down together, which lands on a half circle
|
|
12
|
+
.mw-shape-arch {
|
|
13
|
+
border-radius: 999px 999px 0 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.mw-shape-signature {
|
|
17
|
+
border-radius: radius-sharp() radius('xl') radius-sharp() radius('xl');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// The silhouette taken to its end: the round pair opened up to the full side
|
|
21
|
+
.mw-shape-leaf {
|
|
22
|
+
border-radius: radius-sharp() 50% radius-sharp() 50%;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -62,6 +62,29 @@
|
|
|
62
62
|
align-items: center;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
// Footer links grow to a target; the text's own underline replaces the drawn one
|
|
66
|
+
.mw-footer-column li a,
|
|
67
|
+
.mw-footer-links a {
|
|
68
|
+
display: inline-flex;
|
|
69
|
+
align-items: center;
|
|
70
|
+
min-height: 2.5rem;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.mw-footer-column li a {
|
|
74
|
+
text-decoration: underline;
|
|
75
|
+
text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
|
|
76
|
+
text-underline-offset: 0.25em;
|
|
77
|
+
|
|
78
|
+
&::after {
|
|
79
|
+
content: none;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.mw-footer .mw-social-links a {
|
|
84
|
+
min-width: 2.75rem;
|
|
85
|
+
min-height: 2.75rem;
|
|
86
|
+
}
|
|
87
|
+
|
|
65
88
|
// A checkbox or radio is tapped by its label as much as by the box, so the
|
|
66
89
|
// whole row has to be the target - which it only is if the row is tall enough
|
|
67
90
|
.mw-checkbox,
|
|
@@ -44,12 +44,7 @@
|
|
|
44
44
|
// page, told apart by their line alone. That line then has to carry them:
|
|
45
45
|
// --mw-border is a neighbouring shade of the surface and reads as nothing once
|
|
46
46
|
// the surface *is* the page, so it is redrawn from the ink instead.
|
|
47
|
-
|
|
48
|
-
// Theme-bound tokens, and those *are* re-declared on <body> when the toggle puts
|
|
49
|
-
// .mw-theme-light there - a value written on :root alone would be shadowed for
|
|
50
|
-
// the whole body subtree and the switch would do nothing in light mode.
|
|
51
|
-
:root.mw-surfaces-flush,
|
|
52
|
-
:root.mw-surfaces-flush .mw-theme-light {
|
|
47
|
+
:root.mw-surfaces-flush {
|
|
53
48
|
--mw-card-background: var(--mw-page-background);
|
|
54
49
|
--mw-footer-background: var(--mw-page-background);
|
|
55
50
|
--mw-border: color-mix(in srgb, var(--mw-text-color) 20%, transparent);
|
|
@@ -227,3 +222,27 @@
|
|
|
227
222
|
}
|
|
228
223
|
}
|
|
229
224
|
}
|
|
225
|
+
|
|
226
|
+
@layer mw.utilities {
|
|
227
|
+
// Near-black from a root source: ink would be a light slab on a dark page
|
|
228
|
+
:root.mw-shadows-hard {
|
|
229
|
+
--mw-shadow-hard: oklch(from var(--mw-light-text-color) min(l, 0.12) c h);
|
|
230
|
+
|
|
231
|
+
@each $level, $offset in (1: 2px, 2: 4px, 3: 6px, 4: 8px, 5: 10px) {
|
|
232
|
+
--mw-elevation-#{$level}: #{$offset} #{$offset} 0 var(--mw-shadow-hard);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@layer mw.utilities {
|
|
238
|
+
// Black or white per fill by contrast-color(); without it the set tokens stay
|
|
239
|
+
@supports (color: contrast-color(red)) {
|
|
240
|
+
:root.mw-accent-text-auto {
|
|
241
|
+
@each $name in (primary, secondary, success, warning, danger, info) {
|
|
242
|
+
--mw-#{$name}-accent-text-color: contrast-color(
|
|
243
|
+
var(--mw-#{$name}-color)
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|