maverick-wave 4.27.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.
Files changed (140) hide show
  1. package/.claude/settings.local.json +29 -1
  2. package/.claude/skills/mw-maverick-wave/SKILL.md +42 -25
  3. package/.claude/skills/mw-maverick-wave/examples/angular-services.md +16 -4
  4. package/.claude/skills/mw-maverick-wave/examples/static-landing-page.md +13 -4
  5. package/.claude/skills/mw-maverick-wave/references/components.md +90 -5
  6. package/.claude/skills/mw-maverick-wave/references/forms.md +14 -2
  7. package/.claude/skills/mw-maverick-wave/references/javascript.md +18 -4
  8. package/.claude/skills/mw-maverick-wave/references/layout.md +53 -19
  9. package/.claude/skills/mw-maverick-wave/references/theming.md +38 -1
  10. package/.impeccable/config.local.json +5 -0
  11. package/.impeccable/hook.cache.json +1 -0
  12. package/CHANGELOG.md +17 -0
  13. package/CLAUDE.md +5 -5
  14. package/README.md +48 -4
  15. package/index.html +19 -38
  16. package/maverick-wave.min.css +14 -12
  17. package/maverick-wave.min.js +1 -1
  18. package/package.json +2 -2
  19. package/scripts/verify.js +27 -2
  20. package/src/js/main.js +266 -75
  21. package/src/partials/accordions-container.html +6 -10
  22. package/src/partials/alerts-container.html +6 -6
  23. package/src/partials/announcement-container.html +5 -5
  24. package/src/partials/avatars-container.html +85 -17
  25. package/src/partials/badges-container.html +6 -6
  26. package/src/partials/blog-posts-container.html +11 -12
  27. package/src/partials/buttons-container.html +3 -3
  28. package/src/partials/cards-container.html +26 -9
  29. package/src/partials/code-container.html +5 -5
  30. package/src/partials/content-slider-container.html +5 -4
  31. package/src/partials/divider-container.html +7 -7
  32. package/src/partials/dropdown-container.html +2 -2
  33. package/src/partials/empty-state-container.html +5 -5
  34. package/src/partials/footer-container.html +21 -18
  35. package/src/partials/form-elements-container.html +14 -14
  36. package/src/partials/gallery-container.html +16 -8
  37. package/src/partials/get-started-container.html +4 -8
  38. package/src/partials/header-container.html +18 -7
  39. package/src/partials/header-utilities-container.html +192 -5
  40. package/src/partials/home-container.html +10 -20
  41. package/src/partials/input-group-container.html +11 -2
  42. package/src/partials/kbd-container.html +1 -1
  43. package/src/partials/login-container.html +5 -1
  44. package/src/partials/media-container.html +2 -2
  45. package/src/partials/modals-container.html +22 -32
  46. package/src/partials/pricing-container.html +9 -9
  47. package/src/partials/skeleton-container.html +6 -6
  48. package/src/partials/stepper-container.html +2 -2
  49. package/src/partials/tables-container.html +12 -12
  50. package/src/partials/tabs-container.html +17 -27
  51. package/src/partials/tags-container.html +23 -17
  52. package/src/partials/techstack-bucket-container.html +13 -0
  53. package/src/partials/tiles-container.html +26 -9
  54. package/src/partials/typography-container.html +7 -6
  55. package/src/partials/utilities-container.html +35 -15
  56. package/src/scss/_layers.scss +10 -0
  57. package/src/scss/abstracts/_index.scss +6 -0
  58. package/src/scss/abstracts/_mixins.scss +61 -153
  59. package/src/scss/abstracts/_variables.scss +123 -319
  60. package/src/scss/base/_base.scss +170 -190
  61. package/src/scss/base/_reset.scss +106 -104
  62. package/src/scss/base/_typography.scss +153 -151
  63. package/src/scss/components/_accordions.scss +97 -97
  64. package/src/scss/components/_alerts.scss +71 -70
  65. package/src/scss/components/_announcement.scss +71 -70
  66. package/src/scss/components/_avatars.scss +130 -142
  67. package/src/scss/components/_badge.scss +131 -132
  68. package/src/scss/components/_blog-post.scss +223 -220
  69. package/src/scss/components/_breadcrumbs.scss +93 -92
  70. package/src/scss/components/_button-bar.scss +102 -110
  71. package/src/scss/components/_buttons.scss +319 -324
  72. package/src/scss/components/_calendar.scss +251 -252
  73. package/src/scss/components/_cards.scss +359 -386
  74. package/src/scss/components/_code.scss +190 -194
  75. package/src/scss/components/_coming-soon.scss +77 -75
  76. package/src/scss/components/_content-slider.scss +90 -89
  77. package/src/scss/components/_divider.scss +55 -53
  78. package/src/scss/components/_dropdown.scss +179 -185
  79. package/src/scss/components/_empty-state.scss +57 -57
  80. package/src/scss/components/_flag.scss +325 -0
  81. package/src/scss/components/_gallery.scss +131 -133
  82. package/src/scss/components/_index.scss +2 -0
  83. package/src/scss/components/_info.scss +151 -167
  84. package/src/scss/components/_kanban.scss +332 -341
  85. package/src/scss/components/_kbd.scss +40 -38
  86. package/src/scss/components/_lang-switch.scss +108 -0
  87. package/src/scss/components/_links.scss +21 -28
  88. package/src/scss/components/_lists.scss +510 -514
  89. package/src/scss/components/_localhost-indicator.scss +26 -24
  90. package/src/scss/components/_media.scss +22 -20
  91. package/src/scss/components/_meta-info.scss +35 -33
  92. package/src/scss/components/_modals.scss +277 -186
  93. package/src/scss/components/_pagination.scss +81 -87
  94. package/src/scss/components/_panels.scss +99 -97
  95. package/src/scss/components/_pricing.scss +183 -241
  96. package/src/scss/components/_progress.scss +112 -89
  97. package/src/scss/components/_prose.scss +35 -33
  98. package/src/scss/components/_ratings.scss +40 -38
  99. package/src/scss/components/_segmented.scss +82 -84
  100. package/src/scss/components/_skeleton.scss +66 -72
  101. package/src/scss/components/_spinners.scss +155 -159
  102. package/src/scss/components/_stepper.scss +116 -116
  103. package/src/scss/components/_tables.scss +155 -148
  104. package/src/scss/components/_tabs.scss +232 -141
  105. package/src/scss/components/_tags.scss +109 -107
  106. package/src/scss/components/_techstack-bucket.scss +123 -122
  107. package/src/scss/components/_testimonial.scss +72 -70
  108. package/src/scss/components/_theme-toggle.scss +53 -51
  109. package/src/scss/components/_tiles.scss +174 -174
  110. package/src/scss/components/_timelines.scss +282 -280
  111. package/src/scss/components/_toasts.scss +66 -72
  112. package/src/scss/form-elements/_checkbox.scss +117 -132
  113. package/src/scss/form-elements/_form.scss +149 -115
  114. package/src/scss/form-elements/_input-group.scss +99 -103
  115. package/src/scss/form-elements/_input.scss +74 -74
  116. package/src/scss/form-elements/_login.scss +48 -48
  117. package/src/scss/form-elements/_prefilled.scss +53 -51
  118. package/src/scss/form-elements/_radio.scss +95 -107
  119. package/src/scss/form-elements/_select.scss +42 -42
  120. package/src/scss/form-elements/_slider.scss +117 -132
  121. package/src/scss/form-elements/_textarea.scss +68 -54
  122. package/src/scss/form-elements/_toggle.scss +127 -140
  123. package/src/scss/layout/_footer.scss +172 -171
  124. package/src/scss/layout/_grid.scss +268 -302
  125. package/src/scss/layout/_header.scss +426 -427
  126. package/src/scss/layout/_home.scss +28 -27
  127. package/src/scss/layout/_main.scss +275 -238
  128. package/src/scss/layout/_page-header.scss +38 -36
  129. package/src/scss/layout/_section.scss +150 -124
  130. package/src/scss/main.scss +1 -1
  131. package/src/scss/utilities/_accessibility.scss +46 -45
  132. package/src/scss/utilities/_aspect.scss +22 -20
  133. package/src/scss/utilities/_corner.scss +23 -5
  134. package/src/scss/utilities/_display.scss +76 -70
  135. package/src/scss/utilities/_elevation.scss +13 -11
  136. package/src/scss/utilities/_flex.scss +83 -85
  137. package/src/scss/utilities/_reveal.scss +40 -63
  138. package/src/scss/utilities/_spacing.scss +63 -64
  139. package/src/scss/utilities/_text.scss +139 -141
  140. package/src/scss/utilities/_touch-targets.scss +130 -147
