maverick-wave 6.7.0 → 6.8.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/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "maverick-wave",
3
- "version": "6.7.0",
3
+ "version": "6.8.0",
4
4
  "config": {
5
- "version_short": "6.7"
5
+ "version_short": "6.8"
6
6
  },
7
7
  "description": "A lightweight, modern CSS framework for building responsive websites with elegance and speed.",
8
8
  "main": "src/js/main.js",
@@ -114,12 +114,21 @@
114
114
  // rather than off the end.
115
115
  $_radius-floor: map.get(v.$radius, 'xs');
116
116
 
117
+ // The sharp half of the signature on a value of its own, so the scale can round
118
+ // controls up without softening the one corner meant to read as sharp
119
+ $_radius-sharp-base: 5px;
120
+
117
121
  // Emitted through --mw-radius-scale, so one number retunes every rounded box in
118
122
  // the framework at once - 0 squares them off, above 1 rounds them further, and
119
123
  // the corner arc follows. 'none' and 'full' pass through: an explicit 0 stays
120
- // 0, and a circle has to stay a circle.
124
+ // 0, and a circle has to stay a circle. A length instead of a key takes the
125
+ // same scale and floor, for the few values that sit off the scale.
121
126
  @function radius($key) {
122
- $value: map.get(v.$radius, $key);
127
+ $value: $key;
128
+
129
+ @if meta.type-of($key) != 'number' {
130
+ $value: map.get(v.$radius, $key);
131
+ }
123
132
 
124
133
  @if $key == 'none' or $key == 'full' {
125
134
  @return $value;
@@ -137,7 +146,21 @@ $_radius-floor: map.get(v.$radius, 'xs');
137
146
 
138
147
  @return max(
139
148
  #{$_radius-floor},
140
- calc(#{map.get(v.$radius, 'sm')} * #{$scale} * #{$scale})
149
+ calc(#{$_radius-sharp-base} * #{$scale} * #{$scale})
150
+ );
151
+ }
152
+
153
+ // Where a floating island sits: percentages on a fixed box are the viewport's,
154
+ // so this puts the header's content box on the page container,
155
+ // $header-island-reach wider on either side - and the bar at the foot on the
156
+ // same edges. Logo and links stay put while the header docks around them.
157
+ @function island-edge() {
158
+ @return max(
159
+ calc(var(--mw-header-inset) - #{v.$header-island-reach}),
160
+ calc(
161
+ (100% - var(--mw-container-width)) / 2 - var(--mw-header-pad) -
162
+ #{v.$header-island-reach}
163
+ )
141
164
  );
142
165
  }
143
166
 
@@ -276,6 +276,15 @@
276
276
  }
277
277
  }
278
278
 
279
+ // The floating chrome, shared by the header island and the action bar island
280
+ @mixin island-surface {
281
+ background: var(--mw-header-glass);
282
+ backdrop-filter: blur(20px) saturate(1.6);
283
+ border: 1px solid var(--mw-header-island-border);
284
+ border-radius: radius('xl');
285
+ box-shadow: var(--mw-elevation-4);
286
+ }
287
+
279
288
  // The MaverickWave silhouette: sharp corners on one diagonal, round on the other,
280
289
  // with an accent arc on the round pair - the asymmetry alone reads as an accident.
281
290
  //
@@ -434,9 +434,9 @@ $header-colors: (
434
434
  );
435
435
  // The room the header takes from the top of the viewport - island plus the gap
436
436
  // above it - so every offset that reads it clears the island without knowing it
437
- // floats. The island itself is 60px: a 44px touch control + 2 × spacing('2') +
437
+ // floats. The island itself is 63px: a 44px touch control + 2 × spacing('2') +
438
438
  // 2px border, with room to spare around the 42px logo.
439
- $header-height: 74px;
439
+ $header-height: 77px;
440
440
  // Between the island and the viewport edge
441
441
  $header-inset: 14px;
442
442
  // How far the island reaches past the page container on either side, and in
@@ -537,14 +537,20 @@ $breakpoints: (
537
537
  $radius: (
538
538
  'none': 0,
539
539
  'xs': 2px,
540
- 'sm': 5px,
541
- 'md': 10px,
540
+ 'sm': 7px,
541
+ 'md': 12px,
542
542
  'lg': 15px,
543
543
  'xl': 20px,
544
544
  '2xl': 30px,
545
545
  'full': 50%,
546
546
  );
547
547
 
548
+ // Off the scale on purpose: a chip next to a tag stays tighter than the buttons
549
+ // and fields it would otherwise be mistaken for. Outside the map, or every key
550
+ // would turn into a mw-radius-* utility.
551
+ $chip-radius: 10px;
552
+ $chip-radius-sm: 5px;
553
+
548
554
  // Z-index
549
555
  $z-index: (
550
556
  'lift': 3,
@@ -1,5 +1,11 @@
1
1
  @use '../abstracts' as *;
2
2
 
3
+ // Clear of the home indicator where there is one, the header's gap where not
4
+ $_island-bottom: max(var(--mw-header-inset), env(safe-area-inset-bottom, 0px));
5
+ // Lighter than the flat bar, and as low as it goes: the items keep their
6
+ // 2.75rem touch floor, so the rest is only the padding around them
7
+ $_island-height: calc(var(--mw-action-bar-height) - 4px);
8
+
3
9
  @layer mw.components {
4
10
  :root {
5
11
  --mw-action-bar-height: 3.75rem;
@@ -18,6 +24,10 @@
18
24
  }
19
25
  }
20
26
 
27
+ :root:has(.mw-action-bar-island:not(.mw-action-bar-embedded)) {
28
+ --mw-action-bar-reserve: calc(#{$_island-height} + #{$_island-bottom});
29
+ }
30
+
21
31
  // Chrome like the header, so it takes the header's colours in both themes
22
32
  .mw-action-bar {
23
33
  --mw-focus-ring-color: var(--mw-header-navbar-list-active-color);
@@ -44,6 +54,19 @@
44
54
  position: absolute;
45
55
  }
46
56
 
57
+ &-island {
58
+ inset-inline: island-edge();
59
+ bottom: $_island-bottom;
60
+ min-height: $_island-height;
61
+ padding: spacing('1');
62
+ @include island-surface;
63
+
64
+ // Its own frame has no page container to line up with
65
+ &.mw-action-bar-embedded {
66
+ inset-inline: calc(var(--mw-header-inset) - #{$header-island-reach});
67
+ }
68
+ }
69
+
47
70
  &-item {
48
71
  display: flex;
49
72
  flex-direction: column;
@@ -129,6 +152,12 @@
129
152
  justify-content: center;
130
153
  grid-auto-columns: minmax(0, 10rem);
131
154
  }
155
+
156
+ // A dock: a container-wide island would float the targets in empty glass
157
+ .mw-action-bar-island {
158
+ width: fit-content;
159
+ margin-inline: auto;
160
+ }
132
161
  }
133
162
 
134
163
  @media print {
@@ -95,7 +95,7 @@
95
95
  &-language {
96
96
  font-size: font-size('2xs');
97
97
  padding: spacing('1');
98
- border-radius: radius('sm');
98
+ border-radius: radius($chip-radius-sm);
99
99
 
100
100
  @include media-up('sm') {
101
101
  font-size: font-size('xs');
@@ -13,7 +13,7 @@
13
13
  text-decoration: none;
14
14
  background: var(--mw-card-background);
15
15
  border: 1px solid var(--mw-border);
16
- border-radius: radius('md');
16
+ border-radius: radius($chip-radius);
17
17
  padding: spacing('2');
18
18
  transition: var(--mw-transition-fast);
19
19
  color: var(--mw-text-color);
@@ -55,7 +55,7 @@
55
55
  padding: spacing('1') spacing('2');
56
56
  min-width: 32px;
57
57
  min-height: 32px;
58
- border-radius: radius('sm');
58
+ border-radius: radius($chip-radius-sm);
59
59
 
60
60
  .mw-techstack-logo {
61
61
  width: 18px;
@@ -78,7 +78,7 @@
78
78
 
79
79
  &-logo {
80
80
  object-fit: contain;
81
- border-radius: radius('sm');
81
+ border-radius: radius($chip-radius-sm);
82
82
  transition: transform var(--mw-duration-fast) var(--mw-ease-out);
83
83
  flex-shrink: 0;
84
84
  }
@@ -9,7 +9,6 @@ $dock-range: 160px;
9
9
  $float-edge: (0 0 0 1px rgb(255 255 255 / 0.22), 0 4px 14px rgb(0 0 0 / 0.4));
10
10
 
11
11
  @layer mw.layout {
12
- // None of it on the flat bar, which stands where it is from the first frame
13
12
  :root:not(.mw-header-bar) {
14
13
  // A header that stays put starts as the full bar and docks into the island over
15
14
  // the first stretch of scroll. A revealing one is off screen up there anyway and
@@ -51,172 +50,171 @@ $float-edge: (0 0 0 1px rgb(255 255 255 / 0.22), 0 4px 14px rgb(0 0 0 / 0.4));
51
50
  }
52
51
  }
53
52
  }
53
+ }
54
54
 
55
- // The bar starts above the screen and rides in over the first stretch of scroll.
56
- // Its own file, and not next to .mw-header: that one uses the `animation`
57
- // shorthand, which a consumer bundler folds together with a timeline into a
58
- // declaration no browser accepts.
59
- @supports (animation-timeline: scroll()) {
60
- .mw-header-reveal {
61
- @include motion-safe {
62
- animation-name: mw-header-reveal;
63
- animation-timing-function: var(--mw-ease-out);
64
- animation-fill-mode: both;
65
- animation-timeline: scroll(root);
66
- animation-range: 0 420px;
67
- }
55
+ // The bar starts above the screen and rides in over the first stretch of scroll.
56
+ // Its own file, and not next to .mw-header: that one uses the `animation`
57
+ // shorthand, which a consumer bundler folds together with a timeline into a
58
+ // declaration no browser accepts.
59
+ @supports (animation-timeline: scroll()) {
60
+ .mw-header-reveal {
61
+ @include motion-safe {
62
+ animation-name: mw-header-reveal;
63
+ animation-timing-function: var(--mw-ease-out);
64
+ animation-fill-mode: both;
65
+ animation-timeline: scroll(root);
66
+ animation-range: 0 420px;
68
67
  }
68
+ }
69
69
 
70
- // The bar travels, a keep element travels the same distance back and stays
71
- // put - for a burger that has to be reachable while the hero is untouched.
72
- .mw-header-reveal .mw-header-keep {
73
- @include motion-safe {
74
- animation-name: mw-header-keep;
75
- animation-timing-function: var(--mw-ease-out);
76
- animation-fill-mode: both;
77
- animation-timeline: scroll(root);
78
- animation-range: 0 420px;
79
- }
70
+ // The bar travels, a keep element travels the same distance back and stays
71
+ // put - for a burger that has to be reachable while the hero is untouched.
72
+ .mw-header-reveal .mw-header-keep {
73
+ @include motion-safe {
74
+ animation-name: mw-header-keep;
75
+ animation-timing-function: var(--mw-ease-out);
76
+ animation-fill-mode: both;
77
+ animation-timeline: scroll(root);
78
+ animation-range: 0 420px;
80
79
  }
80
+ }
81
81
 
82
- // A group's opacity cannot be taken back by a child, so the fade goes as
83
- // soon as something is meant to stay visible through it.
84
- .mw-header-reveal:has(.mw-header-keep) {
85
- @include motion-safe {
86
- animation-name: mw-header-slide;
87
- }
82
+ // A group's opacity cannot be taken back by a child, so the fade goes as
83
+ // soon as something is meant to stay visible through it.
84
+ .mw-header-reveal:has(.mw-header-keep) {
85
+ @include motion-safe {
86
+ animation-name: mw-header-slide;
88
87
  }
88
+ }
89
89
 
90
- // Glued under the bar, so it leaves and arrives with it. No class of its
91
- // own: a ribbon under a revealing header has no other sensible behaviour.
92
- body:has(.mw-header-reveal)
93
- .mw-announcement:not(.mw-announcement-static) {
94
- @include motion-safe {
95
- animation-name: mw-announcement-reveal;
96
- animation-timing-function: var(--mw-ease-out);
97
- animation-fill-mode: both;
98
- animation-timeline: scroll(root);
99
- animation-range: 0 420px;
100
- }
90
+ // Glued under the bar, so it leaves and arrives with it. No class of its
91
+ // own: a ribbon under a revealing header has no other sensible behaviour.
92
+ body:has(.mw-header-reveal) .mw-announcement:not(.mw-announcement-static) {
93
+ @include motion-safe {
94
+ animation-name: mw-announcement-reveal;
95
+ animation-timing-function: var(--mw-ease-out);
96
+ animation-fill-mode: both;
97
+ animation-timeline: scroll(root);
98
+ animation-range: 0 420px;
101
99
  }
102
100
  }
101
+ }
102
+
103
+ // Both cover the height of the pair, or the shorter traveller arrives first and
104
+ // the two come in as two things instead of one block.
105
+ .mw-header-reveal {
106
+ --mw-header-reveal-offset: var(--mw-header-height);
107
+ }
103
108
 
104
- // Both cover the height of the pair, or the shorter traveller arrives first and
105
- // the two come in as two things instead of one block.
109
+ body:has(.mw-announcement:not(.mw-announcement-static)) .mw-header-reveal {
110
+ --mw-header-reveal-offset: calc(
111
+ var(--mw-header-height) + var(--mw-announcement-height)
112
+ );
113
+ }
114
+
115
+ // A focus ring on something off screen is WCAG 2.4.11, so focus brings the bar
116
+ // back. `!important` is the one author declaration that outranks a running
117
+ // animation; `animation-name: none` would strand the element on its last value
118
+ // until the next scroll. Keeps are left out - they are on screen already, and a
119
+ // click on the theme toggle would otherwise haul in the whole bar. `:focus` on a
120
+ // descendant and not `:focus-within`: that matches every wrapper too.
121
+ body:has(
122
+ .mw-header-reveal :focus:not(.mw-header-keep, .mw-header-keep *),
123
+ .mw-announcement:focus-within
124
+ ) {
106
125
  .mw-header-reveal {
107
- --mw-header-reveal-offset: var(--mw-header-height);
126
+ top: var(--mw-header-inset) !important;
127
+ opacity: 1 !important;
108
128
  }
109
129
 
110
- body:has(.mw-announcement:not(.mw-announcement-static)) .mw-header-reveal {
111
- --mw-header-reveal-offset: calc(
112
- var(--mw-header-height) + var(--mw-announcement-height)
113
- );
130
+ .mw-header-keep {
131
+ translate: none !important;
132
+ box-shadow: none !important;
114
133
  }
115
134
 
116
- // A focus ring on something off screen is WCAG 2.4.11, so focus brings the bar
117
- // back. `!important` is the one author declaration that outranks a running
118
- // animation; `animation-name: none` would strand the element on its last value
119
- // until the next scroll. Keeps are left out - they are on screen already, and a
120
- // click on the theme toggle would otherwise haul in the whole bar. `:focus` on a
121
- // descendant and not `:focus-within`: that matches every wrapper too.
122
- body:has(
123
- .mw-header-reveal :focus:not(.mw-header-keep, .mw-header-keep *),
124
- .mw-announcement:focus-within
125
- ) {
126
- .mw-header-reveal {
127
- top: var(--mw-header-inset) !important;
128
- opacity: 1 !important;
129
- }
135
+ .mw-announcement:not(.mw-announcement-static) {
136
+ transform: none !important;
137
+ opacity: 1 !important;
138
+ }
139
+ }
130
140
 
131
- .mw-header-keep {
132
- translate: none !important;
133
- box-shadow: none !important;
134
- }
141
+ // The panel hangs off the bar, so the bar has to be in place - and the burger,
142
+ // which is the X while the panel is out, has to stay on its own position.
143
+ //
144
+ // A class the script sets, not `:has(.mw-navbar.mw-active)`: the burger is the
145
+ // control that closes the panel and cannot wait for a selector re-match, which
146
+ // is where WebKit's invalidation has been unreliable.
147
+ //
148
+ // Zeroing the distance rather than overriding each position that reads it: four
149
+ // mechanisms carry the pair - `top` and `translate`, each once as a class and
150
+ // once as a keyframe - and all four resolve this one property. Overriding the
151
+ // values instead pits `!important` against a running animation, which WebKit
152
+ // does not reliably hand to the author.
153
+ body.mw-nav-open {
154
+ .mw-header-reveal {
155
+ // The ribbon variant above raises the same property from a `:has()`, which
156
+ // counts its argument and outranks this rule - author against author, which
157
+ // every engine resolves the same way, not author against an animation.
158
+ --mw-header-reveal-offset: 0px !important;
159
+ opacity: 1 !important;
160
+ }
135
161
 
136
- .mw-announcement:not(.mw-announcement-static) {
137
- transform: none !important;
138
- opacity: 1 !important;
139
- }
162
+ // Not carried by the offset, and there is no picture behind an open panel.
163
+ .mw-header-keep {
164
+ box-shadow: none !important;
140
165
  }
166
+ }
141
167
 
142
- // The panel hangs off the bar, so the bar has to be in place - and the burger,
143
- // which is the X while the panel is out, has to stay on its own position.
144
- //
145
- // A class the script sets, not `:has(.mw-navbar.mw-active)`: the burger is the
146
- // control that closes the panel and cannot wait for a selector re-match, which
147
- // is where WebKit's invalidation has been unreliable.
148
- //
149
- // Zeroing the distance rather than overriding each position that reads it: four
150
- // mechanisms carry the pair - `top` and `translate`, each once as a class and
151
- // once as a keyframe - and all four resolve this one property. Overriding the
152
- // values instead pits `!important` against a running animation, which WebKit
153
- // does not reliably hand to the author.
154
- body.mw-nav-open {
155
- .mw-header-reveal {
156
- // The ribbon variant above raises the same property from a `:has()`, which
157
- // counts its argument and outranks this rule - author against author, which
158
- // every engine resolves the same way, not author against an animation.
159
- --mw-header-reveal-offset: 0px !important;
160
- opacity: 1 !important;
168
+ // No scroll timelines: the script toggles these classes instead (main.js).
169
+ // State and transition are separate because the script sets the state a frame
170
+ // earlier - together the bar would slide away in front of the reader.
171
+ .mw-header-reveal.mw-header-away {
172
+ @include motion-safe {
173
+ top: calc(var(--mw-header-inset) - var(--mw-header-reveal-offset));
174
+ opacity: 0;
175
+
176
+ // Visible through the slide, so its shadow would hang into the hero
177
+ &:has(.mw-header-keep) {
178
+ opacity: 1;
179
+ box-shadow: none;
161
180
  }
162
181
 
163
- // Not carried by the offset, and there is no picture behind an open panel.
164
182
  .mw-header-keep {
165
- box-shadow: none !important;
183
+ translate: 0 var(--mw-header-reveal-offset);
184
+ box-shadow: $float-edge;
166
185
  }
167
186
  }
187
+ }
168
188
 
169
- // No scroll timelines: the script toggles these classes instead (main.js).
170
- // State and transition are separate because the script sets the state a frame
171
- // earlier - together the bar would slide away in front of the reader.
172
- .mw-header-reveal.mw-header-away {
173
- @include motion-safe {
174
- top: calc(var(--mw-header-inset) - var(--mw-header-reveal-offset));
175
- opacity: 0;
176
-
177
- // Visible through the slide, so its shadow would hang into the hero
178
- &:has(.mw-header-keep) {
179
- opacity: 1;
180
- box-shadow: none;
181
- }
182
-
183
- .mw-header-keep {
184
- translate: 0 var(--mw-header-reveal-offset);
185
- box-shadow: $float-edge;
186
- }
187
- }
188
- }
189
+ .mw-header-driven {
190
+ @include motion-safe {
191
+ // The shared list plus `top`: writing only `top` drops the bar's own.
192
+ transition:
193
+ var(--mw-transition),
194
+ top var(--mw-duration-slow) var(--mw-ease-out);
189
195
 
190
- .mw-header-driven {
191
- @include motion-safe {
192
- // The shared list plus `top`: writing only `top` drops the bar's own.
196
+ .mw-header-keep {
193
197
  transition:
194
- var(--mw-transition),
195
- top var(--mw-duration-slow) var(--mw-ease-out);
196
-
197
- .mw-header-keep {
198
- transition:
199
- translate var(--mw-duration-slow) var(--mw-ease-out),
200
- box-shadow var(--mw-duration-slow) var(--mw-ease-out);
201
- }
198
+ translate var(--mw-duration-slow) var(--mw-ease-out),
199
+ box-shadow var(--mw-duration-slow) var(--mw-ease-out);
202
200
  }
203
201
  }
202
+ }
204
203
 
205
- .mw-announcement.mw-announcement-away {
206
- @include motion-safe {
207
- transform: translateY(
208
- calc(-1 * (var(--mw-header-height) + var(--mw-announcement-height)))
209
- );
210
- opacity: 0;
211
- }
204
+ .mw-announcement.mw-announcement-away {
205
+ @include motion-safe {
206
+ transform: translateY(
207
+ calc(-1 * (var(--mw-header-height) + var(--mw-announcement-height)))
208
+ );
209
+ opacity: 0;
212
210
  }
211
+ }
213
212
 
214
- .mw-announcement-driven {
215
- @include motion-safe {
216
- transition:
217
- transform var(--mw-duration-slow) var(--mw-ease-out),
218
- opacity var(--mw-duration-slow) var(--mw-ease-out);
219
- }
213
+ .mw-announcement-driven {
214
+ @include motion-safe {
215
+ transition:
216
+ transform var(--mw-duration-slow) var(--mw-ease-out),
217
+ opacity var(--mw-duration-slow) var(--mw-ease-out);
220
218
  }
221
219
  }
222
220
 
@@ -7,17 +7,6 @@ $_control-size: 40px;
7
7
  // frame on a box this short
8
8
  $_mark-round: radius('lg');
9
9
 
10
- // Where the island sits: percentages on a fixed box are the viewport's, so this
11
- // puts its content box on the page container, $header-island-reach wider on
12
- // either side. Logo and links stay put while the bar docks around them.
13
- $_island-edge: max(
14
- calc(var(--mw-header-inset) - #{$header-island-reach}),
15
- calc(
16
- (100% - var(--mw-container-width)) / 2 - var(--mw-header-pad) -
17
- #{$header-island-reach}
18
- )
19
- );
20
-
21
10
  @mixin navbar-mark-shape {
22
11
  border-radius: radius-sharp() $_mark-round radius-sharp() $_mark-round;
23
12
 
@@ -51,16 +40,12 @@ $_island-edge: max(
51
40
  .mw-header {
52
41
  position: fixed;
53
42
  top: var(--mw-header-inset);
54
- left: $_island-edge;
55
- right: $_island-edge;
43
+ left: island-edge();
44
+ right: island-edge();
56
45
  z-index: z-index('header');
57
46
  // Dark in both themes, fixed light included, where no light-dark() flips
58
47
  --mw-focus-ring-color: var(--mw-header-navbar-list-active-color);
59
- background: var(--mw-header-glass);
60
- backdrop-filter: blur(20px) saturate(1.6);
61
- border: 1px solid var(--mw-header-island-border);
62
- border-radius: radius('xl');
63
- box-shadow: var(--mw-elevation-4);
48
+ @include island-surface;
64
49
  // The height comes from min-height; the padding only has to let a control
65
50
  // grown to its 2.75rem touch floor fit inside it
66
51
  padding: spacing('2') var(--mw-header-pad);
@@ -79,7 +64,7 @@ $_island-edge: max(
79
64
  min-width: 0;
80
65
  }
81
66
 
82
- // The island already sits on the page container, see $_island-edge
67
+ // The island already sits on the page container, see island-edge()
83
68
  .mw-container {
84
69
  width: 100%;
85
70
  display: flex;
@@ -600,8 +585,8 @@ $_island-edge: max(
600
585
  // rounding seam opens between them.
601
586
  .mw-announcement:not(.mw-announcement-static) {
602
587
  top: calc(var(--mw-header-height) - 1px);
603
- left: $_island-edge;
604
- right: $_island-edge;
588
+ left: island-edge();
589
+ right: island-edge();
605
590
  border: 1px solid var(--mw-header-island-border);
606
591
  border-top: none;
607
592
  border-radius: 0 0 radius('xl') radius('xl');
@@ -630,14 +615,16 @@ $_island-edge: max(
630
615
  visibility: hidden;
631
616
  }
632
617
 
633
- // The flat bar, for a site that wants the header to just stand there: full
634
- // width, fixed at the top, no island and no reveal (_header-reveal.scss is off
635
- // under the same class). On <html> like the other site-wide variants.
618
+ // The flat bar: full width, fixed at the top, no island and no docking (the
619
+ // dock in _header-reveal.scss is off under the same class). mw-header-reveal
620
+ // still rides it in. On <html> like the other site-wide variants.
636
621
  :root.mw-header-bar {
637
622
  --mw-header-height: #{$header-bar-height};
623
+ // Not `top: 0` on the header: that would outrank the reveal's resting and
624
+ // away positions, which are both counted from the inset
625
+ --mw-header-inset: 0px;
638
626
 
639
627
  .mw-header {
640
- top: 0;
641
628
  left: 0;
642
629
  right: 0;
643
630
  min-height: var(--mw-header-height);