maverick-wave 4.28.0 → 5.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/.claude/settings.local.json +29 -1
- package/.claude/skills/mw-maverick-wave/SKILL.md +39 -24
- package/.claude/skills/mw-maverick-wave/examples/angular-services.md +16 -4
- package/.claude/skills/mw-maverick-wave/examples/static-landing-page.md +13 -4
- package/.claude/skills/mw-maverick-wave/references/components.md +42 -5
- package/.claude/skills/mw-maverick-wave/references/forms.md +14 -2
- package/.claude/skills/mw-maverick-wave/references/javascript.md +17 -4
- package/.claude/skills/mw-maverick-wave/references/layout.md +53 -19
- package/.claude/skills/mw-maverick-wave/references/theming.md +38 -1
- package/.impeccable/config.local.json +5 -0
- package/.impeccable/hook.cache.json +1 -0
- package/CHANGELOG.md +11 -0
- package/CLAUDE.md +5 -5
- package/README.md +48 -4
- package/index.html +19 -38
- package/maverick-wave.min.css +14 -12
- package/maverick-wave.min.js +1 -1
- package/package.json +2 -2
- package/scripts/verify.js +27 -2
- package/src/js/main.js +223 -83
- package/src/partials/accordions-container.html +6 -10
- package/src/partials/alerts-container.html +6 -6
- package/src/partials/announcement-container.html +5 -5
- package/src/partials/avatars-container.html +85 -17
- package/src/partials/badges-container.html +6 -6
- package/src/partials/blog-posts-container.html +11 -12
- package/src/partials/buttons-container.html +3 -3
- package/src/partials/cards-container.html +26 -9
- package/src/partials/code-container.html +5 -5
- package/src/partials/content-slider-container.html +5 -4
- package/src/partials/divider-container.html +7 -7
- package/src/partials/dropdown-container.html +2 -2
- package/src/partials/empty-state-container.html +5 -5
- package/src/partials/footer-container.html +21 -18
- package/src/partials/form-elements-container.html +14 -14
- package/src/partials/gallery-container.html +16 -8
- package/src/partials/get-started-container.html +4 -8
- package/src/partials/header-container.html +18 -7
- package/src/partials/home-container.html +10 -20
- package/src/partials/input-group-container.html +11 -2
- package/src/partials/kbd-container.html +1 -1
- package/src/partials/login-container.html +5 -1
- package/src/partials/media-container.html +2 -2
- package/src/partials/modals-container.html +22 -32
- package/src/partials/pricing-container.html +9 -9
- package/src/partials/skeleton-container.html +6 -6
- package/src/partials/stepper-container.html +2 -2
- package/src/partials/tables-container.html +12 -12
- package/src/partials/tabs-container.html +17 -27
- package/src/partials/tags-container.html +23 -17
- package/src/partials/techstack-bucket-container.html +13 -0
- package/src/partials/tiles-container.html +26 -9
- package/src/partials/typography-container.html +7 -6
- package/src/partials/utilities-container.html +35 -15
- package/src/scss/_layers.scss +10 -0
- package/src/scss/abstracts/_index.scss +6 -0
- package/src/scss/abstracts/_mixins.scss +61 -153
- package/src/scss/abstracts/_variables.scss +123 -319
- package/src/scss/base/_base.scss +170 -190
- package/src/scss/base/_reset.scss +106 -104
- package/src/scss/base/_typography.scss +153 -151
- package/src/scss/components/_accordions.scss +97 -97
- package/src/scss/components/_alerts.scss +71 -70
- package/src/scss/components/_announcement.scss +71 -70
- package/src/scss/components/_avatars.scss +130 -142
- package/src/scss/components/_badge.scss +131 -132
- package/src/scss/components/_blog-post.scss +223 -220
- package/src/scss/components/_breadcrumbs.scss +93 -92
- package/src/scss/components/_button-bar.scss +102 -110
- package/src/scss/components/_buttons.scss +319 -324
- package/src/scss/components/_calendar.scss +251 -252
- package/src/scss/components/_cards.scss +359 -386
- package/src/scss/components/_code.scss +190 -194
- package/src/scss/components/_coming-soon.scss +77 -75
- package/src/scss/components/_content-slider.scss +90 -89
- package/src/scss/components/_divider.scss +55 -53
- package/src/scss/components/_dropdown.scss +179 -185
- package/src/scss/components/_empty-state.scss +57 -57
- package/src/scss/components/_flag.scss +294 -278
- package/src/scss/components/_gallery.scss +131 -133
- package/src/scss/components/_info.scss +151 -167
- package/src/scss/components/_kanban.scss +332 -341
- package/src/scss/components/_kbd.scss +40 -38
- package/src/scss/components/_lang-switch.scss +89 -97
- package/src/scss/components/_links.scss +21 -28
- package/src/scss/components/_lists.scss +510 -514
- package/src/scss/components/_localhost-indicator.scss +26 -24
- package/src/scss/components/_media.scss +22 -20
- package/src/scss/components/_meta-info.scss +35 -33
- package/src/scss/components/_modals.scss +277 -186
- package/src/scss/components/_pagination.scss +81 -87
- package/src/scss/components/_panels.scss +99 -97
- package/src/scss/components/_pricing.scss +183 -241
- package/src/scss/components/_progress.scss +112 -89
- package/src/scss/components/_prose.scss +35 -33
- package/src/scss/components/_ratings.scss +40 -38
- package/src/scss/components/_segmented.scss +82 -84
- package/src/scss/components/_skeleton.scss +66 -72
- package/src/scss/components/_spinners.scss +155 -159
- package/src/scss/components/_stepper.scss +116 -116
- package/src/scss/components/_tables.scss +155 -148
- package/src/scss/components/_tabs.scss +232 -141
- package/src/scss/components/_tags.scss +109 -107
- package/src/scss/components/_techstack-bucket.scss +123 -122
- package/src/scss/components/_testimonial.scss +72 -70
- package/src/scss/components/_theme-toggle.scss +53 -51
- package/src/scss/components/_tiles.scss +174 -174
- package/src/scss/components/_timelines.scss +282 -280
- package/src/scss/components/_toasts.scss +66 -72
- package/src/scss/form-elements/_checkbox.scss +117 -132
- package/src/scss/form-elements/_form.scss +149 -115
- package/src/scss/form-elements/_input-group.scss +99 -103
- package/src/scss/form-elements/_input.scss +74 -74
- package/src/scss/form-elements/_login.scss +48 -48
- package/src/scss/form-elements/_prefilled.scss +53 -51
- package/src/scss/form-elements/_radio.scss +95 -107
- package/src/scss/form-elements/_select.scss +42 -42
- package/src/scss/form-elements/_slider.scss +117 -132
- package/src/scss/form-elements/_textarea.scss +68 -54
- package/src/scss/form-elements/_toggle.scss +127 -140
- package/src/scss/layout/_footer.scss +172 -171
- package/src/scss/layout/_grid.scss +268 -302
- package/src/scss/layout/_header.scss +426 -427
- package/src/scss/layout/_home.scss +28 -27
- package/src/scss/layout/_main.scss +275 -238
- package/src/scss/layout/_page-header.scss +38 -36
- package/src/scss/layout/_section.scss +150 -124
- package/src/scss/main.scss +1 -1
- package/src/scss/utilities/_accessibility.scss +46 -45
- package/src/scss/utilities/_aspect.scss +22 -20
- package/src/scss/utilities/_corner.scss +23 -5
- package/src/scss/utilities/_display.scss +76 -70
- package/src/scss/utilities/_elevation.scss +13 -11
- package/src/scss/utilities/_flex.scss +83 -85
- package/src/scss/utilities/_reveal.scss +40 -63
- package/src/scss/utilities/_spacing.scss +63 -64
- package/src/scss/utilities/_text.scss +139 -141
- package/src/scss/utilities/_touch-targets.scss +130 -147
|
@@ -1,40 +1,41 @@
|
|
|
1
1
|
@use '../abstracts' as *;
|
|
2
2
|
|
|
3
|
-
.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
@layer mw.layout {
|
|
4
|
+
.mw-home {
|
|
5
|
+
justify-items: center;
|
|
6
|
+
align-items: center;
|
|
7
|
+
text-align: center;
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
padding: spacing('6');
|
|
10
|
-
@include media-down('sm') {
|
|
9
|
+
&-content {
|
|
11
10
|
padding: spacing('9') spacing('4');
|
|
12
|
-
|
|
11
|
+
@include media-up('sm') {
|
|
12
|
+
padding: spacing('6');
|
|
13
|
+
}
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
&-fade {
|
|
16
|
+
@extend .mw-home-content;
|
|
17
|
+
animation: fadeIn var(--mw-duration-slower) var(--mw-ease-out);
|
|
18
|
+
}
|
|
18
19
|
}
|
|
19
|
-
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
width: min(75%, 700px);
|
|
23
|
-
position: relative;
|
|
24
|
-
margin: spacing('0') auto spacing('4');
|
|
25
|
-
@include media-down('sm') {
|
|
21
|
+
&-text {
|
|
26
22
|
width: 85%;
|
|
23
|
+
position: relative;
|
|
24
|
+
margin: spacing('0') auto spacing('4');
|
|
25
|
+
@include media-up('sm') {
|
|
26
|
+
width: min(75%, 700px);
|
|
27
|
+
}
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
|
-
}
|
|
30
30
|
|
|
31
|
-
@keyframes fadeIn {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
@keyframes fadeIn {
|
|
32
|
+
from {
|
|
33
|
+
opacity: 0;
|
|
34
|
+
transform: translateX(-8px) translateY(-23px);
|
|
35
|
+
}
|
|
36
|
+
to {
|
|
37
|
+
opacity: 1;
|
|
38
|
+
transform: translateY(0);
|
|
39
|
+
}
|
|
39
40
|
}
|
|
40
41
|
}
|
|
@@ -1,282 +1,319 @@
|
|
|
1
1
|
@use '../abstracts' as *;
|
|
2
2
|
|
|
3
|
-
.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
.mw-container {
|
|
12
|
-
width: var(--mw-container-width);
|
|
13
|
-
margin: spacing('0') auto;
|
|
14
|
-
padding: spacing('0');
|
|
15
|
-
|
|
16
|
-
// add a hero part for a full size background picture
|
|
17
|
-
@supports (selector(:has(.mw-hero))) {
|
|
18
|
-
// if it has *any* descendant .mw-hero
|
|
19
|
-
&:has(.mw-hero) {
|
|
20
|
-
position: relative;
|
|
21
|
-
width: 100%;
|
|
22
|
-
min-height: 100dvh;
|
|
23
|
-
display: flex;
|
|
24
|
-
align-items: center;
|
|
25
|
-
justify-content: center;
|
|
26
|
-
background-size: cover;
|
|
27
|
-
background-position: center;
|
|
28
|
-
background-image: var(--mw-hero-background);
|
|
29
|
-
|
|
30
|
-
// The image does not change with the theme, so neither does the ink on
|
|
31
|
-
// it - see $mw-hero-text-color. Set on the container so a hero without
|
|
32
|
-
// .mw-home still gets it.
|
|
33
|
-
color: var(--mw-hero-text-color);
|
|
3
|
+
@layer mw.layout {
|
|
4
|
+
.mw-main {
|
|
5
|
+
margin: spacing('0');
|
|
6
|
+
padding: spacing('0');
|
|
7
|
+
min-height: 100dvh;
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
}
|
|
34
11
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// the colour you see. Filtering here rather than on the container keeps
|
|
40
|
-
// the content in front of it unfiltered.
|
|
41
|
-
&::before {
|
|
42
|
-
content: '';
|
|
43
|
-
position: absolute;
|
|
44
|
-
inset: 0;
|
|
45
|
-
backdrop-filter: var(--mw-hero-image-filter);
|
|
46
|
-
z-index: z-index('lift');
|
|
47
|
-
pointer-events: none;
|
|
48
|
-
transition: var(--mw-transition);
|
|
49
|
-
}
|
|
12
|
+
.mw-container {
|
|
13
|
+
width: var(--mw-container-width);
|
|
14
|
+
margin: spacing('0') auto;
|
|
15
|
+
padding: spacing('0');
|
|
50
16
|
|
|
51
|
-
|
|
52
|
-
|
|
17
|
+
@supports (selector(:has(.mw-hero))) {
|
|
18
|
+
&:has(.mw-hero) {
|
|
53
19
|
position: relative;
|
|
54
|
-
|
|
55
|
-
|
|
20
|
+
width: 100%;
|
|
21
|
+
min-height: 100dvh;
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
justify-content: center;
|
|
25
|
+
background-size: cover;
|
|
26
|
+
background-position: center;
|
|
27
|
+
background-image: var(--mw-hero-background);
|
|
56
28
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// or its text would be light on a light card in the light theme.
|
|
60
|
-
.mw-card,
|
|
61
|
-
.mw-panel,
|
|
62
|
-
.mw-modal,
|
|
63
|
-
.mw-tile,
|
|
64
|
-
.mw-calendar:not(.mw-calendar-plain) {
|
|
65
|
-
color: var(--mw-text-color);
|
|
66
|
-
}
|
|
29
|
+
// Set on the container so a hero without .mw-home gets it too
|
|
30
|
+
color: var(--mw-hero-text-color);
|
|
67
31
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
32
|
+
// backdrop-filter and not an overlay - see $hero-filter-dark. On the pseudo
|
|
33
|
+
// element, so the content in front of the image stays unfiltered.
|
|
34
|
+
&::before {
|
|
35
|
+
content: '';
|
|
36
|
+
position: absolute;
|
|
37
|
+
inset: 0;
|
|
38
|
+
backdrop-filter: var(--mw-hero-image-filter);
|
|
39
|
+
z-index: z-index('lift');
|
|
40
|
+
pointer-events: none;
|
|
41
|
+
transition: var(--mw-transition);
|
|
42
|
+
}
|
|
76
43
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
// pay for a feature it does not use.
|
|
83
|
-
&:has(> .mw-scroll-hint) {
|
|
84
|
-
padding-bottom: calc(
|
|
85
|
-
var(--mw-scroll-hint-offset) + var(--mw-scroll-hint-reserve)
|
|
86
|
-
);
|
|
87
|
-
}
|
|
44
|
+
// ...so the content has to sit above it
|
|
45
|
+
> * {
|
|
46
|
+
position: relative;
|
|
47
|
+
z-index: z-index('card');
|
|
48
|
+
}
|
|
88
49
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
50
|
+
// The same shadow the scroll cue already carries: the light theme lifts
|
|
51
|
+
// the photo to brightness(1.1) and pale ink alone stops holding its edge
|
|
52
|
+
h1,
|
|
53
|
+
h2,
|
|
54
|
+
h3,
|
|
55
|
+
p {
|
|
56
|
+
text-shadow: 0 1px 4px rgb(0 0 0 / 65%);
|
|
57
|
+
}
|
|
95
58
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
59
|
+
// ...except anything that paints its own surface: a card in the hero is
|
|
60
|
+
// still a card, or its text is light on a light card in the light theme
|
|
61
|
+
.mw-card,
|
|
62
|
+
.mw-panel,
|
|
63
|
+
.mw-modal,
|
|
64
|
+
.mw-tile,
|
|
65
|
+
.mw-calendar:not(.mw-calendar-plain) {
|
|
66
|
+
color: var(--mw-text-color);
|
|
67
|
+
|
|
68
|
+
h1,
|
|
69
|
+
h2,
|
|
70
|
+
h3,
|
|
71
|
+
p {
|
|
72
|
+
text-shadow: none;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ...and except the outline button, for the opposite reason: its tone is
|
|
77
|
+
// picked to read on the page background and goes quiet over a photograph.
|
|
78
|
+
// The hover is restated because this selector is exactly as specific as
|
|
79
|
+
// `.mw-btn-outline:hover:not(:disabled)` and the layer order beats it.
|
|
80
|
+
.mw-btn-outline {
|
|
81
|
+
border-color: color-mix(
|
|
82
|
+
in srgb,
|
|
83
|
+
var(--mw-hero-text-color) 45%,
|
|
84
|
+
transparent
|
|
85
|
+
);
|
|
86
|
+
background: rgb(0 0 0 / 30%);
|
|
87
|
+
backdrop-filter: blur(6px);
|
|
88
|
+
color: var(--mw-hero-text-color);
|
|
108
89
|
|
|
90
|
+
&:hover:not(:disabled) {
|
|
91
|
+
background: var(--mw-primary-color);
|
|
92
|
+
border-color: var(--mw-primary-color);
|
|
93
|
+
color: var(--mw-primary-accent-text-color);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// The bar floats over the hero, so centring against the full viewport hides
|
|
98
|
+
// a badge or a kicker underneath it. Guarded - no header, no offset.
|
|
99
|
+
body:has(.mw-header) & {
|
|
100
|
+
padding-top: calc(var(--mw-header-height) + #{spacing('7')});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// The cue is out of flow, so buttons under the hero text would park on top
|
|
104
|
+
// of it. Only when there is one, or every hero pays for a feature it lacks.
|
|
105
|
+
&:has(> .mw-scroll-hint) {
|
|
109
106
|
padding-bottom: calc(
|
|
110
107
|
var(--mw-scroll-hint-offset) + var(--mw-scroll-hint-reserve)
|
|
111
108
|
);
|
|
112
109
|
}
|
|
110
|
+
|
|
111
|
+
// ...except in the corner: the end variant stands beside the content
|
|
112
|
+
&:has(> .mw-scroll-hint-end) {
|
|
113
|
+
padding-bottom: spacing('0');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// On a phone the corner is tight too, so both variants get the strip back.
|
|
117
|
+
// Last of the three: a media query adds no specificity and would lose to
|
|
118
|
+
// the end rule above. Smaller than on the desktop, or the full reserve
|
|
119
|
+
// tips the container past 100dvh and pushes the cue off screen.
|
|
120
|
+
@include media-down('md') {
|
|
121
|
+
&:has(> .mw-scroll-hint) {
|
|
122
|
+
--mw-scroll-hint-reserve: #{spacing('6')};
|
|
123
|
+
|
|
124
|
+
padding-bottom: calc(
|
|
125
|
+
var(--mw-scroll-hint-offset) + var(--mw-scroll-hint-reserve)
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
113
129
|
}
|
|
114
130
|
}
|
|
115
131
|
}
|
|
116
|
-
}
|
|
117
132
|
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
letter-spacing: 0.08em;
|
|
137
|
-
text-transform: uppercase;
|
|
138
|
-
text-decoration: none;
|
|
139
|
-
animation: mw-scroll-hint-float 2.2s var(--mw-ease-in-out) infinite;
|
|
140
|
-
text-shadow: 0 1px 4px rgb(0 0 0 / 65%);
|
|
141
|
-
|
|
142
|
-
// The arrow carries the meaning, the word only confirms it - so it is the
|
|
143
|
-
// arrow that gets the size, and the label stays quiet at 'xs'.
|
|
144
|
-
> i,
|
|
145
|
-
> svg {
|
|
146
|
-
font-size: font-size('lg');
|
|
133
|
+
// Glass rather than a fill: on a hero image a solid badge is the loudest thing
|
|
134
|
+
// on the screen and plain text sinks into the picture.
|
|
135
|
+
.mw-hero-badge {
|
|
136
|
+
display: inline-flex;
|
|
137
|
+
align-items: center;
|
|
138
|
+
justify-content: center;
|
|
139
|
+
gap: spacing('3');
|
|
140
|
+
max-width: 100%;
|
|
141
|
+
margin-bottom: spacing('6');
|
|
142
|
+
padding: spacing('2') spacing('5');
|
|
143
|
+
border: 1px solid #{fade('hero-text-color', 22%)};
|
|
144
|
+
border-radius: 999px;
|
|
145
|
+
background: fade('hero-text-color', 8%);
|
|
146
|
+
backdrop-filter: blur(4px);
|
|
147
|
+
color: fade('hero-text-color', 88%);
|
|
148
|
+
font-size: font-size('sm');
|
|
149
|
+
font-weight: font-weight('medium');
|
|
150
|
+
letter-spacing: 0.02em;
|
|
147
151
|
}
|
|
148
152
|
|
|
149
|
-
|
|
150
|
-
|
|
153
|
+
// Carries the secondary colour, because the badge is a state, not a label -
|
|
154
|
+
// override `background` for a different one
|
|
155
|
+
.mw-hero-badge-dot {
|
|
156
|
+
width: 8px;
|
|
157
|
+
height: 8px;
|
|
158
|
+
flex-shrink: 0;
|
|
159
|
+
border-radius: radius('full');
|
|
160
|
+
background: var(--mw-secondary-color);
|
|
151
161
|
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Bottom right instead of centred, for a hero whose text is not centred
|
|
155
|
-
// either - the two would otherwise sit on top of each other.
|
|
156
|
-
.mw-container:has(.mw-hero) > .mw-scroll-hint-end {
|
|
157
|
-
left: auto;
|
|
158
|
-
right: var(--mw-scroll-hint-inline);
|
|
159
|
-
margin-inline: 0;
|
|
160
|
-
}
|
|
161
162
|
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
// to them is free, so both variants go there and the cue stays on screen.
|
|
165
|
-
@include media-down('md') {
|
|
163
|
+
// Belongs to the hero container, not to the flow below it, so the cue sits on
|
|
164
|
+
// the lower edge whatever the content does. Beats the `> *` rule above it.
|
|
166
165
|
.mw-container:has(.mw-hero) > .mw-scroll-hint {
|
|
166
|
+
position: absolute;
|
|
167
|
+
bottom: var(--mw-scroll-hint-offset);
|
|
167
168
|
left: auto;
|
|
168
169
|
right: var(--mw-scroll-hint-inline);
|
|
170
|
+
width: fit-content;
|
|
169
171
|
margin-inline: 0;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
+
display: flex;
|
|
173
|
+
flex-direction: column;
|
|
174
|
+
align-items: center;
|
|
175
|
+
gap: spacing('2');
|
|
176
|
+
color: color-mix(in srgb, var(--mw-hero-text-color) 72%, transparent);
|
|
177
|
+
font-size: font-size('xs');
|
|
178
|
+
letter-spacing: 0.08em;
|
|
179
|
+
text-transform: uppercase;
|
|
180
|
+
text-decoration: none;
|
|
181
|
+
animation: mw-scroll-hint-float 2.2s var(--mw-ease-in-out) infinite;
|
|
182
|
+
text-shadow: 0 1px 4px rgb(0 0 0 / 65%);
|
|
172
183
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
184
|
+
// The arrow carries the meaning, so it gets the size and the label stays quiet
|
|
185
|
+
> i,
|
|
186
|
+
> svg {
|
|
187
|
+
font-size: font-size('lg');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@include hover {
|
|
191
|
+
color: var(--mw-hero-text-color);
|
|
192
|
+
}
|
|
180
193
|
}
|
|
181
|
-
}
|
|
182
194
|
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
animation: none;
|
|
195
|
+
// For a hero whose text is not centred either, or the two sit on each other
|
|
196
|
+
.mw-container:has(.mw-hero) > .mw-scroll-hint-end {
|
|
197
|
+
left: auto;
|
|
198
|
+
right: var(--mw-scroll-hint-inline);
|
|
199
|
+
margin-inline: 0;
|
|
189
200
|
}
|
|
190
|
-
}
|
|
191
201
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
202
|
+
// Both variants start in the corner, because on a phone the middle under the
|
|
203
|
+
// hero is taken. Only the plain one comes back - the end variant belongs there,
|
|
204
|
+
// and the rule above reserves no strip for it.
|
|
205
|
+
@include media-up('md') {
|
|
206
|
+
.mw-container:has(.mw-hero) > .mw-scroll-hint:not(.mw-scroll-hint-end) {
|
|
207
|
+
left: 0;
|
|
208
|
+
right: 0;
|
|
209
|
+
margin-inline: auto;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
196
212
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
213
|
+
@keyframes mw-scroll-hint-float {
|
|
214
|
+
0%,
|
|
215
|
+
100% {
|
|
216
|
+
transform: translateY(0);
|
|
217
|
+
}
|
|
218
|
+
50% {
|
|
219
|
+
transform: translateY(7px);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
203
222
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
// container) cuts it off.
|
|
208
|
-
//
|
|
209
|
-
// Hidden means `display: none`, not `visibility: hidden`. A box that is hidden
|
|
210
|
-
// but still laid out counts towards the page's scrollable overflow: a 280px
|
|
211
|
-
// bubble centred on a trigger near the right edge added 50px of sideways scroll
|
|
212
|
-
// to a 320px screen, on a page where nothing visible was out of place. Coming
|
|
213
|
-
// back from `display: none` is a discrete transition, hence `allow-discrete`
|
|
214
|
-
// and the starting style - a browser that knows neither simply drops the
|
|
215
|
-
// transition and shows the bubble at once.
|
|
216
|
-
$_mw-tooltip-arrow: 6px;
|
|
217
|
-
$_mw-tooltip-gap: 8px;
|
|
218
|
-
|
|
219
|
-
[data-tooltip] {
|
|
220
|
-
position: relative;
|
|
221
|
-
|
|
222
|
-
&::before {
|
|
223
|
-
content: attr(data-tooltip);
|
|
224
|
-
position: absolute;
|
|
225
|
-
bottom: 100%;
|
|
226
|
-
left: 50%;
|
|
227
|
-
transform: translateX(-50%);
|
|
228
|
-
margin-bottom: $_mw-tooltip-gap + $_mw-tooltip-arrow;
|
|
229
|
-
max-width: min(280px, 90vw);
|
|
230
|
-
width: max-content;
|
|
231
|
-
padding: spacing('1') spacing('2');
|
|
232
|
-
background: var(--mw-gray-color);
|
|
233
|
-
color: $fixed-surface-text;
|
|
234
|
-
font-size: font-size('xs');
|
|
235
|
-
border-radius: radius('xs');
|
|
236
|
-
box-shadow: var(--mw-elevation-2);
|
|
237
|
-
pointer-events: none;
|
|
238
|
-
opacity: 0;
|
|
239
|
-
display: none;
|
|
240
|
-
transition:
|
|
241
|
-
opacity var(--mw-duration-fast) var(--mw-ease-out),
|
|
242
|
-
display var(--mw-duration-fast) allow-discrete;
|
|
243
|
-
z-index: z-index('tooltip');
|
|
223
|
+
.mw-content {
|
|
224
|
+
flex: 1;
|
|
225
|
+
padding-top: spacing('7');
|
|
244
226
|
}
|
|
245
227
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
transform: translateX(-50%);
|
|
252
|
-
margin-bottom: $_mw-tooltip-gap;
|
|
253
|
-
border: $_mw-tooltip-arrow solid transparent;
|
|
254
|
-
border-bottom-width: 0;
|
|
255
|
-
border-top-color: var(--mw-gray-color);
|
|
256
|
-
opacity: 0;
|
|
257
|
-
display: none;
|
|
258
|
-
transition:
|
|
259
|
-
opacity var(--mw-duration-fast) var(--mw-ease-out),
|
|
260
|
-
display var(--mw-duration-fast) allow-discrete;
|
|
261
|
-
z-index: z-index('tooltip');
|
|
228
|
+
.mw-content-centered {
|
|
229
|
+
min-height: 100dvh;
|
|
230
|
+
display: flex;
|
|
231
|
+
flex-direction: column;
|
|
232
|
+
justify-content: center;
|
|
262
233
|
}
|
|
263
234
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
235
|
+
// A pseudo element on the trigger, so an ancestor with `overflow: hidden` cuts
|
|
236
|
+
// it off. Hidden means `display: none`: a laid-out box still counts towards the
|
|
237
|
+
// page's overflow, and a 280px bubble near the right edge added 50px of sideways
|
|
238
|
+
// scroll on a phone. Hence `allow-discrete` and the starting style.
|
|
239
|
+
$_mw-tooltip-arrow: 6px;
|
|
240
|
+
$_mw-tooltip-gap: 8px;
|
|
270
241
|
|
|
271
|
-
|
|
242
|
+
[data-tooltip] {
|
|
243
|
+
position: relative;
|
|
244
|
+
|
|
245
|
+
&::before {
|
|
246
|
+
content: attr(data-tooltip);
|
|
247
|
+
position: absolute;
|
|
248
|
+
bottom: 100%;
|
|
249
|
+
left: 50%;
|
|
250
|
+
transform: translateX(-50%);
|
|
251
|
+
margin-bottom: $_mw-tooltip-gap + $_mw-tooltip-arrow;
|
|
252
|
+
max-width: min(280px, 90vw);
|
|
253
|
+
width: max-content;
|
|
254
|
+
padding: spacing('1') spacing('2');
|
|
255
|
+
background: var(--mw-gray-color);
|
|
256
|
+
color: $fixed-surface-text;
|
|
257
|
+
font-size: font-size('xs');
|
|
258
|
+
border-radius: radius('xs');
|
|
259
|
+
box-shadow: var(--mw-elevation-2);
|
|
260
|
+
pointer-events: none;
|
|
272
261
|
opacity: 0;
|
|
262
|
+
display: none;
|
|
263
|
+
transition:
|
|
264
|
+
opacity var(--mw-duration-fast) var(--mw-ease-out),
|
|
265
|
+
display var(--mw-duration-fast) allow-discrete;
|
|
266
|
+
z-index: z-index('tooltip');
|
|
273
267
|
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
268
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
269
|
+
&::after {
|
|
270
|
+
content: '';
|
|
271
|
+
position: absolute;
|
|
272
|
+
bottom: 100%;
|
|
273
|
+
left: 50%;
|
|
274
|
+
transform: translateX(-50%);
|
|
275
|
+
margin-bottom: $_mw-tooltip-gap;
|
|
276
|
+
border: $_mw-tooltip-arrow solid transparent;
|
|
277
|
+
border-bottom-width: 0;
|
|
278
|
+
border-top-color: var(--mw-gray-color);
|
|
279
|
+
opacity: 0;
|
|
280
|
+
display: none;
|
|
281
|
+
transition:
|
|
282
|
+
opacity var(--mw-duration-fast) var(--mw-ease-out),
|
|
283
|
+
display var(--mw-duration-fast) allow-discrete;
|
|
284
|
+
z-index: z-index('tooltip');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
&:hover::before,
|
|
288
|
+
&:hover::after,
|
|
289
|
+
&:focus-visible::before,
|
|
290
|
+
&:focus-visible::after {
|
|
291
|
+
opacity: 1;
|
|
292
|
+
display: block;
|
|
293
|
+
|
|
294
|
+
@starting-style {
|
|
295
|
+
opacity: 0;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// The clipping caveat above, lifted where the browser can do it: `fixed` takes
|
|
300
|
+
// the bubble out of the trigger's containing block, anchor positioning keeps
|
|
301
|
+
// it attached. No `anchor-name` needed - a pseudo element is implicitly
|
|
302
|
+
// anchored to the element it comes from.
|
|
303
|
+
//
|
|
304
|
+
// No `position-try-fallbacks: flip-block` on purpose: the arrow is a border
|
|
305
|
+
// triangle and would still point up, into a bubble that flipped below.
|
|
306
|
+
@supports (position-area: block-start) {
|
|
307
|
+
&::before,
|
|
308
|
+
&::after {
|
|
309
|
+
position: fixed;
|
|
310
|
+
position-area: block-start;
|
|
311
|
+
// The absolute placement these replace - left as-is they fight the
|
|
312
|
+
// position-area, which resolves the inset properties itself.
|
|
313
|
+
bottom: auto;
|
|
314
|
+
left: auto;
|
|
315
|
+
transform: none;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
281
318
|
}
|
|
282
319
|
}
|