@@ -1,536 +1,535 @@
1
1
  @use '../abstracts' as *;
2
2
 
3
- .mw-header {
4
- position: fixed;
5
- top: spacing('0');
6
- left: spacing('0');
7
- width: 100%;
8
- z-index: z-index('header');
9
- background: var(--mw-header-background);
10
- backdrop-filter: blur(7px);
11
- border-bottom: 1px solid var(--mw-header-border);
12
- padding: spacing('3') spacing('0');
13
- transition: var(--mw-transition);
14
- display: flex;
15
- align-items: center;
16
- min-height: var(--mw-header-height);
17
-
18
- // A component host (Angular, React) sitting between the header and its
19
- // container would become the flex item and shrink to content width, leaving
20
- // mw-container to center inside a far too narrow box. The container brings
21
- // its own width and centering, so the wrapper only has to fill the line.
22
- // Absolutely positioned children are out of flow and stay unaffected.
23
- > *:not(.mw-container) {
24
- flex: 1;
25
- min-width: 0;
26
- }
27
-
28
- .mw-container {
29
- display: flex;
30
- justify-content: space-between;
31
- align-items: center;
32
- gap: spacing('3');
33
- }
34
-
35
- .mw-logo {
3
+ @layer mw.layout {
4
+ .mw-header {
5
+ position: fixed;
6
+ top: spacing('0');
7
+ left: spacing('0');
8
+ width: 100%;
9
+ z-index: z-index('header');
10
+ background: var(--mw-header-background);
11
+ backdrop-filter: blur(7px);
12
+ border-bottom: 1px solid var(--mw-header-border);
13
+ padding: spacing('3') spacing('0');
14
+ transition: var(--mw-transition);
36
15
  display: flex;
37
16
  align-items: center;
38
- z-index: z-index('header') + 5;
39
- position: relative;
40
- flex-shrink: 1;
41
- min-width: 0;
42
-
43
- button {
44
- display: inline-block;
45
- text-decoration: none;
17
+ min-height: var(--mw-header-height);
18
+
19
+ // A component host (Angular, React) sitting between the header and its
20
+ // container would become the flex item and shrink to content width, leaving
21
+ // mw-container to center inside a far too narrow box. The container brings
22
+ // its own width and centering, so the wrapper only has to fill the line.
23
+ // Absolutely positioned children are out of flow and stay unaffected.
24
+ > *:not(.mw-container) {
25
+ flex: 1;
46
26
  min-width: 0;
47
27
  }
48
28
 
49
- img {
50
- height: 42px;
51
- width: auto;
52
- max-width: 100%;
53
- object-fit: contain;
54
- object-position: left center;
55
- display: block;
29
+ .mw-container {
30
+ display: flex;
31
+ justify-content: space-between;
32
+ align-items: center;
33
+ gap: spacing('3');
56
34
  }
57
- }
58
35
 
59
- .mw-header-actions {
60
- display: flex;
61
- align-items: center;
62
- gap: spacing('2');
63
- flex-shrink: 0;
64
- }
36
+ .mw-logo {
37
+ display: flex;
38
+ align-items: center;
39
+ z-index: z-index('header') + 5;
40
+ position: relative;
41
+ flex-shrink: 1;
42
+ min-width: 0;
65
43
 
66
- // Login button styling
67
- .mw-login-btn {
68
- background: var(--mw-primary-color);
69
- color: var(--mw-primary-accent-text-color);
70
- border: none;
71
- border-radius: radius('md');
72
- font-size: font-size('md');
73
- cursor: pointer;
74
- transition: var(--mw-transition);
75
- display: flex;
76
- align-items: center;
77
- justify-content: center;
78
- height: 40px;
79
- width: 50px;
80
- flex-shrink: 0;
44
+ a,
45
+ button {
46
+ display: inline-block;
47
+ text-decoration: none;
48
+ min-width: 0;
49
+ }
81
50
 
82
- &:hover:not(:disabled) {
83
- background: var(--mw-primary-color-hover);
84
- transform: translateY(-1px);
51
+ img {
52
+ height: 42px;
53
+ width: auto;
54
+ max-width: 100%;
55
+ object-fit: contain;
56
+ object-position: left center;
57
+ display: block;
58
+ }
85
59
  }
86
60
 
87
- &:disabled {
88
- // Same treatment as every other disabled button - a theme-bound text
89
- // color would go dark on this always-primary surface in light mode
90
- opacity: 0.6;
91
- cursor: not-allowed;
61
+ .mw-header-actions {
62
+ display: flex;
63
+ align-items: center;
64
+ gap: spacing('2');
65
+ flex-shrink: 0;
92
66
  }
93
- }
94
67
 
95
- // Updated burger button to look like primary button
96
- .mw-menu-btn {
97
- background: var(--mw-primary-color);
98
- border: none;
99
- cursor: pointer;
100
- outline: none;
101
- border-radius: radius('md');
102
- transition: var(--mw-transition);
103
- height: 40px;
104
- width: 50px;
105
- display: none;
106
- position: relative;
107
- flex-shrink: 0;
68
+ .mw-login-btn {
69
+ background: var(--mw-primary-color);
70
+ color: var(--mw-primary-accent-text-color);
71
+ border: none;
72
+ border-radius: radius('md');
73
+ font-size: font-size('md');
74
+ cursor: pointer;
75
+ transition: var(--mw-transition);
76
+ display: flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ height: 40px;
80
+ width: 50px;
81
+ flex-shrink: 0;
108
82
 
109
- // iOS
110
- -webkit-tap-highlight-color: transparent;
111
- -webkit-touch-callout: none;
112
- user-select: none;
113
- touch-action: manipulation;
83
+ &:hover:not(:disabled) {
84
+ background: var(--mw-primary-color-hover);
85
+ transform: translateY(-1px);
86
+ }
114
87
 
115
- &:hover {
116
- background: var(--mw-primary-color-hover);
117
- transform: translateY(-1px);
118
- }
88
+ @include focus-ring;
119
89
 
120
- &:active {
121
- transform: translateY(0);
90
+ &:disabled {
91
+ // Same treatment as every other disabled button - a theme-bound text
92
+ // color would go dark on this always-primary surface in light mode
93
+ opacity: 0.6;
94
+ cursor: not-allowed;
95
+ }
122
96
  }
123
97
 
124
- @include focus-ring;
125
-
126
- &.open {
127
- background: var(--mw-secondary-color);
128
- z-index: z-index('header') + 10;
98
+ .mw-menu-btn {
99
+ background: var(--mw-primary-color);
100
+ border: none;
101
+ padding: 0;
102
+ cursor: pointer;
103
+ outline: none;
104
+ border-radius: radius('md');
105
+ transition: var(--mw-transition);
106
+ height: 40px;
107
+ width: 50px;
108
+ display: none;
109
+ position: relative;
110
+ flex-shrink: 0;
129
111
 
130
- // The surface under the burger switches to secondary, so its ink has to
131
- // switch with it. Set on the button, so the bar and both pseudo-elements
132
- // pick it up.
133
- --mw-header-burgerbutton-color: var(--mw-header-burgerbutton-open-color);
112
+ // iOS
113
+ -webkit-tap-highlight-color: transparent;
114
+ -webkit-touch-callout: none;
115
+ user-select: none;
116
+ touch-action: manipulation;
134
117
 
135
118
  &:hover {
136
- background: var(--mw-secondary-color-hover);
119
+ background: var(--mw-primary-color-hover);
120
+ transform: translateY(-1px);
137
121
  }
138
122
 
139
- // Transform the burger to X
140
- .mw-menu-btn-burger {
141
- background: transparent;
123
+ &:active {
124
+ transform: translateY(0);
125
+ }
126
+
127
+ @include focus-ring;
128
+
129
+ &.open {
130
+ background: var(--mw-secondary-color);
131
+ z-index: z-index('header') + 10;
132
+
133
+ // The surface under the burger switches to secondary, so its ink has to
134
+ // switch with it. Set on the button, so the bar and both pseudo-elements
135
+ // pick it up.
136
+ --mw-header-burgerbutton-color: var(
137
+ --mw-header-burgerbutton-open-color
138
+ );
142
139
 
143
- &::before {
144
- top: 0;
145
- transform: rotate(45deg);
140
+ &:hover {
141
+ background: var(--mw-secondary-color-hover);
146
142
  }
147
143
 
148
- &::after {
149
- bottom: 0;
150
- transform: rotate(-45deg);
144
+ .mw-menu-btn-burger {
145
+ background: transparent;
146
+
147
+ &::before {
148
+ top: 0;
149
+ transform: rotate(45deg);
150
+ }
151
+
152
+ &::after {
153
+ bottom: 0;
154
+ transform: rotate(-45deg);
155
+ }
151
156
  }
152
157
  }
153
158
  }
154
- }
155
159
 
156
- .mw-menu-btn-burger {
157
- width: 18px;
158
- height: 2px;
159
- background: var(--mw-header-burgerbutton-color);
160
- border-radius: 1px;
161
- position: relative;
162
- // `all` on purpose, and the one place in the framework that keeps it: the
163
- // burger morphs into an X by moving its two bars to the centre, so `top`
164
- // and `bottom` have to animate - and those are exactly what the shared
165
- // property list leaves out.
166
- transition: all var(--mw-duration-base) var(--mw-ease-out);
167
-
168
- &::before,
169
- &::after {
170
- content: '';
171
- position: absolute;
172
- left: 0;
160
+ .mw-menu-btn-burger {
161
+ // A <span> in a button (a <div> is not phrasing content), so it needs a box
162
+ display: block;
173
163
  width: 18px;
174
164
  height: 2px;
175
165
  background: var(--mw-header-burgerbutton-color);
176
166
  border-radius: 1px;
167
+ position: relative;
168
+ // `all` on purpose, and the one place in the framework that keeps it: the
169
+ // burger morphs into an X by moving its two bars to the centre, so `top`
170
+ // and `bottom` have to animate - and those are exactly what the shared
171
+ // property list leaves out.
177
172
  transition: all var(--mw-duration-base) var(--mw-ease-out);
178
- }
179
-
180
- &::before {
181
- top: -6px;
182
- }
183
173
 
184
- &::after {
185
- bottom: -6px;
186
- }
187
- }
188
- }
174
+ &::before,
175
+ &::after {
176
+ content: '';
177
+ position: absolute;
178
+ left: 0;
179
+ width: 18px;
180
+ height: 2px;
181
+ background: var(--mw-header-burgerbutton-color);
182
+ border-radius: 1px;
183
+ transition: all var(--mw-duration-base) var(--mw-ease-out);
184
+ }
189
185
 
190
- // Off-canvas drawer for the collapsed navbar (mobile only)
191
- @mixin navbar-off-canvas {
192
- position: fixed;
193
- top: 0;
194
- right: 0;
195
- --mw-navbar-drawer-width: 250px;
196
- width: var(--mw-navbar-drawer-width);
197
- height: 100dvh;
198
- background: var(--mw-header-background);
199
- border-left: 1px solid var(--mw-header-border);
200
- box-shadow:
201
- -6px 0 12px var(--mw-shadow-near),
202
- -18px 0 40px var(--mw-shadow-far);
203
- z-index: z-index('header') + 3;
204
-
205
- transform: translateX(100%);
206
- visibility: hidden;
207
- transition:
208
- transform var(--mw-duration-base) var(--mw-ease-out),
209
- visibility var(--mw-duration-base);
210
-
211
- .mw-navbar-list {
212
- display: flex;
213
- flex-direction: column;
214
- align-items: stretch;
215
- gap: spacing('1');
216
- height: 100%;
217
- overflow-y: auto;
218
- // Keeps a rubber-band scroll inside the panel from moving the page
219
- overscroll-behavior: contain;
220
- padding: calc(
221
- var(--mw-header-height) + #{spacing('6')} + env(safe-area-inset-top)
222
- )
223
- spacing('4') calc(#{spacing('6')} + env(safe-area-inset-bottom));
224
- }
186
+ &::before {
187
+ top: -6px;
188
+ }
225
189
 
226
- .mw-navbar-item {
227
- width: 100%;
228
- margin: spacing('0');
229
- opacity: 0;
230
- transform: translateX(12px);
190
+ &::after {
191
+ bottom: -6px;
192
+ }
193
+ }
231
194
  }
232
195
 
233
- .mw-navbar-link {
234
- display: flex;
235
- align-items: center;
236
- min-height: 48px;
237
- width: 100%;
238
- padding: spacing('3') spacing('4');
239
- border-radius: radius('md');
240
- font-size: font-size('md');
241
- text-align: left;
242
- color: var(--mw-header-text-color);
243
-
244
- // The sliding underline is a hover affordance and has no place on touch
245
- &::after {
246
- display: none;
196
+ @mixin navbar-off-canvas {
197
+ position: fixed;
198
+ top: 0;
199
+ right: 0;
200
+ --mw-navbar-drawer-width: 250px;
201
+ width: var(--mw-navbar-drawer-width);
202
+ height: 100dvh;
203
+ background: var(--mw-header-background);
204
+ border-left: 1px solid var(--mw-header-border);
205
+ box-shadow:
206
+ -6px 0 12px var(--mw-shadow-near),
207
+ -18px 0 40px var(--mw-shadow-far);
208
+ z-index: z-index('header') + 3;
209
+
210
+ transform: translateX(100%);
211
+ visibility: hidden;
212
+ transition:
213
+ transform var(--mw-duration-base) var(--mw-ease-out),
214
+ visibility var(--mw-duration-base);
215
+
216
+ .mw-navbar-list {
217
+ display: flex;
218
+ flex-direction: column;
219
+ align-items: stretch;
220
+ gap: spacing('1');
221
+ height: 100%;
222
+ overflow-y: auto;
223
+ // Keeps a rubber-band scroll inside the panel from moving the page
224
+ overscroll-behavior: contain;
225
+ padding: calc(
226
+ var(--mw-header-height) + #{spacing('6')} + env(safe-area-inset-top)
227
+ )
228
+ spacing('4') calc(#{spacing('6')} + env(safe-area-inset-bottom));
247
229
  }
248
230
 
249
- // Restated here: the plain color above already outranks the base
250
- &:hover {
251
- color: var(--mw-header-navbar-list-active-color);
252
- background: var(--mw-primary-background);
231
+ .mw-navbar-item {
232
+ width: 100%;
233
+ margin: spacing('0');
234
+ opacity: 0;
235
+ transform: translateX(12px);
253
236
  }
254
237
 
255
- &:active {
256
- background: var(--mw-primary-background-hover);
257
- }
238
+ .mw-navbar-link {
239
+ display: flex;
240
+ align-items: center;
241
+ min-height: 48px;
242
+ width: 100%;
243
+ padding: spacing('3') spacing('4');
244
+ border-radius: radius('md');
245
+ font-size: font-size('md');
246
+ text-align: left;
247
+ color: var(--mw-header-text-color);
248
+
249
+ // The sliding underline is a hover affordance and has no place on touch
250
+ &::after {
251
+ display: none;
252
+ }
258
253
 
259
- // Last, so the current page keeps its look while being hovered
260
- &.mw-active,
261
- &.active {
262
- color: var(--mw-header-navbar-list-active-color);
263
- background: var(--mw-primary-background);
264
- box-shadow: inset 3px 0 0 var(--mw-header-navbar-list-active-color);
265
- font-weight: font-weight('medium');
266
- }
267
- }
254
+ // Restated here: the plain color above already outranks the base
255
+ &:hover {
256
+ color: var(--mw-header-navbar-list-active-color);
257
+ background: var(--mw-primary-background);
258
+ }
268
259
 
269
- &.open {
270
- transform: translateX(0);
271
- visibility: visible;
260
+ &:active {
261
+ background: var(--mw-primary-background-hover);
262
+ }
272
263
 
273
- // Items follow the panel in, slightly staggered
274
- .mw-navbar-item {
275
- animation: mw-navbar-item-in var(--mw-duration-base) var(--mw-ease-out)
276
- forwards;
264
+ // Last, so the current page keeps its look while being hovered
265
+ @include active() {
266
+ color: var(--mw-header-navbar-list-active-color);
267
+ background: var(--mw-primary-background);
268
+ box-shadow: inset 3px 0 0 var(--mw-header-navbar-list-active-color);
269
+ font-weight: font-weight('medium');
270
+ }
271
+ }
277
272
 
278
- @for $i from 1 through 10 {
279
- &:nth-child(#{$i}) {
280
- animation-delay: 0.1s + $i * 0.035s;
273
+ &.open {
274
+ transform: translateX(0);
275
+ visibility: visible;
276
+
277
+ // Items follow the panel in, slightly staggered
278
+ .mw-navbar-item {
279
+ animation: mw-navbar-item-in var(--mw-duration-base) var(--mw-ease-out)
280
+ forwards;
281
+
282
+ @for $i from 1 through 10 {
283
+ &:nth-child(#{$i}) {
284
+ animation-delay: 0.1s + $i * 0.035s;
285
+ }
281
286
  }
282
287
  }
283
288
  }
284
- }
285
289
 
286
- @media (prefers-reduced-motion: reduce) {
287
- transition-duration: 0.01ms;
290
+ @media (prefers-reduced-motion: reduce) {
291
+ transition-duration: 0.01ms;
288
292
 
289
- .mw-navbar-item {
290
- opacity: 1;
291
- transform: none;
292
- animation: none;
293
+ .mw-navbar-item {
294
+ opacity: 1;
295
+ transform: none;
296
+ animation: none;
297
+ }
293
298
  }
294
299
  }
295
- }
296
300
 
297
- // Page scrim behind the drawer
298
- @mixin navbar-scrim($navbar-selector) {
299
- body:has(#{$navbar-selector}.open) {
300
- overflow: hidden;
301
+ @mixin navbar-scrim($navbar-selector) {
302
+ body:has(#{$navbar-selector}.open) {
303
+ overflow: hidden;
301
304
 
302
- &::after {
303
- content: '';
304
- position: fixed;
305
- inset: 0;
306
- background: var(--mw-overlay-background);
307
- backdrop-filter: blur(2px);
308
- z-index: z-index('header') - 1;
309
- animation: mw-navbar-scrim-in var(--mw-duration-base) var(--mw-ease-out);
305
+ &::after {
306
+ content: '';
307
+ position: fixed;
308
+ inset: 0;
309
+ background: var(--mw-overlay-background);
310
+ backdrop-filter: blur(2px);
311
+ z-index: z-index('header') - 1;
312
+ animation: mw-navbar-scrim-in var(--mw-duration-base) var(--mw-ease-out);
313
+ }
310
314
  }
311
315
  }
312
- }
313
316
 
314
- @keyframes mw-navbar-item-in {
315
- to {
316
- opacity: 1;
317
- transform: translateX(0);
317
+ @keyframes mw-navbar-item-in {
318
+ to {
319
+ opacity: 1;
320
+ transform: translateX(0);
321
+ }
318
322
  }
319
- }
320
323
 
321
- @keyframes mw-navbar-scrim-in {
322
- from {
323
- opacity: 0;
324
+ @keyframes mw-navbar-scrim-in {
325
+ from {
326
+ opacity: 0;
327
+ }
324
328
  }
325
- }
326
329
 
327
- // Navbar with built-in auto-detection
328
- .mw-navbar {
329
- display: flex;
330
-
331
- &-list {
330
+ .mw-navbar {
332
331
  display: flex;
333
- list-style: none;
334
- margin: spacing('0');
335
- padding: spacing('0');
336
- gap: spacing('4');
337
- align-items: center;
338
- flex-wrap: nowrap;
339
- overflow: visible;
340
332
 
341
- @include media-down('lg') {
333
+ &-list {
334
+ display: flex;
335
+ list-style: none;
336
+ margin: spacing('0');
337
+ padding: spacing('0');
342
338
  gap: spacing('2');
343
- }
344
- }
345
-
346
- &-item {
347
- position: relative;
348
- flex-shrink: 0;
349
- white-space: nowrap;
350
- }
339
+ align-items: center;
340
+ flex-wrap: nowrap;
341
+ overflow: visible;
351
342
 
352
- &-link {
353
- position: relative;
354
- font-weight: font-weight('medium');
355
- font-size: inherit;
356
- transition: var(--mw-transition);
357
- color: var(--mw-header-navbar-list-color);
358
- padding-bottom: 3px;
359
-
360
- &::after {
361
- content: '';
362
- position: absolute;
363
- left: 10%;
364
- bottom: 0;
365
- width: 80%;
366
- height: 2px;
367
- background: currentColor;
368
- transform: scaleX(0);
369
- transform-origin: center;
370
- transition:
371
- transform var(--mw-duration-fast),
372
- opacity var(--mw-duration-fast);
373
- opacity: 0;
343
+ @include media-up('lg') {
344
+ gap: spacing('4');
345
+ }
374
346
  }
375
347
 
376
- &:hover,
377
- &.mw-active,
378
- &.active {
379
- color: var(--mw-header-navbar-list-active-color);
348
+ &-item {
349
+ position: relative;
350
+ flex-shrink: 0;
351
+ white-space: nowrap;
380
352
  }
381
353
 
382
- &:hover::after,
383
- &.mw-active::after,
384
- &.active::after {
385
- transform: scaleX(1) !important;
386
- opacity: 1 !important;
387
- }
388
- }
354
+ &-link {
355
+ position: relative;
356
+ font-weight: font-weight('medium');
357
+ font-size: inherit;
358
+ transition: var(--mw-transition);
359
+ color: var(--mw-header-navbar-list-color);
360
+ padding-bottom: 3px;
361
+
362
+ &::after {
363
+ content: '';
364
+ position: absolute;
365
+ left: 10%;
366
+ bottom: 0;
367
+ width: 80%;
368
+ height: 2px;
369
+ background: currentColor;
370
+ transform: scaleX(0);
371
+ transform-origin: center;
372
+ transition:
373
+ transform var(--mw-duration-fast),
374
+ opacity var(--mw-duration-fast);
375
+ opacity: 0;
376
+ }
389
377
 
390
- // Auto-responsive behavior based on nav item count
391
- // Default behavior (1-3 items): collapse at md
392
- @include media-down('md') {
393
- @include navbar-off-canvas;
394
- }
378
+ &:hover,
379
+ &.mw-active,
380
+ &.active {
381
+ color: var(--mw-header-navbar-list-active-color);
382
+ }
395
383
 
396
- // Medium (4-5 items): collapse at lg
397
- &.mw-navbar-medium {
398
- @include media-down('lg') {
399
- @include navbar-off-canvas;
384
+ &:hover::after,
385
+ &.mw-active::after,
386
+ &.active::after {
387
+ transform: scaleX(1) !important;
388
+ opacity: 1 !important;
389
+ }
400
390
  }
401
- }
402
391
 
403
- // Large (6+ items): collapse at xl
404
- &.mw-navbar-large {
405
- @include media-down('xl') {
392
+ // Auto-responsive behavior based on nav item count
393
+ // Default behavior (1-3 items): collapse at md
394
+ @include media-down('md') {
406
395
  @include navbar-off-canvas;
407
396
  }
408
- }
409
- }
410
397
 
411
- // Every variant is collapsed at md, so the default selector covers them all
412
- @include media-down('md') {
413
- @include navbar-scrim('.mw-navbar');
414
- }
415
-
416
- @include media-down('lg') {
417
- @include navbar-scrim('.mw-navbar-medium');
418
- }
398
+ // Medium (4-5 items): collapse at lg
399
+ &.mw-navbar-medium {
400
+ @include media-down('lg') {
401
+ @include navbar-off-canvas;
402
+ }
403
+ }
419
404
 
420
- @include media-down('xl') {
421
- @include navbar-scrim('.mw-navbar-large');
422
- }
405
+ // Large (6+ items): collapse at xl
406
+ &.mw-navbar-large {
407
+ @include media-down('xl') {
408
+ @include navbar-off-canvas;
409
+ }
410
+ }
411
+ }
423
412
 
424
- // Show burger button based on navbar size
425
- .mw-navbar {
426
- // Default (1-3 items): show burger at md
413
+ // Every variant is collapsed at md, so the default selector covers them all
427
414
  @include media-down('md') {
428
- ~ .mw-menu-btn {
429
- display: flex;
430
- align-items: center;
431
- justify-content: center;
432
- }
415
+ @include navbar-scrim('.mw-navbar');
433
416
  }
434
417
 
435
- &.mw-navbar-medium {
436
- // 4-5 items: show burger at lg
437
- @include media-down('lg') {
418
+ @include media-down('lg') {
419
+ @include navbar-scrim('.mw-navbar-medium');
420
+ }
421
+
422
+ @include media-down('xl') {
423
+ @include navbar-scrim('.mw-navbar-large');
424
+ }
425
+
426
+ .mw-navbar {
427
+ // Default (1-3 items): show burger at md
428
+ @include media-down('md') {
438
429
  ~ .mw-menu-btn {
439
430
  display: flex;
440
431
  align-items: center;
441
432
  justify-content: center;
442
433
  }
443
434
  }
444
- }
445
435
 
446
- &.mw-navbar-large {
447
- // 6+ items: show burger at xl
448
- @include media-down('xl') {
449
- ~ .mw-menu-btn {
450
- display: flex;
451
- align-items: center;
452
- justify-content: center;
436
+ &.mw-navbar-medium {
437
+ // 4-5 items: show burger at lg
438
+ @include media-down('lg') {
439
+ ~ .mw-menu-btn {
440
+ display: flex;
441
+ align-items: center;
442
+ justify-content: center;
443
+ }
453
444
  }
454
445
  }
455
- }
456
- }
457
446
 
458
- @keyframes fadeIn {
459
- from {
460
- opacity: 0;
461
- transform: translateY(-10px);
462
- }
463
- to {
464
- opacity: 1;
465
- transform: translateY(0);
447
+ &.mw-navbar-large {
448
+ // 6+ items: show burger at xl
449
+ @include media-down('xl') {
450
+ ~ .mw-menu-btn {
451
+ display: flex;
452
+ align-items: center;
453
+ justify-content: center;
454
+ }
455
+ }
456
+ }
466
457
  }
467
- }
468
458
 
469
- // Profile button - avatar plus the signed-in name
470
- .mw-profile-btn {
471
- display: inline-flex;
472
- align-items: center;
473
- gap: spacing('3');
474
- height: 40px;
475
- padding: spacing('0') spacing('4') spacing('0') spacing('1');
476
- background: transparent;
477
- border: 1px solid var(--mw-header-border);
478
- border-radius: radius('2xl');
479
- color: var(--mw-header-text-color);
480
- cursor: pointer;
481
- transition: var(--mw-transition);
482
- flex-shrink: 0;
483
- max-width: 220px;
484
-
485
- // The avatar brings spacing of its own that would break the pill shape
486
- .mw-avatar {
487
- margin: spacing('0');
488
- box-shadow: none;
489
- border-width: 0;
459
+ @keyframes fadeIn {
460
+ from {
461
+ opacity: 0;
462
+ transform: translateY(-10px);
463
+ }
464
+ to {
465
+ opacity: 1;
466
+ transform: translateY(0);
467
+ }
490
468
  }
491
469
 
492
- &-name {
493
- font-size: font-size('sm');
494
- font-weight: font-weight('medium');
495
- line-height: 1.2;
496
- white-space: nowrap;
497
- overflow: hidden;
498
- text-overflow: ellipsis;
499
- }
470
+ // Profile button - avatar plus the signed-in name
471
+ .mw-profile-btn {
472
+ display: inline-flex;
473
+ align-items: center;
474
+ gap: spacing('3');
475
+ height: 40px;
476
+ padding: spacing('0') spacing('4') spacing('0') spacing('1');
477
+ background: transparent;
478
+ border: 1px solid var(--mw-header-border);
479
+ border-radius: radius('2xl');
480
+ color: var(--mw-header-text-color);
481
+ cursor: pointer;
482
+ transition: var(--mw-transition);
483
+ flex-shrink: 0;
484
+ max-width: 220px;
500
485
 
501
- &:hover:not(:disabled) {
502
- background: var(--mw-primary-background-hover);
503
- border-color: var(--mw-primary-text-color);
504
- }
486
+ // The avatar brings spacing of its own that would break the pill shape
487
+ .mw-avatar {
488
+ margin: spacing('0');
489
+ box-shadow: none;
490
+ border-width: 0;
491
+ }
505
492
 
506
- @include focus-ring;
493
+ &-name {
494
+ font-size: font-size('sm');
495
+ font-weight: font-weight('medium');
496
+ line-height: 1.2;
497
+ @include truncate;
498
+ }
507
499
 
508
- &:disabled {
509
- opacity: 0.6;
510
- cursor: not-allowed;
511
- }
500
+ &:hover:not(:disabled) {
501
+ background: var(--mw-primary-background-hover);
502
+ border-color: var(--mw-primary-text-color);
503
+ }
512
504
 
513
- // Icon fallback for projects without initials
514
- > i,
515
- > svg,
516
- > [class*='fa-'] {
517
- display: inline-flex;
518
- align-items: center;
519
- justify-content: center;
520
- width: 32px;
521
- height: 32px;
522
- flex-shrink: 0;
523
- font-size: font-size('xl');
524
- }
505
+ @include focus-ring;
525
506
 
526
- @include media-down('md') {
527
- padding: spacing('0');
528
- width: 40px;
529
- justify-content: center;
530
- border-radius: radius('full');
507
+ &:disabled {
508
+ opacity: 0.6;
509
+ cursor: not-allowed;
510
+ }
531
511
 
532
- .mw-profile-btn-name {
533
- display: none;
512
+ > i,
513
+ > svg,
514
+ > [class*='fa-'] {
515
+ display: inline-flex;
516
+ align-items: center;
517
+ justify-content: center;
518
+ width: 32px;
519
+ height: 32px;
520
+ flex-shrink: 0;
521
+ font-size: font-size('xl');
522
+ }
523
+
524
+ @include media-down('md') {
525
+ padding: spacing('0');
526
+ width: 40px;
527
+ justify-content: center;
528
+ border-radius: radius('full');
529
+
530
+ .mw-profile-btn-name {
531
+ display: none;
532
+ }
534
533
  }
535
534
  }
536
535
  }