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.
Files changed (138) hide show
  1. package/.claude/settings.local.json +29 -1
  2. package/.claude/skills/mw-maverick-wave/SKILL.md +39 -24
  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 +42 -5
  6. package/.claude/skills/mw-maverick-wave/references/forms.md +14 -2
  7. package/.claude/skills/mw-maverick-wave/references/javascript.md +17 -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 +11 -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 +223 -83
  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/home-container.html +10 -20
  40. package/src/partials/input-group-container.html +11 -2
  41. package/src/partials/kbd-container.html +1 -1
  42. package/src/partials/login-container.html +5 -1
  43. package/src/partials/media-container.html +2 -2
  44. package/src/partials/modals-container.html +22 -32
  45. package/src/partials/pricing-container.html +9 -9
  46. package/src/partials/skeleton-container.html +6 -6
  47. package/src/partials/stepper-container.html +2 -2
  48. package/src/partials/tables-container.html +12 -12
  49. package/src/partials/tabs-container.html +17 -27
  50. package/src/partials/tags-container.html +23 -17
  51. package/src/partials/techstack-bucket-container.html +13 -0
  52. package/src/partials/tiles-container.html +26 -9
  53. package/src/partials/typography-container.html +7 -6
  54. package/src/partials/utilities-container.html +35 -15
  55. package/src/scss/_layers.scss +10 -0
  56. package/src/scss/abstracts/_index.scss +6 -0
  57. package/src/scss/abstracts/_mixins.scss +61 -153
  58. package/src/scss/abstracts/_variables.scss +123 -319
  59. package/src/scss/base/_base.scss +170 -190
  60. package/src/scss/base/_reset.scss +106 -104
  61. package/src/scss/base/_typography.scss +153 -151
  62. package/src/scss/components/_accordions.scss +97 -97
  63. package/src/scss/components/_alerts.scss +71 -70
  64. package/src/scss/components/_announcement.scss +71 -70
  65. package/src/scss/components/_avatars.scss +130 -142
  66. package/src/scss/components/_badge.scss +131 -132
  67. package/src/scss/components/_blog-post.scss +223 -220
  68. package/src/scss/components/_breadcrumbs.scss +93 -92
  69. package/src/scss/components/_button-bar.scss +102 -110
  70. package/src/scss/components/_buttons.scss +319 -324
  71. package/src/scss/components/_calendar.scss +251 -252
  72. package/src/scss/components/_cards.scss +359 -386
  73. package/src/scss/components/_code.scss +190 -194
  74. package/src/scss/components/_coming-soon.scss +77 -75
  75. package/src/scss/components/_content-slider.scss +90 -89
  76. package/src/scss/components/_divider.scss +55 -53
  77. package/src/scss/components/_dropdown.scss +179 -185
  78. package/src/scss/components/_empty-state.scss +57 -57
  79. package/src/scss/components/_flag.scss +294 -278
  80. package/src/scss/components/_gallery.scss +131 -133
  81. package/src/scss/components/_info.scss +151 -167
  82. package/src/scss/components/_kanban.scss +332 -341
  83. package/src/scss/components/_kbd.scss +40 -38
  84. package/src/scss/components/_lang-switch.scss +89 -97
  85. package/src/scss/components/_links.scss +21 -28
  86. package/src/scss/components/_lists.scss +510 -514
  87. package/src/scss/components/_localhost-indicator.scss +26 -24
  88. package/src/scss/components/_media.scss +22 -20
  89. package/src/scss/components/_meta-info.scss +35 -33
  90. package/src/scss/components/_modals.scss +277 -186
  91. package/src/scss/components/_pagination.scss +81 -87
  92. package/src/scss/components/_panels.scss +99 -97
  93. package/src/scss/components/_pricing.scss +183 -241
  94. package/src/scss/components/_progress.scss +112 -89
  95. package/src/scss/components/_prose.scss +35 -33
  96. package/src/scss/components/_ratings.scss +40 -38
  97. package/src/scss/components/_segmented.scss +82 -84
  98. package/src/scss/components/_skeleton.scss +66 -72
  99. package/src/scss/components/_spinners.scss +155 -159
  100. package/src/scss/components/_stepper.scss +116 -116
  101. package/src/scss/components/_tables.scss +155 -148
  102. package/src/scss/components/_tabs.scss +232 -141
  103. package/src/scss/components/_tags.scss +109 -107
  104. package/src/scss/components/_techstack-bucket.scss +123 -122
  105. package/src/scss/components/_testimonial.scss +72 -70
  106. package/src/scss/components/_theme-toggle.scss +53 -51
  107. package/src/scss/components/_tiles.scss +174 -174
  108. package/src/scss/components/_timelines.scss +282 -280
  109. package/src/scss/components/_toasts.scss +66 -72
  110. package/src/scss/form-elements/_checkbox.scss +117 -132
  111. package/src/scss/form-elements/_form.scss +149 -115
  112. package/src/scss/form-elements/_input-group.scss +99 -103
  113. package/src/scss/form-elements/_input.scss +74 -74
  114. package/src/scss/form-elements/_login.scss +48 -48
  115. package/src/scss/form-elements/_prefilled.scss +53 -51
  116. package/src/scss/form-elements/_radio.scss +95 -107
  117. package/src/scss/form-elements/_select.scss +42 -42
  118. package/src/scss/form-elements/_slider.scss +117 -132
  119. package/src/scss/form-elements/_textarea.scss +68 -54
  120. package/src/scss/form-elements/_toggle.scss +127 -140
  121. package/src/scss/layout/_footer.scss +172 -171
  122. package/src/scss/layout/_grid.scss +268 -302
  123. package/src/scss/layout/_header.scss +426 -427
  124. package/src/scss/layout/_home.scss +28 -27
  125. package/src/scss/layout/_main.scss +275 -238
  126. package/src/scss/layout/_page-header.scss +38 -36
  127. package/src/scss/layout/_section.scss +150 -124
  128. package/src/scss/main.scss +1 -1
  129. package/src/scss/utilities/_accessibility.scss +46 -45
  130. package/src/scss/utilities/_aspect.scss +22 -20
  131. package/src/scss/utilities/_corner.scss +23 -5
  132. package/src/scss/utilities/_display.scss +76 -70
  133. package/src/scss/utilities/_elevation.scss +13 -11
  134. package/src/scss/utilities/_flex.scss +83 -85
  135. package/src/scss/utilities/_reveal.scss +40 -63
  136. package/src/scss/utilities/_spacing.scss +63 -64
  137. package/src/scss/utilities/_text.scss +139 -141
  138. package/src/scss/utilities/_touch-targets.scss +130 -147
