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,48 +1,50 @@
1
1
  @use '../abstracts' as *;
2
2
 
3
- .mw-page-header {
4
- display: flex;
5
- flex-wrap: wrap;
6
- align-items: flex-start;
7
- justify-content: space-between;
8
- gap: spacing('4');
9
- margin-bottom: spacing('6');
10
- padding-bottom: spacing('4');
11
- border-bottom: 1px solid var(--mw-border);
12
-
13
- h1,
14
- h2,
15
- h3 {
16
- margin: spacing('0');
17
- font-size: font-size('2xl');
18
- line-height: 1.2;
3
+ @layer mw.layout {
4
+ .mw-page-header {
5
+ display: flex;
6
+ flex-wrap: wrap;
7
+ align-items: flex-start;
8
+ justify-content: space-between;
9
+ gap: spacing('4');
10
+ margin-bottom: spacing('6');
11
+ padding-bottom: spacing('4');
12
+ border-bottom: 1px solid var(--mw-border);
19
13
 
20
- @include media-down('sm') {
14
+ h1,
15
+ h2,
16
+ h3 {
17
+ margin: spacing('0');
21
18
  font-size: font-size('xl');
19
+ line-height: 1.2;
20
+
21
+ @include media-up('sm') {
22
+ font-size: font-size('2xl');
23
+ }
22
24
  }
23
- }
24
25
 
25
- p {
26
- margin: spacing('1') spacing('0') spacing('0') spacing('0');
27
- color: var(--mw-text-muted-color);
28
- font-size: font-size('sm');
29
- }
26
+ p {
27
+ margin: spacing('1') spacing('0') spacing('0') spacing('0');
28
+ color: var(--mw-text-muted-color);
29
+ font-size: font-size('sm');
30
+ }
30
31
 
31
- &-actions {
32
- display: flex;
33
- flex-wrap: wrap;
34
- align-items: center;
35
- gap: spacing('3');
36
- margin-left: auto;
32
+ &-actions {
33
+ display: flex;
34
+ flex-wrap: wrap;
35
+ align-items: center;
36
+ gap: spacing('3');
37
+ margin-left: auto;
37
38
 
38
- @include media-down('sm') {
39
- width: 100%;
40
- margin-left: spacing('0');
39
+ @include media-down('sm') {
40
+ width: 100%;
41
+ margin-left: spacing('0');
42
+ }
41
43
  }
42
- }
43
44
 
44
- &-plain {
45
- padding-bottom: spacing('0');
46
- border-bottom: none;
45
+ &-plain {
46
+ padding-bottom: spacing('0');
47
+ border-bottom: none;
48
+ }
47
49
  }
48
50
  }
@@ -1,150 +1,176 @@
1
1
  @use '../abstracts' as *;
2
2
 
3
- .mw-section-title {
4
- font-size: font-size('3xl');
5
- margin-bottom: var(--mw-section-title-gap);
6
- text-align: center;
7
- position: relative;
8
-
9
- &::after {
10
- content: '';
11
- position: absolute;
12
- bottom: spacing('-3');
13
- left: 50%;
14
- transform: translateX(-50%);
15
- width: 80px;
16
- height: 5px;
17
- background: var(--mw-primary-text-color);
3
+ @layer mw.layout {
4
+ // The rule under a section heading. Shared, so the two levels cannot drift
5
+ // apart in width and weight - the subtitle carried the wider mark, which reads
6
+ // as the louder one under the smaller heading. Colour is where they do part.
7
+ @mixin _section-rule(
8
+ $width,
9
+ $height,
10
+ $offset,
11
+ $color: var(--mw-primary-text-color)
12
+ ) {
13
+ &::after {
14
+ content: '';
15
+ position: absolute;
16
+ bottom: $offset;
17
+ left: 50%;
18
+ transform: translateX(-50%);
19
+ width: $width;
20
+ height: $height;
21
+ border-radius: radius('xs');
22
+ background: $color;
23
+ }
18
24
  }
19
25
 
20
- @include media-down('sm') {
26
+ .mw-section-title {
21
27
  font-size: font-size('2xl');
22
- }
23
- }
28
+ margin-bottom: var(--mw-section-title-gap);
29
+ text-align: center;
30
+ position: relative;
24
31
 
25
- // The lead line under a section title. Every landing page writes this
26
- // paragraph, and it always wants the same four things: centred, muted,
27
- // narrower than the container so it reads as a line rather than a block, and
28
- // pulled up toward the title it belongs to - the title's gap is sized for the
29
- // content below, not for its own subtitle.
30
- .mw-section-intro {
31
- max-width: 46rem;
32
- margin: spacing('-3') auto spacing('9');
33
- font-size: font-size('md');
34
- color: var(--mw-text-muted-color);
35
- text-align: center;
36
- text-wrap: balance;
37
- }
32
+ @include _section-rule(56px, 3px, spacing('-3'));
38
33
 
39
- .mw-section-subtitle {
40
- font-size: font-size('2xl');
41
- margin: spacing('8') spacing('0') spacing('6') spacing('0');
42
- text-align: center;
43
- position: relative;
44
-
45
- &::after {
46
- content: '';
47
- position: absolute;
48
- bottom: spacing('-2');
49
- left: 50%;
50
- transform: translateX(-50%);
51
- width: 100px;
52
- height: 2px;
53
- background: var(--mw-secondary-text-color);
34
+ @include media-up('sm') {
35
+ font-size: font-size('3xl');
36
+ }
54
37
  }
55
38
 
56
- @include media-down('sm') {
57
- font-size: font-size('xl');
39
+ // The lead line under a section title. Every landing page writes this
40
+ // paragraph, and it always wants the same four things: centred, muted,
41
+ // narrower than the container so it reads as a line rather than a block, and
42
+ // pulled up toward the title it belongs to - the title's gap is sized for the
43
+ // content below, not for its own subtitle.
44
+ .mw-section-intro {
45
+ max-width: 46rem;
46
+ margin: spacing('-3') auto spacing('9');
47
+ font-size: font-size('md');
48
+ color: var(--mw-text-muted-color);
49
+ text-align: center;
50
+ text-wrap: balance;
58
51
  }
59
- }
60
52
 
61
- .mw-section-nav {
62
- max-width: 100%;
63
- margin: spacing('0') auto spacing('0') auto;
64
- display: flex;
65
- flex-wrap: wrap;
66
- justify-content: center;
67
- gap: spacing('3');
68
- }
53
+ .mw-section-subtitle {
54
+ font-size: font-size('xl');
55
+ // The step above a demo gap of spacing('6') - at spacing('8') the boundary
56
+ // between two components read like the one between two demos
57
+ margin: spacing('10') spacing('0') spacing('6') spacing('0');
58
+ text-align: center;
59
+ position: relative;
69
60
 
70
- .mw-section-btn {
71
- display: inline-flex;
72
- align-items: center;
73
- justify-content: center;
74
- gap: spacing('3');
75
- padding: spacing('3') spacing('4');
76
- border: 1px solid var(--mw-primary-text-color);
77
- border-radius: radius('sm');
78
- font-weight: font-weight('medium');
79
- font-size: inherit;
80
- font-family: inherit;
81
- text-decoration: none;
82
- cursor: pointer;
83
- transition: var(--mw-transition);
84
- box-sizing: border-box;
85
- background: transparent;
86
- color: var(--mw-primary-text-color);
87
-
88
- &:hover:not(:disabled) {
89
- background: var(--mw-primary-color);
90
- color: var(--mw-primary-accent-text-color);
91
- }
61
+ @include _section-rule(
62
+ 32px,
63
+ 2px,
64
+ spacing('-2'),
65
+ var(--mw-secondary-text-color)
66
+ );
92
67
 
93
- &:active:not(:disabled) {
94
- transform: translateY(1px);
95
- transition-duration: var(--mw-duration-instant);
68
+ @include media-up('sm') {
69
+ font-size: font-size('2xl');
70
+ }
96
71
  }
97
72
 
98
- @include focus-ring;
99
- @include tappable;
100
-
101
- &:disabled {
102
- cursor: not-allowed;
103
- opacity: 0.6;
104
- }
105
- }
106
-
107
- // Responsive adjustments
108
- @include media-down('sm') {
73
+ // Sticky, because the strip is the only way back: inside a long section the
74
+ // nav at the entrance can be twenty thousand pixels behind the reader
109
75
  .mw-section-nav {
110
- flex-direction: column;
76
+ position: sticky;
77
+ top: var(--mw-header-height);
78
+ z-index: z-index('menu');
111
79
  width: 100%;
112
- max-width: 300px;
113
- margin-left: auto;
114
- margin-right: auto;
80
+ padding-block: spacing('3');
81
+ display: flex;
82
+ flex-wrap: nowrap;
83
+ justify-content: center;
84
+ // A long strip aligns to its start instead of centring both ends out of reach
85
+ justify-content: safe center;
86
+ gap: spacing('3');
87
+ overflow-x: auto;
88
+ overscroll-behavior-x: contain;
89
+ // Opaque and unblurred - the strip repaints on every scroll frame, and the
90
+ // alternate sections build their pattern on this same colour anyway
91
+ background: var(--mw-page-background);
92
+
93
+ @include scrollbar;
94
+ }
95
+
96
+ // The strip parks under the header, so a jump to a component clears both
97
+ .mw-container > div:has(> .mw-section-subtitle) {
98
+ scroll-margin-top: calc(
99
+ var(--mw-header-height) + var(--mw-section-nav-height) + #{spacing('5')}
100
+ );
115
101
  }
116
102
 
117
103
  .mw-section-btn {
118
- width: 100%;
119
- text-align: center;
104
+ display: inline-flex;
105
+ align-items: center;
106
+ justify-content: center;
107
+ // No shrinking in a row that scrolls rather than wraps
108
+ flex: 0 0 auto;
109
+ gap: spacing('3');
110
+ padding: spacing('3') spacing('4');
111
+ border: 1px solid var(--mw-primary-text-color);
112
+ border-radius: radius('sm');
113
+ font-weight: font-weight('medium');
114
+ font-size: inherit;
115
+ font-family: inherit;
116
+ text-decoration: none;
117
+ cursor: pointer;
118
+ transition: var(--mw-transition);
119
+ box-sizing: border-box;
120
+ background: transparent;
121
+ color: var(--mw-primary-text-color);
122
+
123
+ &:hover:not(:disabled) {
124
+ background: var(--mw-primary-color);
125
+ color: var(--mw-primary-accent-text-color);
126
+ }
127
+
128
+ &:active:not(:disabled) {
129
+ transform: translateY(1px);
130
+ transition-duration: var(--mw-duration-instant);
131
+ }
132
+
133
+ @include focus-ring;
134
+ @include tappable;
135
+
136
+ &:disabled {
137
+ cursor: not-allowed;
138
+ opacity: 0.6;
139
+ }
120
140
  }
121
- }
122
141
 
123
- // Additional spacing for the whole section
124
- .mw-section {
125
- padding: var(--mw-section-padding-block) spacing('0');
126
- position: relative;
127
-
128
- // ...except around a hero. The hero container is already 100dvh, so the
129
- // padding pushes exactly that much of it past the bottom of the screen -
130
- // and with it the scroll cue sitting on its lower edge. A hero is the full
131
- // screen by definition and brings its own breathing room.
132
- @supports (selector(:has(.mw-hero))) {
133
- &:has(.mw-hero) {
134
- padding-block: spacing('0');
142
+ @include media-down('sm') {
143
+ // The section boundary steps down to 56px on a phone, so the component
144
+ // boundary steps with it or the two stop being distinguishable
145
+ .mw-section-subtitle {
146
+ margin-top: spacing('7');
135
147
  }
136
148
  }
137
- }
138
149
 
139
- // Pattern variant for sections
140
- .mw-section-alternate {
141
- position: relative;
142
- --s: 5px; // size
143
- --c1: var(--mw-page-background);
144
- --c2: var(--mw-section-alternate-pattern);
145
- --g: var(--c2) -5% 5%, var(--c1) 0 45%;
146
- background:
147
- linear-gradient(0deg, #0000 10%, var(--c1) 0 40%, #0000 0),
148
- repeating-linear-gradient(-45deg, var(--g)) var(--c1);
149
- background-size: var(--s) var(--s);
150
+ .mw-section {
151
+ padding: var(--mw-section-padding-block) spacing('0');
152
+ position: relative;
153
+
154
+ // ...except around a hero. The hero container is already 100dvh, so the
155
+ // padding pushes exactly that much of it past the bottom of the screen -
156
+ // and with it the scroll cue sitting on its lower edge. A hero is the full
157
+ // screen by definition and brings its own breathing room.
158
+ @supports (selector(:has(.mw-hero))) {
159
+ &:has(.mw-hero) {
160
+ padding-block: spacing('0');
161
+ }
162
+ }
163
+ }
164
+
165
+ .mw-section-alternate {
166
+ position: relative;
167
+ --s: 5px;
168
+ --c1: var(--mw-page-background);
169
+ --c2: var(--mw-section-alternate-pattern);
170
+ --g: var(--c2) -5% 5%, var(--c1) 0 45%;
171
+ background:
172
+ linear-gradient(0deg, #0000 10%, var(--c1) 0 40%, #0000 0),
173
+ repeating-linear-gradient(-45deg, var(--g)) var(--c1);
174
+ background-size: var(--s) var(--s);
175
+ }
150
176
  }
@@ -3,7 +3,7 @@
3
3
  @forward 'abstracts/variables';
4
4
 
5
5
  @use 'base';
6
+ @use 'layout';
6
7
  @use 'components';
7
8
  @use 'form-elements';
8
- @use 'layout';
9
9
  @use 'utilities';
@@ -1,52 +1,53 @@
1
1
  @use '../abstracts' as *;
2
2
 
3
- // Visible to screen readers only
4
- .mw-sr-only {
5
- position: absolute;
6
- width: 1px;
7
- height: 1px;
8
- padding: 0;
9
- margin: -1px;
10
- overflow: hidden;
11
- clip-path: inset(50%);
12
- white-space: nowrap;
13
- border: 0;
14
- }
3
+ @layer mw.utilities {
4
+ .mw-sr-only {
5
+ position: absolute;
6
+ width: 1px;
7
+ height: 1px;
8
+ padding: 0;
9
+ margin: -1px;
10
+ overflow: hidden;
11
+ clip-path: inset(50%);
12
+ white-space: nowrap;
13
+ border: 0;
14
+ }
15
15
 
16
- // The first thing a keyboard user meets on the page: a link that jumps past the
17
- // header and the navigation straight to the content. Off-screen until focused,
18
- // which is why it can be the first element in the body without being seen.
19
- //
20
- // <a class="mw-skip-link" href="#main">Skip to content</a>
21
- .mw-skip-link {
22
- position: absolute;
23
- left: spacing('3');
24
- top: spacing('3');
25
- z-index: z-index('alert');
26
- padding: spacing('3') spacing('5');
27
- border-radius: radius('sm');
28
- background: var(--mw-primary-color);
29
- color: var(--mw-primary-accent-text-color);
30
- font-weight: font-weight('medium');
31
- box-shadow: var(--mw-elevation-3);
32
- transform: translateY(calc(-100% - #{spacing('5')}));
33
- transition: transform var(--mw-duration-fast) var(--mw-ease-out);
16
+ // The first thing a keyboard user meets on the page: a link that jumps past the
17
+ // header and the navigation straight to the content. Off-screen until focused,
18
+ // which is why it can be the first element in the body without being seen.
19
+ //
20
+ // <a class="mw-skip-link" href="#main">Skip to content</a>
21
+ .mw-skip-link {
22
+ position: absolute;
23
+ left: spacing('3');
24
+ top: spacing('3');
25
+ z-index: z-index('alert');
26
+ padding: spacing('3') spacing('5');
27
+ border-radius: radius('sm');
28
+ background: var(--mw-primary-color);
29
+ color: var(--mw-primary-accent-text-color);
30
+ font-weight: font-weight('medium');
31
+ box-shadow: var(--mw-elevation-3);
32
+ transform: translateY(calc(-100% - #{spacing('5')}));
33
+ transition: transform var(--mw-duration-fast) var(--mw-ease-out);
34
34
 
35
- &:focus-visible {
36
- transform: translateY(0);
35
+ &:focus-visible {
36
+ transform: translateY(0);
37
+ }
37
38
  }
38
- }
39
39
 
40
- // Content that is there for a screen reader but comes back on focus - the same
41
- // idea as sr-only, for something that has to be reachable by tab.
42
- .mw-sr-only-focusable:not(:focus):not(:focus-within) {
43
- position: absolute;
44
- width: 1px;
45
- height: 1px;
46
- padding: 0;
47
- margin: -1px;
48
- overflow: hidden;
49
- clip-path: inset(50%);
50
- white-space: nowrap;
51
- border: 0;
40
+ // Content that is there for a screen reader but comes back on focus - the same
41
+ // idea as sr-only, for something that has to be reachable by tab.
42
+ .mw-sr-only-focusable:not(:focus):not(:focus-within) {
43
+ position: absolute;
44
+ width: 1px;
45
+ height: 1px;
46
+ padding: 0;
47
+ margin: -1px;
48
+ overflow: hidden;
49
+ clip-path: inset(50%);
50
+ white-space: nowrap;
51
+ border: 0;
52
+ }
52
53
  }
@@ -1,27 +1,29 @@
1
1
  @use '../abstracts' as *;
2
2
 
3
- // Reserves the right box before the image inside it has loaded, which is the
4
- // whole point: without it the page reflows when the picture arrives and
5
- // everything below it jumps. The child fills the box and crops rather than
6
- // stretching.
7
- $_mw-aspects: (
8
- 'square': '1 / 1',
9
- 'video': '16 / 9',
10
- 'wide': '21 / 9',
11
- 'portrait': '3 / 4',
12
- 'photo': '4 / 3',
13
- );
3
+ @layer mw.utilities {
4
+ // Reserves the right box before the image inside it has loaded, which is the
5
+ // whole point: without it the page reflows when the picture arrives and
6
+ // everything below it jumps. The child fills the box and crops rather than
7
+ // stretching.
8
+ $_mw-aspects: (
9
+ 'square': '1 / 1',
10
+ 'video': '16 / 9',
11
+ 'wide': '21 / 9',
12
+ 'portrait': '3 / 4',
13
+ 'photo': '4 / 3',
14
+ );
14
15
 
15
- @each $name, $ratio in $_mw-aspects {
16
- .mw-aspect-#{$name} {
17
- aspect-ratio: #{$ratio};
16
+ @each $name, $ratio in $_mw-aspects {
17
+ .mw-aspect-#{$name} {
18
+ aspect-ratio: #{$ratio};
18
19
 
19
- > img,
20
- > video,
21
- > iframe {
22
- width: 100%;
23
- height: 100%;
24
- object-fit: cover;
20
+ > img,
21
+ > video,
22
+ > iframe {
23
+ width: 100%;
24
+ height: 100%;
25
+ object-fit: cover;
26
+ }
25
27
  }
26
28
  }
27
29
  }
@@ -1,8 +1,26 @@
1
1
  @use '../abstracts' as *;
2
2
 
3
- // Opt-out from the corner accent - the arc on the two round corners that every
4
- // surface in the framework carries, see the surface() mixin. Everything else
5
- // stays: the radii, the border, the shadow, the hover.
6
- .mw-corner-plain::after {
7
- content: none;
3
+ @layer mw.utilities {
4
+ // Opt-out from the corner accent - the arc on the two round corners that every
5
+ // surface in the framework carries, see the surface() mixin. Everything else
6
+ // stays: the radii, the border, the shadow, the hover.
7
+ .mw-corner-plain::after {
8
+ content: none;
9
+ }
10
+
11
+ // The framework silhouette drawn with a superellipse instead of a circular
12
+ // arc - the same four radii, a fuller curve. Opt-in on purpose: `corner-shape`
13
+ // only lands in Chromium so far, and switching it on by default would make the
14
+ // same card read differently in two browsers side by side without anyone
15
+ // having asked for it.
16
+ //
17
+ // The corner accent follows, or the arc would sit on a curve it no longer
18
+ // matches.
19
+ .mw-squircle {
20
+ corner-shape: squircle;
21
+
22
+ &::after {
23
+ corner-shape: squircle;
24
+ }
25
+ }
8
26
  }