maverick-wave 5.12.0 → 5.14.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/.claude/skills/mw-maverick-wave/SKILL.md +63 -8
- package/.claude/skills/mw-maverick-wave/examples/static-landing-page.md +6 -3
- package/.claude/skills/mw-maverick-wave/references/components.md +41 -27
- package/.claude/skills/mw-maverick-wave/references/javascript.md +27 -26
- package/.claude/skills/mw-maverick-wave/references/layout.md +20 -8
- package/.claude/skills/mw-maverick-wave/references/theming.md +59 -4
- package/CHANGELOG.md +19 -0
- package/README.md +45 -5
- package/index.html +5 -4
- package/maverick-wave.min.css +4 -4
- package/maverick-wave.min.js +1 -1
- package/package.json +2 -2
- package/src/js/main.js +67 -20
- package/src/partials/buttons-container.html +2 -1
- package/src/partials/get-started-container.html +52 -3
- package/src/partials/parallax-container.html +8 -5
- package/src/partials/tabs-container.html +1 -1
- package/src/partials/typography-container.html +3 -0
- package/src/partials/utilities-container.html +29 -0
- package/src/scss/abstracts/_functions.scss +50 -0
- package/src/scss/abstracts/_mixins.scss +33 -0
- package/src/scss/base/_typography.scss +4 -21
- package/src/scss/components/_buttons.scss +1 -1
- package/src/scss/components/_content-slider.scss +16 -8
- package/src/scss/components/_dropdown.scss +1 -1
- package/src/scss/components/_gallery.scss +13 -2
- package/src/scss/components/_lang-switch.scss +1 -1
- package/src/scss/components/_segmented.scss +4 -0
- package/src/scss/layout/_header.scss +3 -2
- package/src/scss/layout/_main.scss +87 -8
- package/src/scss/layout/_parallax.scss +15 -1
- package/src/scss/layout/_section.scss +2 -10
- package/src/scss/utilities/_touch-targets.scss +22 -16
|
@@ -9,21 +9,29 @@
|
|
|
9
9
|
border-radius: radius('md');
|
|
10
10
|
overflow: hidden;
|
|
11
11
|
|
|
12
|
+
// The slider caps at 600px, so past a tablet the viewport no longer says how
|
|
13
|
+
// much room it has. Named, so a query cannot resolve to a container above.
|
|
14
|
+
container: mw-slider / inline-size;
|
|
15
|
+
|
|
12
16
|
// Heights variables for consistency
|
|
13
17
|
$height-lg: 370px;
|
|
14
18
|
$height-md: 320px;
|
|
15
19
|
$height-sm: 250px;
|
|
16
20
|
|
|
21
|
+
// The slider widths the old viewport steps landed on, not the breakpoints
|
|
22
|
+
$wide: 560px;
|
|
23
|
+
$mid: 420px;
|
|
24
|
+
|
|
17
25
|
&-base {
|
|
18
26
|
position: relative;
|
|
19
27
|
width: 100%;
|
|
20
28
|
height: $height-sm;
|
|
21
29
|
|
|
22
|
-
@
|
|
30
|
+
@container mw-slider (width >= #{$mid}) {
|
|
23
31
|
height: $height-md;
|
|
24
32
|
}
|
|
25
33
|
|
|
26
|
-
@
|
|
34
|
+
@container mw-slider (width >= #{$wide}) {
|
|
27
35
|
height: $height-lg;
|
|
28
36
|
}
|
|
29
37
|
}
|
|
@@ -43,11 +51,11 @@
|
|
|
43
51
|
height: $height-sm;
|
|
44
52
|
pointer-events: none;
|
|
45
53
|
|
|
46
|
-
@
|
|
54
|
+
@container mw-slider (width >= #{$mid}) {
|
|
47
55
|
height: $height-md;
|
|
48
56
|
}
|
|
49
57
|
|
|
50
|
-
@
|
|
58
|
+
@container mw-slider (width >= #{$wide}) {
|
|
51
59
|
height: $height-lg;
|
|
52
60
|
}
|
|
53
61
|
}
|
|
@@ -86,11 +94,11 @@
|
|
|
86
94
|
z-index: z-index('menu');
|
|
87
95
|
width: 100%;
|
|
88
96
|
|
|
89
|
-
@
|
|
97
|
+
@container mw-slider (width >= #{$mid}) {
|
|
90
98
|
grid-template-columns: repeat(3, 1fr);
|
|
91
99
|
}
|
|
92
100
|
|
|
93
|
-
@
|
|
101
|
+
@container mw-slider (width >= #{$wide}) {
|
|
94
102
|
gap: spacing('3');
|
|
95
103
|
padding: spacing('3');
|
|
96
104
|
}
|
|
@@ -106,11 +114,11 @@
|
|
|
106
114
|
z-index: z-index('menu');
|
|
107
115
|
width: 100%;
|
|
108
116
|
|
|
109
|
-
@
|
|
117
|
+
@container mw-slider (width >= #{$mid}) {
|
|
110
118
|
grid-template-columns: repeat(2, 1fr);
|
|
111
119
|
}
|
|
112
120
|
|
|
113
|
-
@
|
|
121
|
+
@container mw-slider (width >= #{$wide}) {
|
|
114
122
|
gap: spacing('3');
|
|
115
123
|
padding: spacing('3');
|
|
116
124
|
}
|
|
@@ -257,7 +257,7 @@
|
|
|
257
257
|
// A menu opened by a thumb needs rows a thumb can hit, and the room to show
|
|
258
258
|
// them - so it takes the trigger's full width rather than a 200px column
|
|
259
259
|
// floating beside it.
|
|
260
|
-
@
|
|
260
|
+
@include touch-context('sm') {
|
|
261
261
|
.mw-dropdown-menu {
|
|
262
262
|
min-width: max(100%, 240px);
|
|
263
263
|
}
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
@use '../abstracts' as *;
|
|
2
2
|
|
|
3
3
|
@layer mw.components {
|
|
4
|
+
// Thresholds are the wrapper widths the old viewport steps landed on once the
|
|
5
|
+
// container gutter is taken off, not the breakpoints themselves.
|
|
6
|
+
$wide: 688px;
|
|
7
|
+
$narrow: 512px;
|
|
8
|
+
|
|
4
9
|
.mw-gallery-container {
|
|
5
10
|
max-width: 1100px;
|
|
11
|
+
// Inline-size containment computes the width as if the element were empty,
|
|
12
|
+
// so one dropped into a flex or grid slot would shrink to nothing without it
|
|
13
|
+
width: 100%;
|
|
6
14
|
margin: spacing('1') auto;
|
|
15
|
+
// The wrapper and not .mw-gallery: the description and the dots are its
|
|
16
|
+
// siblings, and a container query only reaches descendants
|
|
17
|
+
container: mw-gallery / inline-size;
|
|
7
18
|
}
|
|
8
19
|
|
|
9
20
|
.mw-gallery {
|
|
@@ -119,7 +130,7 @@
|
|
|
119
130
|
}
|
|
120
131
|
}
|
|
121
132
|
|
|
122
|
-
@
|
|
133
|
+
@container mw-gallery (width < #{$wide}) {
|
|
123
134
|
.mw-gallery {
|
|
124
135
|
&-desc {
|
|
125
136
|
font-size: font-size('sm');
|
|
@@ -134,7 +145,7 @@
|
|
|
134
145
|
}
|
|
135
146
|
}
|
|
136
147
|
|
|
137
|
-
@
|
|
148
|
+
@container mw-gallery (width < #{$narrow}) {
|
|
138
149
|
.mw-gallery {
|
|
139
150
|
&-slide {
|
|
140
151
|
aspect-ratio: 4 / 3;
|
|
@@ -92,6 +92,10 @@
|
|
|
92
92
|
// the width of the shortest, so the items follow their own content instead.
|
|
93
93
|
.mw-segmented-auto {
|
|
94
94
|
width: auto;
|
|
95
|
+
// Shrink-to-fit sizes this off the labels, which on a 320px screen is wider
|
|
96
|
+
// than the screen. The items already carry `min-width: 0` and truncate, so
|
|
97
|
+
// the cap only ever bites where the row genuinely has no room.
|
|
98
|
+
max-width: 100%;
|
|
95
99
|
|
|
96
100
|
.mw-segmented-item {
|
|
97
101
|
flex: 0 1 auto;
|
|
@@ -231,9 +231,10 @@
|
|
|
231
231
|
// Keeps a rubber-band scroll inside the panel from moving the page
|
|
232
232
|
overscroll-behavior: contain;
|
|
233
233
|
padding: calc(
|
|
234
|
-
var(--mw-header-height) + #{spacing('6')} +
|
|
234
|
+
var(--mw-header-height) + #{spacing('6')} +
|
|
235
|
+
env(safe-area-inset-top, 0px)
|
|
235
236
|
)
|
|
236
|
-
spacing('4') calc(#{spacing('6')} + env(safe-area-inset-bottom));
|
|
237
|
+
spacing('4') calc(#{spacing('6')} + env(safe-area-inset-bottom, 0px));
|
|
237
238
|
}
|
|
238
239
|
|
|
239
240
|
.mw-navbar-item {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
@use 'sass:math';
|
|
1
2
|
@use '../abstracts' as *;
|
|
2
3
|
|
|
3
4
|
@layer mw.layout {
|
|
@@ -268,10 +269,40 @@
|
|
|
268
269
|
// scroll on a phone. Hence `allow-discrete` and the starting style.
|
|
269
270
|
$_mw-tooltip-arrow: 6px;
|
|
270
271
|
$_mw-tooltip-gap: 8px;
|
|
272
|
+
// A square turned 45deg rather than a border triangle: it reads the same from
|
|
273
|
+
// above and from below, so the second placement costs no second arrow and a
|
|
274
|
+
// flip never has to repaint anything. The diagonal carries the visible width,
|
|
275
|
+
// so the side is the visible height doubled over root two.
|
|
276
|
+
$_mw-tooltip-arrow-side: math.div($_mw-tooltip-arrow * 2, math.sqrt(2));
|
|
277
|
+
// Half a side short of where the triangle's edge sat, so the turned square is
|
|
278
|
+
// centred on the bubble's edge and only its outer half shows. The inner half
|
|
279
|
+
// lands on the bubble in the same colour, which is what makes it read as one
|
|
280
|
+
// shape rather than a diamond stuck to a box.
|
|
281
|
+
$_mw-tooltip-arrow-inset: $_mw-tooltip-gap +
|
|
282
|
+
$_mw-tooltip-arrow - math.div($_mw-tooltip-arrow-side, 2);
|
|
271
283
|
|
|
272
284
|
[data-tooltip] {
|
|
273
285
|
position: relative;
|
|
274
286
|
|
|
287
|
+
// The placement API: the text is the attribute, the side is a class. Both
|
|
288
|
+
// axes are custom properties rather than rules, so `below` and `end` compose
|
|
289
|
+
// without a rule per pairing - and the arrow reads only the block axis,
|
|
290
|
+
// because it points at the trigger whichever way the bubble is aligned.
|
|
291
|
+
--_mw-tooltip-block: block-start;
|
|
292
|
+
--_mw-tooltip-inline: center;
|
|
293
|
+
|
|
294
|
+
&.mw-tooltip-below {
|
|
295
|
+
--_mw-tooltip-block: block-end;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
&.mw-tooltip-end {
|
|
299
|
+
--_mw-tooltip-inline: span-inline-start;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
&.mw-tooltip-start {
|
|
303
|
+
--_mw-tooltip-inline: span-inline-end;
|
|
304
|
+
}
|
|
305
|
+
|
|
275
306
|
&::before {
|
|
276
307
|
content: attr(data-tooltip);
|
|
277
308
|
position: absolute;
|
|
@@ -301,11 +332,11 @@
|
|
|
301
332
|
position: absolute;
|
|
302
333
|
bottom: 100%;
|
|
303
334
|
left: 50%;
|
|
304
|
-
transform: translateX(-50%);
|
|
305
|
-
margin-bottom: $_mw-tooltip-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
335
|
+
transform: translateX(-50%) rotate(45deg);
|
|
336
|
+
margin-bottom: $_mw-tooltip-arrow-inset;
|
|
337
|
+
width: $_mw-tooltip-arrow-side;
|
|
338
|
+
height: $_mw-tooltip-arrow-side;
|
|
339
|
+
background: var(--mw-gray-color);
|
|
309
340
|
opacity: 0;
|
|
310
341
|
display: none;
|
|
311
342
|
transition:
|
|
@@ -314,6 +345,42 @@
|
|
|
314
345
|
z-index: z-index('tooltip');
|
|
315
346
|
}
|
|
316
347
|
|
|
348
|
+
// What the modifiers mean without anchor positioning. Kept in its own
|
|
349
|
+
// `@supports not` rather than reset inside the anchored path: a modifier
|
|
350
|
+
// carries a class more weight than such a reset, so the two would fight
|
|
351
|
+
// instead of replace - which is exactly how the absolute placement used to
|
|
352
|
+
// survive into the anchored path and land the bubble on its own trigger.
|
|
353
|
+
@supports not (position-area: block-start) {
|
|
354
|
+
&.mw-tooltip-below {
|
|
355
|
+
&::before {
|
|
356
|
+
top: 100%;
|
|
357
|
+
bottom: auto;
|
|
358
|
+
margin-top: $_mw-tooltip-gap + $_mw-tooltip-arrow;
|
|
359
|
+
margin-bottom: 0;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
&::after {
|
|
363
|
+
top: 100%;
|
|
364
|
+
bottom: auto;
|
|
365
|
+
margin-top: $_mw-tooltip-arrow-inset;
|
|
366
|
+
margin-bottom: 0;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Only the bubble moves - the arrow stays on the trigger it points at.
|
|
371
|
+
&.mw-tooltip-end::before {
|
|
372
|
+
left: auto;
|
|
373
|
+
right: 0;
|
|
374
|
+
transform: none;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
&.mw-tooltip-start::before {
|
|
378
|
+
left: 0;
|
|
379
|
+
right: auto;
|
|
380
|
+
transform: none;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
317
384
|
&:hover::before,
|
|
318
385
|
&:hover::after,
|
|
319
386
|
&:focus-visible::before,
|
|
@@ -345,19 +412,31 @@
|
|
|
345
412
|
// it attached. No `anchor-name` needed - a pseudo element is implicitly
|
|
346
413
|
// anchored to the element it comes from.
|
|
347
414
|
//
|
|
348
|
-
//
|
|
349
|
-
//
|
|
415
|
+
// Still no `position-try-fallbacks: flip-block`, and no longer because of the
|
|
416
|
+
// arrow - the turned square survives a flip. Bubble and arrow are two
|
|
417
|
+
// separately anchored boxes, so each would decide on its own whether it fits,
|
|
418
|
+
// and the tiny one nearly always does: the label flips, the arrow stays.
|
|
350
419
|
@supports (position-area: block-start) {
|
|
351
420
|
&::before,
|
|
352
421
|
&::after {
|
|
353
422
|
position: fixed;
|
|
354
|
-
position-area: block-start;
|
|
355
423
|
// The absolute placement these replace - left as-is they fight the
|
|
356
424
|
// position-area, which resolves the inset properties itself.
|
|
357
425
|
bottom: auto;
|
|
358
426
|
left: auto;
|
|
427
|
+
top: auto;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
&::before {
|
|
431
|
+
position-area: var(--_mw-tooltip-block) var(--_mw-tooltip-inline);
|
|
359
432
|
transform: none;
|
|
360
433
|
}
|
|
434
|
+
|
|
435
|
+
// The turn stays - it is the arrow's shape, not its placement.
|
|
436
|
+
&::after {
|
|
437
|
+
position-area: var(--_mw-tooltip-block) center;
|
|
438
|
+
transform: rotate(45deg);
|
|
439
|
+
}
|
|
361
440
|
}
|
|
362
441
|
}
|
|
363
442
|
}
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
position: relative;
|
|
25
25
|
display: flex;
|
|
26
26
|
align-items: center;
|
|
27
|
-
min-height:
|
|
27
|
+
min-height: 60vh;
|
|
28
28
|
// `clip` and never `hidden`: hidden makes this a scroll container, and the
|
|
29
29
|
// view() timeline below would then resolve against this box instead of the
|
|
30
30
|
// viewport - the layer keeps its overhang and never moves
|
|
@@ -148,6 +148,20 @@
|
|
|
148
148
|
background: var(--mw-page-background);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
// `+` and not `~` like the two rules above: only the section that does the
|
|
152
|
+
// overtaking carries the edge, on every one after it the shadow would read as
|
|
153
|
+
// a seam across the page. Fixed values and not elevation(): this shadow lands
|
|
154
|
+
// on the picture rather than on a theme surface, and the light theme's 21%
|
|
155
|
+
// near layer disappears there - same reason mw-parallax-dimmed below
|
|
156
|
+
// hardcodes its brightness and its text-shadow.
|
|
157
|
+
:where(
|
|
158
|
+
:is(.mw-parallax-sticky, .mw-parallax-slow) + *:not(.mw-parallax-sticky)
|
|
159
|
+
) {
|
|
160
|
+
box-shadow:
|
|
161
|
+
0 -6px 12px rgb(0 0 0 / 45%),
|
|
162
|
+
0 -20px 44px rgb(0 0 0 / 26%);
|
|
163
|
+
}
|
|
164
|
+
|
|
151
165
|
// Ink on a photograph, the same pair the hero uses: the picture goes down, the
|
|
152
166
|
// text goes light. A band without content on it needs neither.
|
|
153
167
|
.mw-parallax-dimmed {
|
|
@@ -24,16 +24,12 @@
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
.mw-section-title {
|
|
27
|
-
font-size:
|
|
27
|
+
font-size: fluid('2xl', '3xl', $to: 'sm');
|
|
28
28
|
margin-bottom: var(--mw-section-title-gap);
|
|
29
29
|
text-align: center;
|
|
30
30
|
position: relative;
|
|
31
31
|
|
|
32
32
|
@include _section-rule(56px, 3px, spacing('-3'));
|
|
33
|
-
|
|
34
|
-
@include media-up('sm') {
|
|
35
|
-
font-size: font-size('3xl');
|
|
36
|
-
}
|
|
37
33
|
}
|
|
38
34
|
|
|
39
35
|
// The lead line under a section title. Every landing page writes this
|
|
@@ -51,7 +47,7 @@
|
|
|
51
47
|
}
|
|
52
48
|
|
|
53
49
|
.mw-section-subtitle {
|
|
54
|
-
font-size:
|
|
50
|
+
font-size: fluid('xl', '2xl', $to: 'sm');
|
|
55
51
|
// The step above a demo gap of spacing('6') - at spacing('8') the boundary
|
|
56
52
|
// between two components read like the one between two demos
|
|
57
53
|
margin: spacing('10') spacing('0') spacing('6') spacing('0');
|
|
@@ -64,10 +60,6 @@
|
|
|
64
60
|
spacing('-2'),
|
|
65
61
|
var(--mw-secondary-text-color)
|
|
66
62
|
);
|
|
67
|
-
|
|
68
|
-
@include media-up('sm') {
|
|
69
|
-
font-size: font-size('2xl');
|
|
70
|
-
}
|
|
71
63
|
}
|
|
72
64
|
|
|
73
65
|
// Sticky, because the strip is the only way back: inside a long section the
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
@layer mw.utilities {
|
|
4
4
|
// WCAG 2.5.8 puts the floor at 24x24px, and a floor is not a goal - the compact
|
|
5
|
-
// sizes are right under a pointer and too small under a thumb.
|
|
6
|
-
// narrow, because a tablet in landscape is wide and still finger-operated.
|
|
5
|
+
// sizes are right under a pointer and too small under a thumb.
|
|
7
6
|
// Loaded last, so these win without extra specificity.
|
|
8
|
-
@
|
|
7
|
+
@include touch-context {
|
|
9
8
|
// Padding and line-height add up to ~35px, under the 44px a thumb needs. Only
|
|
10
9
|
// the height grows: the padding sets the label's relationship to the edges.
|
|
11
10
|
.mw-btn {
|
|
@@ -85,13 +84,7 @@
|
|
|
85
84
|
}
|
|
86
85
|
|
|
87
86
|
.mw-gallery-dot {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
&::after {
|
|
91
|
-
content: '';
|
|
92
|
-
position: absolute;
|
|
93
|
-
inset: -7.5px;
|
|
94
|
-
}
|
|
87
|
+
@include hit-area(7.5px);
|
|
95
88
|
}
|
|
96
89
|
|
|
97
90
|
// A range input is as tall as its track, so the whole hit area is 8px and you
|
|
@@ -109,14 +102,27 @@
|
|
|
109
102
|
// area grows, to 28px - clear of the 24px floor. The extra margin keeps two
|
|
110
103
|
// neighbouring hit areas from overlapping.
|
|
111
104
|
.mw-btn-mini {
|
|
112
|
-
position: relative;
|
|
113
105
|
margin-left: spacing('4');
|
|
106
|
+
@include hit-area(5px);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Edit and delete on a ticket. The 32px box stays - a 44px one would push
|
|
110
|
+
// the assignee off the card footer - and the row carries the gap the two
|
|
111
|
+
// grown hit areas need, or they overlap and a tap meant for edit deletes.
|
|
112
|
+
.mw-kanban-card-actions {
|
|
113
|
+
gap: spacing('4');
|
|
114
|
+
}
|
|
114
115
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
.mw-kanban-action {
|
|
117
|
+
@include hit-area(6px);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// The box itself and not a hit area over it: half of these carry a
|
|
121
|
+
// `data-tooltip`, which owns both pseudo-elements, so the trick above lands
|
|
122
|
+
// on some of the logos and silently skips the rest.
|
|
123
|
+
.mw-techstack-item-sm {
|
|
124
|
+
min-width: 2.5rem;
|
|
125
|
+
min-height: 2.5rem;
|
|
120
126
|
}
|
|
121
127
|
}
|
|
122
128
|
|