@@ -1,381 +1,347 @@
1
+ @use 'sass:list';
2
+ @use 'sass:map';
1
3
  @use '../abstracts' as *;
2
4
 
3
- // Base grid styles that apply to all grid types
4
- %grid-base {
5
- display: grid;
6
- gap: spacing('6');
7
- }
8
-
9
- %grid-base-lg {
10
- display: grid;
11
- gap: spacing('9');
12
- }
13
-
14
- // The scroll-reveal stagger, made to follow the columns. mw-reveal-stagger
15
- // (utilities/_reveal.scss) shifts the entrance of the second and third child of
16
- // every three - right for a row of three, but in a mw-grid-4 the fourth card
17
- // would start over with the first. The grid knows its column count at every
18
- // breakpoint, so it restates the cycle to match: included once per column
19
- // count, right next to the grid-template-columns it belongs to. Only the range
20
- // is set here, through the shared `reveal-range` mixin - the animation and its
21
- // guards stay in _reveal.scss, and a child without the animation ignores the
22
- // range. The :nth-child(n) reset carries the
23
- // same specificity as the cycle rules, so a narrower breakpoint can override
24
- // the wider one's cycle for every child.
25
- @mixin _reveal-stagger($cols) {
26
- &.mw-reveal-stagger > :nth-child(n) {
27
- @include reveal-range(1);
5
+ // How every column grid steps up, as data: one column is the base, each entry
6
+ // adds a breakpoint above it as (breakpoint, columns, gap), and `null` means that
7
+ // step leaves the one it stands for alone. Ascending order, because they are
8
+ // emitted in it and a wider step has to override a narrower one.
9
+ //
10
+ // Outside the layer blocks below, because both read it - the columns are emitted
11
+ // in `mw.layout`, the reveal cycle in `mw.utilities`, and a Sass variable declared
12
+ // inside an `@layer` block is local to it.
13
+ $_column-steps: (
14
+ 2: (
15
+ ('sm', 2, null),
16
+ ),
17
+ 3: (
18
+ ('sm', 2, null),
19
+ ('md', 3, null),
20
+ ),
21
+ 4: (
22
+ ('sm', 2, null),
23
+ ('lg', 4, null),
24
+ ),
25
+ 5: (
26
+ ('xs', 2, null),
27
+ ('sm', 3, null),
28
+ ('md', 4, null),
29
+ ('lg', 5, null),
30
+ ),
31
+ );
32
+
33
+ $_column-steps-lg: (
34
+ 2: (
35
+ ('sm', 2, '9'),
36
+ ),
37
+ 3: (
38
+ ('sm', 2, '7'),
39
+ ('lg', 3, '9'),
40
+ ),
41
+ 4: (
42
+ ('sm', 2, '7'),
43
+ ('md', null, '9'),
44
+ ('xl', 4, null),
45
+ ),
46
+ 5: (
47
+ ('sm', 2, '7'),
48
+ ('md', 3, '9'),
49
+ ('lg', 4, null),
50
+ ('xl', 5, null),
51
+ ),
52
+ );
53
+
54
+ @layer mw.layout {
55
+ %grid-base {
56
+ display: grid;
57
+ gap: spacing('6');
28
58
  }
29
59
 
30
- // Guarded: Sass counts `from 2 through 1` downwards and would emit a rule
31
- // for a second column that a single-column grid does not have.
32
- @if $cols > 1 {
33
- @for $i from 2 through $cols {
34
- &.mw-reveal-stagger > :nth-child(#{$cols}n + #{$i}) {
35
- @include reveal-range($i);
36
- }
37
- }
60
+ %grid-base-lg {
61
+ display: grid;
62
+ gap: spacing('9');
38
63
  }
39
- }
40
-
41
- .mw-grid {
42
- @extend %grid-base;
43
- }
44
-
45
- .mw-grid-1 {
46
- @extend %grid-base;
47
- grid-template-columns: minmax(0, 1fr);
48
64
 
49
- justify-items: stretch;
50
- > * {
51
- width: 100% !important;
52
- max-width: none !important;
65
+ @mixin _columns($count) {
66
+ grid-template-columns: repeat($count, minmax(0, 1fr));
53
67
  }
54
- }
55
-
56
- .mw-grid-2 {
57
- @extend %grid-base;
58
- grid-template-columns: repeat(2, minmax(0, 1fr));
59
- @include _reveal-stagger(2);
60
68
 
61
- @include media-down('sm') {
69
+ @mixin _single-column {
62
70
  grid-template-columns: minmax(0, 1fr);
63
- @include _reveal-stagger(1);
64
71
  }
65
- }
66
72
 
67
- .mw-grid-3 {
68
- @extend %grid-base;
69
- grid-template-columns: repeat(3, minmax(0, 1fr));
70
- @include _reveal-stagger(3);
73
+ // $base-gap is for the -lg ramp, whose placeholder carries the desktop gap and
74
+ // has to come back down to the default air on a phone
75
+ @mixin _column-grid($steps, $base-gap: null) {
76
+ @include _single-column;
77
+ @if $base-gap {
78
+ gap: spacing($base-gap);
79
+ }
71
80
 
72
- @include media-down('md') {
73
- grid-template-columns: repeat(2, minmax(0, 1fr));
74
- @include _reveal-stagger(2);
81
+ @each $breakpoint, $cols, $gap in $steps {
82
+ @include media-up($breakpoint) {
83
+ @if $cols {
84
+ @include _columns($cols);
85
+ }
86
+ @if $gap {
87
+ gap: spacing($gap);
88
+ }
89
+ }
90
+ }
75
91
  }
76
92
 
77
- @include media-down('sm') {
78
- grid-template-columns: minmax(0, 1fr);
79
- @include _reveal-stagger(1);
93
+ // The child reset a full-width single column needs: a card that carries its own
94
+ // max-width would otherwise sit narrow in a column built to hold it.
95
+ @mixin _stretch-children {
96
+ justify-items: stretch;
97
+
98
+ > * {
99
+ width: 100% !important;
100
+ max-width: none !important;
101
+ }
80
102
  }
81
- }
82
103
 
83
- .mw-grid-4 {
84
- @extend %grid-base;
85
- grid-template-columns: repeat(4, minmax(0, 1fr));
86
- @include _reveal-stagger(4);
104
+ .mw-grid {
105
+ @extend %grid-base;
106
+ }
87
107
 
88
- @include media-down('lg') {
89
- grid-template-columns: repeat(2, minmax(0, 1fr));
90
- @include _reveal-stagger(2);
108
+ .mw-grid-1 {
109
+ @extend %grid-base;
110
+ @include _single-column;
111
+ @include _stretch-children;
91
112
  }
92
113
 
93
- @include media-down('sm') {
94
- grid-template-columns: minmax(0, 1fr);
95
- @include _reveal-stagger(1);
114
+ @each $count, $steps in $_column-steps {
115
+ .mw-grid-#{$count} {
116
+ @extend %grid-base;
117
+ @include _column-grid($steps);
118
+ }
96
119
  }
97
- }
98
120
 
99
- .mw-grid-5 {
100
- @extend %grid-base;
101
- grid-template-columns: repeat(5, minmax(0, 1fr));
102
- @include _reveal-stagger(5);
121
+ .mw-grid-flex {
122
+ @extend %grid-base;
103
123
 
104
- @include media-down('lg') {
105
- grid-template-columns: repeat(4, minmax(0, 1fr));
106
- @include _reveal-stagger(4);
107
- }
124
+ @include _columns(12);
108
125
 
109
- @include media-down('md') {
110
- grid-template-columns: repeat(3, minmax(0, 1fr));
111
- @include _reveal-stagger(3);
112
- }
126
+ @include media-down('md') {
127
+ @include _single-column;
113
128
 
114
- @include media-down('sm') {
115
- grid-template-columns: repeat(2, minmax(0, 1fr));
116
- @include _reveal-stagger(2);
129
+ > * {
130
+ grid-column: 1 / -1 !important;
131
+ }
132
+ }
117
133
  }
118
134
 
119
- @include media-down('xs') {
120
- grid-template-columns: minmax(0, 1fr);
121
- @include _reveal-stagger(1);
135
+ @for $i from 1 through 12 {
136
+ .mw-col-span-#{$i} {
137
+ grid-column: span #{$i};
138
+ }
122
139
  }
123
- }
124
-
125
- // flexible grid system with column spans
126
- .mw-grid-flex {
127
- @extend %grid-base;
128
140
 
129
- // Default: 12-column grid (you can adjust this base)
130
- grid-template-columns: repeat(12, minmax(0, 1fr));
131
-
132
- // At MD breakpoint and below, force single column
133
- @include media-down('md') {
134
- grid-template-columns: minmax(0, 1fr);
141
+ .mw-grid-auto {
142
+ @extend %grid-base;
143
+ grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
135
144
 
136
- // Reset all spans to full width
137
145
  > * {
138
- grid-column: 1 / -1 !important;
146
+ width: auto !important;
147
+ max-width: none !important;
148
+ min-width: 0;
139
149
  }
140
150
  }
141
- }
142
151
 
143
- // Column span utilities
144
- @for $i from 1 through 12 {
145
- .mw-col-span-#{$i} {
146
- grid-column: span #{$i};
152
+ .mw-grid-auto-sm {
153
+ @extend %grid-base;
154
+ grid-template-columns: repeat(auto-fill, minmax(min(250px, 100%), 1fr));
147
155
  }
148
- }
149
-
150
- // Responsive auto grid
151
- .mw-grid-auto {
152
- @extend %grid-base;
153
- grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
154
156
 
155
- // Ensure children don't override the grid behavior
156
- > * {
157
- width: auto !important;
158
- max-width: none !important;
159
- min-width: 0;
157
+ .mw-grid-auto-md {
158
+ @extend %grid-base;
159
+ grid-template-columns: repeat(auto-fill, minmax(min(350px, 100%), 1fr));
160
160
  }
161
- }
162
-
163
- // Alternative with different minimum widths
164
- .mw-grid-auto-sm {
165
- @extend %grid-base;
166
- grid-template-columns: repeat(auto-fill, minmax(min(250px, 100%), 1fr));
167
- }
168
-
169
- .mw-grid-auto-md {
170
- @extend %grid-base;
171
- grid-template-columns: repeat(auto-fill, minmax(min(350px, 100%), 1fr));
172
- }
173
-
174
- .mw-grid-lg {
175
- @extend %grid-base-lg;
176
- }
177
161
 
178
- .mw-grid-1-lg {
179
- @extend %grid-base-lg;
180
- grid-template-columns: minmax(0, 1fr);
181
- justify-items: stretch;
182
- > * {
183
- width: 100% !important;
184
- max-width: none !important;
162
+ .mw-grid-lg {
163
+ @extend %grid-base-lg;
185
164
  }
186
- }
187
165
 
188
- .mw-grid-2-lg {
189
- @extend %grid-base-lg;
190
- grid-template-columns: repeat(2, minmax(0, 1fr));
191
- @include _reveal-stagger(2);
192
- @include media-down('sm') {
193
- grid-template-columns: minmax(0, 1fr);
194
- @include _reveal-stagger(1);
195
- gap: spacing('6');
166
+ .mw-grid-1-lg {
167
+ @extend %grid-base-lg;
168
+ @include _single-column;
169
+ @include _stretch-children;
196
170
  }
197
- }
198
171
 
199
- .mw-grid-3-lg {
200
- @extend %grid-base-lg;
201
- grid-template-columns: repeat(3, minmax(0, 1fr));
202
- @include _reveal-stagger(3);
203
- @include media-down('lg') {
204
- grid-template-columns: repeat(2, minmax(0, 1fr));
205
- @include _reveal-stagger(2);
206
- gap: spacing('7');
207
- }
208
- @include media-down('sm') {
209
- grid-template-columns: minmax(0, 1fr);
210
- @include _reveal-stagger(1);
211
- gap: spacing('6');
172
+ @each $count, $steps in $_column-steps-lg {
173
+ .mw-grid-#{$count}-lg {
174
+ @extend %grid-base-lg;
175
+ // A phone gets the same air between cards whichever ramp is used; the -lg
176
+ // in the name is about the desktop end of it.
177
+ @include _column-grid($steps, '6');
178
+ }
212
179
  }
213
- }
214
180
 
215
- .mw-grid-4-lg {
216
- @extend %grid-base-lg;
217
- grid-template-columns: repeat(4, minmax(0, 1fr));
218
- @include _reveal-stagger(4);
219
- @include media-down('xl') {
220
- grid-template-columns: repeat(2, minmax(0, 1fr));
221
- @include _reveal-stagger(2);
181
+ .mw-grid-auto-lg {
182
+ @extend %grid-base-lg;
183
+ grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
222
184
  }
223
- @include media-down('md') {
224
- gap: spacing('7');
225
- }
226
- @include media-down('sm') {
227
- grid-template-columns: minmax(0, 1fr);
228
- @include _reveal-stagger(1);
229
- gap: spacing('6');
230
- }
231
- }
232
185
 
233
- .mw-grid-5-lg {
234
- @extend %grid-base-lg;
235
- grid-template-columns: repeat(5, minmax(0, 1fr));
236
- @include _reveal-stagger(5);
237
- @include media-down('xl') {
238
- grid-template-columns: repeat(4, minmax(0, 1fr));
239
- @include _reveal-stagger(4);
240
- }
241
- @include media-down('lg') {
242
- grid-template-columns: repeat(3, minmax(0, 1fr));
243
- @include _reveal-stagger(3);
244
- }
245
- @include media-down('md') {
246
- grid-template-columns: repeat(2, minmax(0, 1fr));
247
- @include _reveal-stagger(2);
248
- gap: spacing('7');
249
- }
250
- @include media-down('sm') {
251
- grid-template-columns: minmax(0, 1fr);
252
- @include _reveal-stagger(1);
253
- gap: spacing('6');
254
- }
255
- }
186
+ .mw-grid-flex-lg {
187
+ @extend %grid-base-lg;
188
+ @include _columns(12);
256
189
 
257
- .mw-grid-auto-lg {
258
- @extend %grid-base-lg;
259
- grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
260
- }
190
+ @include media-down('md') {
191
+ @include _single-column;
192
+ gap: spacing('5');
193
+ > * {
194
+ grid-column: 1 / -1 !important;
195
+ }
196
+ }
197
+ }
261
198
 
262
- // Flexible grids with large spacing
263
- .mw-grid-flex-lg {
264
- @extend %grid-base-lg;
265
- grid-template-columns: repeat(12, minmax(0, 1fr));
199
+ // For cards of unequal height, where a row grid tears a gap under every short
200
+ // one. break-inside keeps each child whole. Caveat: columns read top to bottom
201
+ // then across, so anything ranked or chronological stays in a grid.
202
+ %columns-base {
203
+ column-gap: spacing('6');
266
204
 
267
- @include media-down('md') {
268
- grid-template-columns: minmax(0, 1fr);
269
- gap: spacing('5');
270
205
  > * {
271
- grid-column: 1 / -1 !important;
206
+ break-inside: avoid;
207
+ margin-bottom: spacing('6');
272
208
  }
273
209
  }
274
- }
275
210
 
276
- // Masonry columns - for cards of unequal height, where a row grid tears a gap
277
- // under every short one. CSS multi-column instead: entries flow into columns
278
- // and close up, the column count steps down with the viewport. break-inside
279
- // keeps each child whole - without it a page break lands mid-card.
280
- //
281
- // Reading order caveat: columns read top to bottom, then across. Right for
282
- // testimonials and galleries, wrong for anything ranked or chronological -
283
- // that stays in a grid.
284
- %columns-base {
285
- column-gap: spacing('6');
286
-
287
- > * {
288
- break-inside: avoid;
289
- margin-bottom: spacing('6');
290
- }
291
- }
211
+ .mw-columns-2 {
212
+ @extend %columns-base;
213
+ columns: 1;
292
214
 
293
- .mw-columns-2 {
294
- @extend %columns-base;
295
- columns: 2;
215
+ @include media-up('sm') {
216
+ columns: 2;
217
+ }
218
+ }
296
219
 
297
- @include media-down('sm') {
220
+ .mw-columns-3 {
221
+ @extend %columns-base;
298
222
  columns: 1;
299
- }
300
- }
301
223
 
302
- .mw-columns-3 {
303
- @extend %columns-base;
304
- columns: 3;
224
+ @include media-up('sm') {
225
+ columns: 2;
226
+ }
305
227
 
306
- @include media-down('lg') {
307
- columns: 2;
228
+ @include media-up('lg') {
229
+ columns: 3;
230
+ }
308
231
  }
309
232
 
310
- @include media-down('sm') {
311
- columns: 1;
233
+ // The stack variants: one column, and the difference is only where the items
234
+ // sit in it and whether they keep their natural width. `justify-items` plus the
235
+ // matching child reset, which is the whole of what separates the four.
236
+ $_stack-alignments: (
237
+ '': (
238
+ start,
239
+ auto,
240
+ ),
241
+ '-center': (
242
+ center,
243
+ null,
244
+ ),
245
+ '-end': (
246
+ end,
247
+ auto,
248
+ ),
249
+ '-stretch': (
250
+ stretch,
251
+ 100%,
252
+ ),
253
+ );
254
+
255
+ @mixin _stack($justify, $child-width) {
256
+ @include _single-column;
257
+ justify-items: $justify;
258
+
259
+ > * {
260
+ @if $child-width {
261
+ width: $child-width;
262
+ }
263
+ max-width: none;
264
+ }
312
265
  }
313
- }
314
266
 
315
- // Base stack - items keep their natural width
316
- .mw-grid-stack {
317
- @extend %grid-base;
318
- grid-template-columns: minmax(0, 1fr);
319
- justify-items: start; // Items keep natural width, aligned left
267
+ @each $suffix, $spec in $_stack-alignments {
268
+ $justify: list.nth($spec, 1);
269
+ $child-width: list.nth($spec, 2);
320
270
 
321
- // Remove the forced width from grid-1
322
- > * {
323
- width: auto;
324
- max-width: none;
271
+ .mw-grid-stack#{$suffix} {
272
+ @extend %grid-base;
273
+ @include _stack($justify, $child-width);
274
+ }
325
275
  }
326
- }
327
276
 
328
- // Stack variants with different alignments
329
- .mw-grid-stack-center {
330
- @extend %grid-base;
331
- grid-template-columns: minmax(0, 1fr);
332
- justify-items: center;
277
+ // Large spacing variants - only the two that were ever written out
278
+ @each $suffix in ('', '-center') {
279
+ $spec: map.get($_stack-alignments, $suffix);
333
280
 
334
- > * {
335
- max-width: none;
281
+ .mw-grid-stack#{$suffix}-lg {
282
+ @extend %grid-base-lg;
283
+ @include _stack(list.nth($spec, 1), list.nth($spec, 2));
284
+ }
336
285
  }
337
- }
338
-
339
- .mw-grid-stack-end {
340
- @extend %grid-base;
341
- grid-template-columns: minmax(0, 1fr);
342
- justify-items: end;
343
286
 
344
- > * {
345
- width: auto;
346
- max-width: none;
287
+ // A feature card grows outwards - its frame and its label bar reach into the
288
+ // gap, and two rows of them would touch. The card asks for the room, but the
289
+ // grid has to hand it over: written next to the card it would sit in
290
+ // `mw.components` and lose to every gap above, no matter how specific.
291
+ [class*='mw-grid-']:has(> .mw-card-feature) {
292
+ row-gap: 48px;
347
293
  }
348
294
  }
349
295
 
350
- .mw-grid-stack-stretch {
351
- @extend %grid-base;
352
- grid-template-columns: minmax(0, 1fr);
353
- justify-items: stretch;
296
+ // The reveal cycle restated per column count, because the fallback in
297
+ // _reveal.scss shifts every third child and a mw-grid-4 would start its fourth
298
+ // card over with the first. Only the range is set here.
299
+ //
300
+ // In `mw.utilities` and not next to the columns, because that is where the
301
+ // fallback it has to beat lives - specificity is no help across layers.
302
+ @layer mw.utilities {
303
+ // The `:nth-child(n)` reset carries the same specificity as the cycle rules,
304
+ // so a narrower breakpoint can override the wider one's cycle for every child.
305
+ @mixin _reveal-stagger($cols) {
306
+ &.mw-reveal-stagger > :nth-child(n) {
307
+ @include reveal-range(1);
308
+ }
354
309
 
355
- > * {
356
- width: 100%;
357
- max-width: none;
310
+ // Guarded: Sass counts `from 2 through 1` downwards and would emit a rule
311
+ // for a second column that a single-column grid does not have.
312
+ @if $cols > 1 {
313
+ @for $i from 2 through $cols {
314
+ &.mw-reveal-stagger > :nth-child(#{$cols}n + #{$i}) {
315
+ @include reveal-range($i);
316
+ }
317
+ }
318
+ }
358
319
  }
359
- }
360
320
 
361
- // Large spacing variants
362
- .mw-grid-stack-lg {
363
- @extend %grid-base-lg;
364
- grid-template-columns: minmax(0, 1fr);
365
- justify-items: start;
321
+ // One column on a phone, then the same steps the columns take. The gap each
322
+ // entry carries is not read here: a step that only widens the gap leaves the
323
+ // cycle alone.
324
+ @mixin _reveal-ramp($steps) {
325
+ @include _reveal-stagger(1);
366
326
 
367
- > * {
368
- width: auto;
369
- max-width: none;
327
+ @each $breakpoint, $cols in $steps {
328
+ @if $cols {
329
+ @include media-up($breakpoint) {
330
+ @include _reveal-stagger($cols);
331
+ }
332
+ }
333
+ }
370
334
  }
371
- }
372
335
 
373
- .mw-grid-stack-center-lg {
374
- @extend %grid-base-lg;
375
- grid-template-columns: minmax(0, 1fr);
376
- justify-items: center;
336
+ @each $count, $steps in $_column-steps {
337
+ .mw-grid-#{$count} {
338
+ @include _reveal-ramp($steps);
339
+ }
340
+ }
377
341
 
378
- > * {
379
- max-width: none;
342
+ @each $count, $steps in $_column-steps-lg {
343
+ .mw-grid-#{$count}-lg {
344
+ @include _reveal-ramp($steps);
345
+ }
380
346
  }
381
347
  }