maverick-wave 5.33.0 → 5.34.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.
@@ -0,0 +1,700 @@
1
+ @use 'sass:map';
2
+ @use '../abstracts' as *;
3
+ @use 'buttons';
4
+ @use 'deck-blocks';
5
+
6
+ @layer mw.components {
7
+ // The theme's dark inks are cut for 3:1 on a card. A slide sets small type
8
+ // in them on the page ground, and a projector takes a share of every contrast.
9
+ $_ink-dark: 0.66;
10
+ $_primary-ink-dark: ink-on-dark('primary-color', $_ink-dark);
11
+ $_secondary-ink-dark: ink-on-dark('secondary-color', $_ink-dark);
12
+
13
+ // What a slide, and the chrome over it, paints with. Every surface a slide can
14
+ // have sets all of them, so a block never has to know which surface it sits
15
+ // on. `mark` is the brand as ink on that surface, `fill` the brand as a solid
16
+ // with `fill-ink` on top; `accent` and `accent-fill` are the same pair in the
17
+ // second colour, which the chrome over the slides wears.
18
+ $_tones: (
19
+ 'page': (
20
+ ground: var(--mw-page-background),
21
+ ink: var(--mw-text-color),
22
+ mark: var(--mw-deck-first-ink),
23
+ fill: var(--mw-primary-color),
24
+ fill-ink: var(--mw-primary-accent-text-color),
25
+ accent: var(--mw-deck-second-ink),
26
+ accent-fill: var(--mw-deck-second),
27
+ accent-fill-ink: var(--mw-deck-second-label),
28
+ ),
29
+ 'surface': (
30
+ ground: var(--mw-card-background),
31
+ ink: var(--mw-text-color),
32
+ mark: var(--mw-deck-first-ink),
33
+ fill: var(--mw-primary-color),
34
+ fill-ink: var(--mw-primary-accent-text-color),
35
+ accent: var(--mw-deck-second-ink),
36
+ accent-fill: var(--mw-deck-second),
37
+ accent-fill-ink: var(--mw-deck-second-label),
38
+ ),
39
+ // The header bar's surface: dark in both themes and tinted with the brand,
40
+ // and its active link colour is already cut to read on it
41
+ 'dark': (
42
+ ground: var(--mw-header-background),
43
+ ink: var(--mw-header-text-color),
44
+ mark: var(--mw-header-navbar-list-active-color),
45
+ fill: var(--mw-primary-color),
46
+ fill-ink: var(--mw-primary-accent-text-color),
47
+ accent: var(--mw-deck-second-ink-dark),
48
+ accent-fill: var(--mw-deck-second),
49
+ accent-fill-ink: var(--mw-deck-second-label),
50
+ ),
51
+ // The second colour on the first one rarely holds a 2px line - here the
52
+ // chrome takes the label colour instead
53
+ 'primary': (
54
+ ground: var(--mw-primary-color),
55
+ ink: var(--mw-primary-accent-text-color),
56
+ mark: var(--mw-primary-accent-text-color),
57
+ fill: var(--mw-primary-accent-text-color),
58
+ fill-ink: var(--mw-primary-color),
59
+ accent: var(--mw-primary-accent-text-color),
60
+ accent-fill: var(--mw-primary-accent-text-color),
61
+ accent-fill-ink: var(--mw-primary-color),
62
+ ),
63
+ // A photo under a dark gradient - judged against black, like the hero
64
+ 'cover': (
65
+ ground: $fixed-stage,
66
+ ink: $fixed-surface-text,
67
+ mark: ink-on-dark('primary-color', $hero-ink-lightness),
68
+ fill: var(--mw-primary-color),
69
+ fill-ink: var(--mw-primary-accent-text-color),
70
+ accent: var(--mw-deck-second-ink-dark),
71
+ accent-fill: var(--mw-deck-second),
72
+ accent-fill-ink: var(--mw-deck-second-label),
73
+ ),
74
+ );
75
+
76
+ @mixin tone($name) {
77
+ @each $key, $value in map.get($_tones, $name) {
78
+ --mw-deck-#{$key}: #{$value};
79
+ }
80
+ }
81
+
82
+ // The deck is the page: put it on <body>. Everything inside is placed
83
+ // against it rather than the viewport, so it also works in a box of its own.
84
+ .mw-deck {
85
+ // The second colour of the site, as the chrome uses it. Pointed at the
86
+ // primary by .mw-deck-accent-primary below, or site-wide by
87
+ // .mw-accent-single on <html>, which makes the second colour the first.
88
+ --mw-deck-second: var(--mw-secondary-color);
89
+ --mw-deck-second-label: var(--mw-secondary-accent-text-color);
90
+ --mw-deck-second-ink: var(--mw-secondary-text-color);
91
+ --mw-deck-second-ink-dark: #{$_secondary-ink-dark};
92
+ --mw-deck-first-ink: var(--mw-primary-text-color);
93
+
94
+ // A browser without light-dark() keeps the theme's own inks
95
+ @supports (color: light-dark(#000, #fff)) {
96
+ --mw-deck-first-ink: light-dark(
97
+ var(--mw-light-primary-text-color),
98
+ #{$_primary-ink-dark}
99
+ );
100
+ --mw-deck-second-ink: light-dark(
101
+ var(--mw-light-secondary-text-color),
102
+ #{$_secondary-ink-dark}
103
+ );
104
+ }
105
+
106
+ @include tone('page');
107
+
108
+ // vmin rather than the fluid() ramp: a slide has to fit its height as much
109
+ // as its width, and on a beamer the height is the short side
110
+ --mw-deck-gutter: clamp(1.25rem, 4.6vmin, 4.75rem);
111
+ --mw-deck-text-xl: clamp(2.6rem, 8.8vmin, 8.6rem);
112
+ --mw-deck-text-lg: clamp(1.9rem, 5.6vmin, 5.2rem);
113
+ --mw-deck-text-md: clamp(1.25rem, 3.1vmin, 2.6rem);
114
+ --mw-deck-text: clamp(1rem, 2.05vmin, 1.4rem);
115
+ --mw-deck-text-sm: clamp(0.76rem, 1.45vmin, 1rem);
116
+ // The voice of the titles - the knobs a brand turns next to its colours
117
+ --mw-deck-title-weight: 600;
118
+ --mw-deck-title-tracking: -0.035em;
119
+ --mw-deck-title-leading: 0.98;
120
+ --mw-deck-title-case: none;
121
+ // currentColor resolves where the token is used, so one line and one muted
122
+ // tone serve every surface
123
+ --mw-deck-line: color-mix(in srgb, currentColor 16%, transparent);
124
+ --mw-deck-muted: color-mix(in oklab, currentColor 72%, transparent);
125
+ --mw-deck-radius: #{radius('sm')};
126
+ // Written by the script, read by the progress bar
127
+ --mw-deck-progress: 0;
128
+
129
+ position: relative;
130
+ height: 100vh;
131
+ height: 100dvh;
132
+ overflow: hidden;
133
+ background-color: var(--mw-page-background);
134
+ color: var(--mw-deck-ink);
135
+ font-size: var(--mw-deck-text);
136
+ line-height: 1.5;
137
+ text-rendering: optimizeLegibility;
138
+ }
139
+
140
+ // One brand colour in the chrome: the second one gives way to the first
141
+ .mw-deck-accent-primary {
142
+ --mw-deck-second: var(--mw-primary-color);
143
+ --mw-deck-second-label: var(--mw-primary-accent-text-color);
144
+ --mw-deck-second-ink: var(--mw-deck-first-ink);
145
+ --mw-deck-second-ink-dark: var(--mw-header-navbar-list-active-color);
146
+ }
147
+
148
+ // A deck page is exactly the window: nothing scrolls past it, and the reset's
149
+ // 320px floor goes - an embedded phone deck is often narrower than that, and
150
+ // the floor pushed its right edge out of the frame
151
+ :root:has(> body.mw-deck) {
152
+ min-width: 0;
153
+ overflow: hidden;
154
+ }
155
+
156
+ // The base layer spaces headings and paragraphs for a page of text; a slide
157
+ // places every block itself
158
+ :where(.mw-deck)
159
+ :where(h1, h2, h3, h4, p, ul, ol, dl, dd, figure, blockquote) {
160
+ margin: 0;
161
+ }
162
+
163
+ // The reset clears ul only; steps and notes number themselves
164
+ :where(.mw-deck) ol {
165
+ list-style: none;
166
+ }
167
+
168
+ // Big type in a phone-wide column: a German compound breaks mid-word
169
+ // otherwise. Only long words, so a headline does not fill with hyphens.
170
+ :where(.mw-deck) :where(h1, h2, h3, .mw-deck-title, .mw-deck-aside-title) {
171
+ hyphens: auto;
172
+ hyphenate-limit-chars: 10 4 4;
173
+ }
174
+
175
+ :where(.mw-deck) a {
176
+ color: inherit;
177
+ }
178
+
179
+ .mw-deck-head,
180
+ .mw-deck-foot {
181
+ z-index: 5;
182
+ display: flex;
183
+ align-items: center;
184
+ color: var(--mw-deck-ink);
185
+ font-size: var(--mw-deck-text-sm);
186
+ // The bars lie over the slide: only their controls may catch a click
187
+ pointer-events: none;
188
+ transition: color var(--mw-duration-slow) var(--mw-ease-out);
189
+
190
+ > * {
191
+ pointer-events: auto;
192
+ }
193
+ }
194
+
195
+ .mw-deck-head {
196
+ justify-content: space-between;
197
+ gap: spacing('5');
198
+ }
199
+
200
+ .mw-deck-brand {
201
+ font-weight: 600;
202
+ letter-spacing: 0.02em;
203
+
204
+ small {
205
+ display: block;
206
+ margin-top: 0.15em;
207
+ color: inherit;
208
+ font-size: 0.82em;
209
+ font-weight: 400;
210
+ letter-spacing: 0.04em;
211
+ opacity: 0.7;
212
+ }
213
+ }
214
+
215
+ .mw-deck-tools,
216
+ .mw-deck-arrows {
217
+ display: flex;
218
+ align-items: center;
219
+ gap: spacing('3');
220
+ }
221
+
222
+ // A long brand note wraps, the counter and the button keep their line
223
+ .mw-deck-tools {
224
+ flex: none;
225
+ gap: spacing('4');
226
+ }
227
+
228
+ .mw-deck-counter {
229
+ color: color-mix(in srgb, currentColor 75%, transparent);
230
+ font-variant-numeric: tabular-nums;
231
+ letter-spacing: 0.06em;
232
+ white-space: nowrap;
233
+ }
234
+
235
+ .mw-deck-counter-current {
236
+ color: var(--mw-deck-accent);
237
+ font-weight: 700;
238
+ }
239
+
240
+ // An outline button drawn in whatever ink the current slide hands the
241
+ // chrome, filled with the second colour under the pointer
242
+ .mw-deck-btn {
243
+ display: inline-grid;
244
+ place-items: center;
245
+ flex: none;
246
+ width: 2.5rem;
247
+ height: 2.5rem;
248
+ padding: spacing('0');
249
+ border: 1px solid color-mix(in srgb, currentColor 32%, transparent);
250
+ border-radius: radius('full');
251
+ background: color-mix(in srgb, currentColor 6%, transparent);
252
+ color: inherit;
253
+ cursor: pointer;
254
+ transition: var(--mw-transition-fast);
255
+ @include tappable;
256
+ @include focus-ring(3px, currentColor);
257
+
258
+ svg {
259
+ width: 1.05rem;
260
+ height: 1.05rem;
261
+ fill: none;
262
+ stroke: currentColor;
263
+ stroke-width: 1.8;
264
+ stroke-linecap: round;
265
+ stroke-linejoin: round;
266
+ }
267
+
268
+ // Only under a pointer: a tap on a tablet would leave the fill standing
269
+ @include hover {
270
+ border-color: var(--mw-deck-accent-fill);
271
+ background: var(--mw-deck-accent-fill);
272
+ color: var(--mw-deck-accent-fill-ink);
273
+ }
274
+
275
+ &:active {
276
+ transform: scale(0.92);
277
+ transition-duration: var(--mw-duration-instant);
278
+ }
279
+ }
280
+
281
+ // A class the script sets, not :fullscreen - a browser that only knows the
282
+ // prefixed pseudo-class would drop the whole rule and show both icons
283
+ .mw-deck-icon-collapse,
284
+ .mw-deck-fullscreen .mw-deck-icon-expand {
285
+ display: none;
286
+ }
287
+
288
+ .mw-deck-fullscreen .mw-deck-icon-collapse {
289
+ display: block;
290
+ }
291
+
292
+ .mw-deck-progress {
293
+ flex: 1;
294
+ height: 2px;
295
+ background: var(--mw-deck-line);
296
+
297
+ &::after {
298
+ content: '';
299
+ display: block;
300
+ height: 100%;
301
+ background: var(--mw-deck-accent);
302
+ transform: scaleX(var(--mw-deck-progress));
303
+ transform-origin: left;
304
+ transition: transform var(--mw-duration-zoom) var(--mw-ease-out);
305
+ }
306
+ }
307
+
308
+ // Positioned, so a slide's offsetLeft and offsetTop are its scroll position
309
+ .mw-deck-slides {
310
+ position: relative;
311
+ height: 100%;
312
+ }
313
+
314
+ // Until the script runs - and if it never does - the slides keep their
315
+ // scrollbar to be moved with, and the controls that would do nothing stay
316
+ // out of sight
317
+ .mw-deck-ready .mw-deck-slides {
318
+ scrollbar-width: none;
319
+
320
+ &::-webkit-scrollbar {
321
+ display: none;
322
+ }
323
+ }
324
+
325
+ .mw-deck:not(.mw-deck-ready)
326
+ :is(
327
+ [data-deck-next],
328
+ [data-deck-prev],
329
+ [data-deck-fullscreen],
330
+ .mw-deck-counter,
331
+ .mw-deck-progress
332
+ ) {
333
+ visibility: hidden;
334
+ }
335
+
336
+ .mw-slide {
337
+ @include tone('page');
338
+
339
+ position: relative;
340
+ display: grid;
341
+ overflow: hidden;
342
+ background-color: var(--mw-deck-ground);
343
+ color: var(--mw-deck-ink);
344
+ scroll-snap-align: start;
345
+ scroll-snap-stop: always;
346
+ --mw-corner-accent: var(--mw-deck-mark);
347
+ }
348
+
349
+ @each $name in ('surface', 'dark', 'primary', 'cover') {
350
+ .mw-slide-#{$name} {
351
+ @include tone($name);
352
+ }
353
+ }
354
+
355
+ // The chrome follows the slide on screen. The slides set their own tone
356
+ // above, so what this puts on the chrome never reaches them. Behind
357
+ // @supports so the minifier cannot fold it into the rules above: a browser
358
+ // without :has() would drop the slide tones along with it.
359
+ @supports selector(:has(*)) {
360
+ @each $name in ('surface', 'dark', 'primary', 'cover') {
361
+ .mw-deck:has(.mw-slide-#{$name}.mw-active)
362
+ :is(.mw-deck-head, .mw-deck-foot, .mw-deck-segments, .mw-deck-stage) {
363
+ @include tone($name);
364
+ }
365
+ }
366
+ }
367
+
368
+ .mw-deck-landscape {
369
+ .mw-deck-head {
370
+ position: absolute;
371
+ inset: 0 0 auto;
372
+ padding: calc(var(--mw-deck-gutter) * 0.6) var(--mw-deck-gutter);
373
+ }
374
+
375
+ .mw-deck-foot {
376
+ position: absolute;
377
+ inset: auto 0 0;
378
+ gap: spacing('6');
379
+ padding: 0 var(--mw-deck-gutter) calc(var(--mw-deck-gutter) * 0.55);
380
+ }
381
+
382
+ .mw-deck-slides {
383
+ display: flex;
384
+ overflow: auto hidden;
385
+ scroll-snap-type: x mandatory;
386
+ // Only sideways: the back gesture stays off, a page around an embedded
387
+ // deck still scrolls on
388
+ overscroll-behavior-x: contain;
389
+ }
390
+
391
+ // Never less than the bars over it need: head and foot carry a 2.5rem
392
+ // button each, and at a small gutter the multiples alone fall short
393
+ .mw-slide {
394
+ flex: 0 0 100%;
395
+ height: 100%;
396
+ padding: max(
397
+ var(--mw-deck-gutter) * 2.3,
398
+ var(--mw-deck-gutter) * 1.2 + 2.5rem
399
+ )
400
+ var(--mw-deck-gutter)
401
+ max(var(--mw-deck-gutter) * 2.4, var(--mw-deck-gutter) * 1.15 + 2.5rem);
402
+ }
403
+
404
+ .mw-slide-split {
405
+ grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
406
+ column-gap: 7vmin;
407
+ align-items: center;
408
+ }
409
+
410
+ .mw-slide-reverse > :first-child {
411
+ order: 2;
412
+ }
413
+
414
+ .mw-slide-statement,
415
+ .mw-slide-cover {
416
+ align-content: end;
417
+ }
418
+
419
+ .mw-slide-stack {
420
+ row-gap: 8vmin;
421
+ align-content: center;
422
+ }
423
+
424
+ // A tablet held upright: the two columns stack, the picture on top
425
+ @media (orientation: portrait) {
426
+ .mw-slide-split {
427
+ grid-template-columns: minmax(0, 1fr);
428
+ grid-template-rows: minmax(0, 1fr) auto;
429
+ row-gap: 5vmin;
430
+ align-items: end;
431
+ }
432
+
433
+ .mw-slide-reverse > :first-child {
434
+ order: 0;
435
+ }
436
+ }
437
+
438
+ // A phone turned sideways, where the rotate hint sends it: 390px of
439
+ // height do not hold the rem floors of the scale
440
+ @media (orientation: landscape) and (height < 500px) {
441
+ --mw-deck-gutter: 1rem;
442
+ --mw-deck-text-xl: 2rem;
443
+ --mw-deck-text-lg: 1.5rem;
444
+ --mw-deck-text-md: 1.05rem;
445
+ --mw-deck-text: 0.85rem;
446
+ --mw-deck-text-sm: 0.7rem;
447
+
448
+ // What still does not fit scrolls inside its slide, and the bars turn
449
+ // solid so the text never runs beneath the counter
450
+ .mw-deck-head,
451
+ .mw-deck-foot {
452
+ background-color: var(--mw-deck-ground);
453
+ transition-property: color, background-color;
454
+ }
455
+
456
+ // A squeezed row spills past the padding, under the foot and out of reach
457
+ .mw-slide {
458
+ grid-auto-rows: max-content;
459
+ overflow: hidden auto;
460
+ overscroll-behavior-y: contain;
461
+ }
462
+
463
+ // safe keeps an overflow off the top edge; start where it is unknown
464
+ .mw-slide-stack {
465
+ align-content: start;
466
+ align-content: safe center;
467
+ }
468
+
469
+ .mw-slide-statement,
470
+ .mw-slide-cover {
471
+ align-content: start;
472
+ align-content: safe end;
473
+ }
474
+ }
475
+ }
476
+
477
+ .mw-deck-portrait {
478
+ // Against the phone's width, not the window's: on a desktop the slides
479
+ // stay a phone
480
+ --mw-deck-text-xl: clamp(2.2rem, 12cqi, 3.5rem);
481
+ --mw-deck-text-lg: clamp(1.75rem, 9cqi, 2.7rem);
482
+ --mw-deck-text-md: clamp(1.2rem, 6cqi, 1.65rem);
483
+ --mw-deck-text: clamp(0.95rem, 4.2cqi, 1.1rem);
484
+ --mw-deck-text-sm: clamp(0.72rem, 3.2cqi, 0.86rem);
485
+ --mw-deck-gutter: 1.4rem;
486
+
487
+ background-color: var(--mw-footer-background);
488
+
489
+ .mw-deck-stage {
490
+ position: absolute;
491
+ inset: 0;
492
+ overflow: hidden;
493
+ container-type: inline-size;
494
+ background-color: var(--mw-page-background);
495
+
496
+ // Keeps the counter and the segments readable over a bright picture
497
+ &::before {
498
+ content: '';
499
+ position: absolute;
500
+ inset: 0 0 auto;
501
+ z-index: 4;
502
+ height: 7rem;
503
+ background: linear-gradient(
504
+ color-mix(in srgb, var(--mw-deck-ground) 85%, transparent),
505
+ color-mix(in srgb, var(--mw-deck-ground) 60%, transparent) 55%,
506
+ transparent
507
+ );
508
+ pointer-events: none;
509
+ }
510
+ }
511
+
512
+ .mw-deck-segments {
513
+ position: absolute;
514
+ top: max(#{spacing('4')}, env(safe-area-inset-top));
515
+ right: spacing('5');
516
+ left: spacing('5');
517
+ z-index: 5;
518
+ display: flex;
519
+ gap: 4px;
520
+ color: var(--mw-deck-ink);
521
+ pointer-events: none;
522
+
523
+ > span {
524
+ flex: 1;
525
+ height: 3px;
526
+ border-radius: 3px;
527
+ background: color-mix(in srgb, currentColor 24%, transparent);
528
+ transition: background-color var(--mw-duration-slow) var(--mw-ease-out);
529
+ }
530
+
531
+ > .mw-done {
532
+ background: var(--mw-deck-accent);
533
+ }
534
+ }
535
+
536
+ .mw-deck-head {
537
+ position: absolute;
538
+ top: calc(max(#{spacing('4')}, env(safe-area-inset-top)) + 0.85rem);
539
+ right: spacing('5');
540
+ left: 1.1rem;
541
+ }
542
+
543
+ .mw-deck-slides {
544
+ overflow: hidden auto;
545
+ scroll-snap-type: y mandatory;
546
+ overscroll-behavior: contain;
547
+ }
548
+
549
+ .mw-slide {
550
+ display: flex;
551
+ flex-direction: column;
552
+ gap: 1.1rem;
553
+ height: 100%;
554
+ padding: 5.2rem var(--mw-deck-gutter)
555
+ calc(#{spacing('8')} + env(safe-area-inset-bottom));
556
+ }
557
+
558
+ .mw-slide-statement,
559
+ .mw-slide-cover {
560
+ justify-content: flex-end;
561
+ }
562
+ }
563
+
564
+ .mw-deck-aside {
565
+ display: none;
566
+ }
567
+
568
+ @media (width >= #{breakpoint('sm')}) and (height >= 560px) {
569
+ .mw-deck-portrait {
570
+ display: grid;
571
+ place-content: center;
572
+ gap: clamp(2rem, 6vw, 6rem);
573
+
574
+ .mw-deck-stage {
575
+ position: relative;
576
+ inset: auto;
577
+ // 430 x 932, the tallest phone in common use, scaled down to the window
578
+ width: min(430px, calc((100vh - 4rem) * 0.4615));
579
+ width: min(430px, calc((100dvh - 4rem) * 0.4615));
580
+ height: min(932px, calc(100vh - 4rem));
581
+ height: min(932px, calc(100dvh - 4rem));
582
+ border-radius: 2.4rem;
583
+ outline: 1px solid var(--mw-border);
584
+ box-shadow: var(--mw-elevation-5);
585
+ }
586
+ }
587
+ }
588
+
589
+ @media (width >= #{breakpoint('lg')}) and (height >= 560px) {
590
+ .mw-deck-portrait {
591
+ grid-template-columns: minmax(0, 21rem) auto;
592
+ }
593
+
594
+ .mw-deck-aside {
595
+ display: flex;
596
+ flex-direction: column;
597
+ align-self: center;
598
+ gap: spacing('6');
599
+
600
+ .mw-deck-aside-title {
601
+ font-family: var(--mw-font-family-heading);
602
+ font-size: font-size('3xl');
603
+ font-weight: var(--mw-deck-title-weight);
604
+ line-height: 1.05;
605
+ letter-spacing: var(--mw-deck-title-tracking);
606
+ text-transform: var(--mw-deck-title-case);
607
+ }
608
+
609
+ p:not(.mw-deck-kicker, .mw-deck-aside-title) {
610
+ font-size: font-size('base');
611
+ color: var(--mw-text-muted-color);
612
+ }
613
+
614
+ .mw-deck-arrows {
615
+ margin-top: spacing('3');
616
+ }
617
+
618
+ a {
619
+ font-size: font-size('sm');
620
+ color: var(--mw-text-muted-color);
621
+
622
+ &:hover {
623
+ color: var(--mw-primary-text-color);
624
+ }
625
+ }
626
+ }
627
+ }
628
+
629
+ // A landscape deck on a phone held upright asks to be turned
630
+ .mw-deck-rotate {
631
+ display: none;
632
+ }
633
+
634
+ @media (orientation: portrait) and (width < #{breakpoint('md')}) {
635
+ .mw-deck-landscape .mw-deck-rotate {
636
+ position: absolute;
637
+ inset: 0;
638
+ z-index: 20;
639
+ display: grid;
640
+ place-content: center;
641
+ gap: spacing('6');
642
+ padding: spacing('8');
643
+ background-color: var(--mw-page-background);
644
+ text-align: center;
645
+
646
+ svg {
647
+ width: 4.5rem;
648
+ margin-inline: auto;
649
+ fill: none;
650
+ stroke: var(--mw-deck-second-ink);
651
+ stroke-width: 1.5;
652
+ animation: mw-deck-rotate motion(2.4s) var(--mw-ease-in-out) infinite;
653
+ }
654
+
655
+ p {
656
+ max-width: 22rem;
657
+ color: var(--mw-text-muted-color);
658
+ }
659
+
660
+ a {
661
+ color: var(--mw-deck-first-ink);
662
+ text-decoration: underline;
663
+ text-underline-offset: 0.22em;
664
+ }
665
+ }
666
+ }
667
+
668
+ @keyframes mw-deck-rotate {
669
+ 0%,
670
+ 30% {
671
+ transform: rotate(0);
672
+ }
673
+
674
+ 60%,
675
+ 100% {
676
+ transform: rotate(-90deg);
677
+ }
678
+ }
679
+
680
+ // Entrance: only once the script runs, so without it every slide stays whole
681
+
682
+ .mw-deck-ready [data-deck-in] {
683
+ opacity: 0;
684
+ transform: translateY(1.1rem);
685
+ transition:
686
+ opacity var(--mw-duration-zoom) var(--mw-ease-out),
687
+ transform var(--mw-duration-zoom) var(--mw-ease-out);
688
+ }
689
+
690
+ .mw-deck-ready .mw-slide.mw-active [data-deck-in] {
691
+ opacity: 1;
692
+ transform: none;
693
+ }
694
+
695
+ @for $step from 2 through 7 {
696
+ .mw-deck-ready .mw-slide.mw-active [data-deck-in='#{$step}'] {
697
+ transition-delay: motion(($step - 1) * 90ms);
698
+ }
699
+ }
700
+ }
@@ -14,6 +14,8 @@
14
14
  @forward 'contact';
15
15
  @forward 'content-slider';
16
16
  @forward 'date-stamp';
17
+ @forward 'deck';
18
+ @forward 'deck-frame';
17
19
  @forward 'divider';
18
20
  @forward 'dropdown';
19
21
  @forward 'empty-state';
@@ -34,6 +36,7 @@
34
36
  @forward 'meta-info';
35
37
  @forward 'modals';
36
38
  @forward 'mosaic';
39
+ @forward 'occasions';
37
40
  @forward 'overlay-btn';
38
41
  @forward 'pagination';
39
42
  @forward 'panels';