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,376 +1,371 @@
1
1
  @use '../abstracts' as *;
2
2
 
3
- // Base
4
- .mw-btn {
5
- display: inline-flex;
6
- align-items: center;
7
- justify-content: center;
8
- gap: spacing('3');
9
- // Block padding sits a step under the inline one on purpose: the height comes
10
- // from --mw-control-height, and padding above that value would override it
11
- // and put this button out of line with the field next to it.
12
- padding: spacing('2') spacing('4');
13
- border: 1px solid transparent;
14
- border-radius: radius('sm');
15
- font-weight: font-weight('medium');
16
- line-height: 1.2;
17
- min-height: var(--mw-control-height);
18
- text-decoration: none;
19
- cursor: pointer;
20
- transition: var(--mw-transition);
21
- box-sizing: border-box;
22
- font-family: inherit;
23
- font-size: inherit;
24
-
25
- @include focus-ring;
26
- @include tappable;
27
-
28
- &:active:not(:disabled) {
29
- transform: translateY(1px);
30
- transition-duration: var(--mw-duration-instant);
31
- }
3
+ @layer mw.components {
4
+ // Base
5
+ .mw-btn {
6
+ display: inline-flex;
7
+ align-items: center;
8
+ justify-content: center;
9
+ gap: spacing('3');
10
+ // Block padding sits a step under the inline one on purpose: the height comes
11
+ // from --mw-control-height, and padding above that value would override it
12
+ // and put this button out of line with the field next to it.
13
+ padding: spacing('2') spacing('4');
14
+ border: 1px solid transparent;
15
+ border-radius: radius('sm');
16
+ font-weight: font-weight('medium');
17
+ line-height: 1.2;
18
+ min-height: var(--mw-control-height);
19
+ text-decoration: none;
20
+ cursor: pointer;
21
+ transition: var(--mw-transition);
22
+ box-sizing: border-box;
23
+ font-family: inherit;
24
+ font-size: inherit;
25
+
26
+ @include focus-ring;
27
+ @include tappable;
28
+
29
+ &:active:not(:disabled) {
30
+ transform: translateY(1px);
31
+ transition-duration: var(--mw-duration-instant);
32
+ }
32
33
 
33
- &:disabled {
34
- cursor: not-allowed;
35
- opacity: 0.6;
36
- transform: none;
34
+ &:disabled {
35
+ cursor: not-allowed;
36
+ opacity: 0.6;
37
+ transform: none;
38
+ }
37
39
  }
38
- }
39
40
 
40
- // Color variants
41
- .mw-btn-primary {
42
- @include btn-solid;
43
- background: var(--mw-primary-color);
44
- color: var(--mw-primary-accent-text-color);
45
- &:hover:not(:disabled) {
46
- background: var(--mw-primary-color-hover);
47
- }
48
- &.mw-active:not(:disabled),
49
- &.active:not(:disabled) {
50
- background: var(--mw-primary-color-hover);
51
- border: 1px solid var(--mw-primary-color);
52
- }
53
- }
54
- .mw-btn-secondary {
55
- @include btn-solid;
56
- background: var(--mw-secondary-color);
57
- color: var(--mw-secondary-accent-text-color);
58
- &:hover:not(:disabled) {
59
- background: var(--mw-secondary-color-hover);
60
- }
61
- &.mw-active:not(:disabled),
62
- &.active:not(:disabled) {
63
- background: var(--mw-secondary-color-hover);
64
- border: 1px solid var(--mw-secondary-color);
65
- }
66
- }
67
- // Semantic variants for destructive / confirming actions
68
- .mw-btn-danger {
69
- @include btn-solid;
70
- background: var(--mw-danger-color);
71
- color: var(--mw-danger-accent-text-color);
72
- &:hover:not(:disabled) {
73
- background: var(--mw-danger-color-hover);
74
- }
75
- &.mw-active:not(:disabled),
76
- &.active:not(:disabled) {
77
- background: var(--mw-danger-color-hover);
78
- border: 1px solid var(--mw-danger-color);
79
- }
80
- }
81
- .mw-btn-success {
82
- @include btn-solid;
83
- background: var(--mw-success-color);
84
- color: var(--mw-success-accent-text-color);
85
- &:hover:not(:disabled) {
86
- background: var(--mw-success-color-hover);
87
- }
88
- &.mw-active:not(:disabled),
89
- &.active:not(:disabled) {
90
- background: var(--mw-success-color-hover);
91
- border: 1px solid var(--mw-success-color);
92
- }
93
- }
94
- .mw-btn-outline {
95
- background: transparent;
96
- border-color: var(--mw-primary-text-color);
97
- color: var(--mw-primary-text-color);
98
- &:hover:not(:disabled) {
41
+ .mw-btn-primary {
42
+ @include btn-solid;
99
43
  background: var(--mw-primary-color);
100
- border-color: var(--mw-primary-color);
101
44
  color: var(--mw-primary-accent-text-color);
102
- box-shadow: var(--mw-elevation-1);
45
+ &:hover:not(:disabled) {
46
+ background: var(--mw-primary-color-hover);
47
+ }
48
+ @include active(':not(:disabled)') {
49
+ background: var(--mw-primary-color-hover);
50
+ border: 1px solid var(--mw-primary-color);
51
+ }
103
52
  }
104
- &:active:not(:disabled) {
105
- box-shadow: inset 0 2px 5px color-mix(in srgb, #000 25%, transparent);
53
+ .mw-btn-secondary {
54
+ @include btn-solid;
55
+ background: var(--mw-secondary-color);
56
+ color: var(--mw-secondary-accent-text-color);
57
+ &:hover:not(:disabled) {
58
+ background: var(--mw-secondary-color-hover);
59
+ }
60
+ @include active(':not(:disabled)') {
61
+ background: var(--mw-secondary-color-hover);
62
+ border: 1px solid var(--mw-secondary-color);
63
+ }
106
64
  }
107
- &.mw-active:not(:disabled),
108
- &.active:not(:disabled) {
109
- background: var(--mw-primary-color);
110
- color: var(--mw-primary-accent-text-color);
65
+ // Semantic variants for destructive / confirming actions
66
+ .mw-btn-danger {
67
+ @include btn-solid;
68
+ background: var(--mw-danger-color);
69
+ color: var(--mw-danger-accent-text-color);
70
+ &:hover:not(:disabled) {
71
+ background: var(--mw-danger-color-hover);
72
+ }
73
+ @include active(':not(:disabled)') {
74
+ background: var(--mw-danger-color-hover);
75
+ border: 1px solid var(--mw-danger-color);
76
+ }
111
77
  }
112
- }
113
-
114
- // A button that looks like a link but is still a button: it keeps the control
115
- // height, so it lines up with the Save next to it in a card's actions or a
116
- // button bar. A link inside a sentence is `mw-link` instead - see _links.scss.
117
- .mw-btn-link,
118
- .mw-btn-link-muted {
119
- @include link-look;
120
- }
121
-
122
- .mw-btn-link {
123
- color: var(--mw-primary-text-color);
124
- }
125
-
126
- .mw-btn-link-muted {
127
- color: var(--mw-text-muted-color);
128
- &:hover:not(:disabled) {
129
- color: var(--mw-primary-text-color);
78
+ .mw-btn-success {
79
+ @include btn-solid;
80
+ background: var(--mw-success-color);
81
+ color: var(--mw-success-accent-text-color);
82
+ &:hover:not(:disabled) {
83
+ background: var(--mw-success-color-hover);
84
+ }
85
+ @include active(':not(:disabled)') {
86
+ background: var(--mw-success-color-hover);
87
+ border: 1px solid var(--mw-success-color);
88
+ }
130
89
  }
131
- }
132
-
133
- // The third emphasis level, and the one that was missing. Primary fills, outline
134
- // draws a line, ghost does neither until you point at it - which is what a
135
- // toolbar, a card's own actions or a row of icon buttons wants, where five
136
- // outlined boxes would fight the content they sit on.
137
- //
138
- // Not the same as `mw-btn-plain`: this one keeps the button's shape, padding and
139
- // hit area, it just does not paint them at rest.
140
- .mw-btn-ghost {
141
- background: transparent;
142
- border-color: transparent;
143
- color: var(--mw-text-color);
144
-
145
- &:hover:not(:disabled) {
146
- background: var(--mw-primary-background);
90
+ .mw-btn-outline {
91
+ background: transparent;
92
+ border-color: var(--mw-primary-text-color);
147
93
  color: var(--mw-primary-text-color);
94
+ &:hover:not(:disabled) {
95
+ background: var(--mw-primary-color);
96
+ border-color: var(--mw-primary-color);
97
+ color: var(--mw-primary-accent-text-color);
98
+ box-shadow: var(--mw-elevation-1);
99
+ }
100
+ &:active:not(:disabled) {
101
+ box-shadow: inset 0 2px 5px color-mix(in srgb, #000 25%, transparent);
102
+ }
103
+ @include active(':not(:disabled)') {
104
+ background: var(--mw-primary-color);
105
+ color: var(--mw-primary-accent-text-color);
106
+ }
148
107
  }
149
108
 
150
- &:active:not(:disabled) {
151
- background: var(--mw-primary-background-hover);
109
+ // A button that looks like a link but is still a button: it keeps the control
110
+ // height, so it lines up with the Save next to it in a card's actions or a
111
+ // button bar. A link inside a sentence is `mw-link` instead - see _links.scss.
112
+ .mw-btn-link,
113
+ .mw-btn-link-muted {
114
+ @include link-look;
152
115
  }
153
116
 
154
- &.mw-active:not(:disabled),
155
- &.active:not(:disabled) {
156
- background: var(--mw-primary-background);
117
+ .mw-btn-link {
157
118
  color: var(--mw-primary-text-color);
158
119
  }
159
- }
160
120
 
161
- .mw-btn-ghost-danger {
162
- color: var(--mw-danger-text-color);
163
-
164
- &:hover:not(:disabled) {
165
- background: var(--mw-danger-info-background);
166
- color: var(--mw-danger-text-color);
121
+ .mw-btn-link-muted {
122
+ color: var(--mw-text-muted-color);
123
+ &:hover:not(:disabled) {
124
+ color: var(--mw-primary-text-color);
125
+ }
167
126
  }
168
127
 
169
- &:active:not(:disabled) {
170
- background: var(--mw-danger-info-background-hover);
171
- }
172
- }
128
+ // The third emphasis level, and the one that was missing. Primary fills, outline
129
+ // draws a line, ghost does neither until you point at it - which is what a
130
+ // toolbar, a card's own actions or a row of icon buttons wants, where five
131
+ // outlined boxes would fight the content they sit on.
132
+ //
133
+ // Not the same as `mw-btn-plain`: this one keeps the button's shape, padding and
134
+ // hit area, it just does not paint them at rest.
135
+ .mw-btn-ghost {
136
+ background: transparent;
137
+ border-color: transparent;
138
+ color: var(--mw-text-color);
139
+
140
+ &:hover:not(:disabled) {
141
+ background: var(--mw-primary-background);
142
+ color: var(--mw-primary-text-color);
143
+ }
173
144
 
174
- // Square, for a button whose whole label is one icon. Without it the horizontal
175
- // padding is the only thing setting the width, so an icon button ends up wider
176
- // than it is tall and a row of them next to a text button lines up on nothing.
177
- // The width follows the size modifier it is combined with.
178
- .mw-btn-icon {
179
- --mw-btn-icon-size: 2.4rem;
180
-
181
- width: var(--mw-btn-icon-size);
182
- height: var(--mw-btn-icon-size);
183
- min-width: 0;
184
- padding: 0;
185
- flex-shrink: 0;
186
-
187
- &.mw-btn-sm {
188
- --mw-btn-icon-size: 2rem;
189
- }
145
+ &:active:not(:disabled) {
146
+ background: var(--mw-primary-background-hover);
147
+ }
190
148
 
191
- &.mw-btn-lg {
192
- --mw-btn-icon-size: 2.9rem;
149
+ @include active(':not(:disabled)') {
150
+ background: var(--mw-primary-background);
151
+ color: var(--mw-primary-text-color);
152
+ }
193
153
  }
194
154
 
195
- // The floor a thumb needs, over the visual size above
196
- @media (pointer: coarse), (max-width: #{breakpoint('md')}) {
197
- --mw-btn-icon-size: 2.75rem;
155
+ .mw-btn-ghost-danger {
156
+ color: var(--mw-danger-text-color);
198
157
 
199
- &.mw-btn-sm {
200
- --mw-btn-icon-size: 2.5rem;
158
+ &:hover:not(:disabled) {
159
+ background: var(--mw-danger-info-background);
160
+ color: var(--mw-danger-text-color);
161
+ }
162
+
163
+ &:active:not(:disabled) {
164
+ background: var(--mw-danger-info-background-hover);
201
165
  }
202
166
  }
203
- }
204
167
 
205
- // Full width. Mostly a phone thing - a sign-in button, the one action on a
206
- // sheet - but also right for a narrow sidebar. `flex` rather than `block`, so
207
- // the icon-and-label centering the base class sets up still holds.
208
- .mw-btn-block {
209
- display: flex;
210
- width: 100%;
211
- }
168
+ // Square, for a button whose whole label is one icon. Without it the horizontal
169
+ // padding is the only thing setting the width, so an icon button ends up wider
170
+ // than it is tall and a row of them next to a text button lines up on nothing.
171
+ // The width follows the size modifier it is combined with.
172
+ .mw-btn-icon {
173
+ --mw-btn-icon-size: 2.4rem;
212
174
 
213
- // A button that brings nothing but its operability - settings tabs, calendar
214
- // days, the time in a request row, a modal backdrop. Everywhere a <button> is
215
- // the right element and a button is the wrong look.
216
- //
217
- // Not the same as `mw-btn-link`: that one is a button dressed as a link, with
218
- // its own colour and a control height. Nor `mw-link`, which is the link inside
219
- // a sentence. This one has no look at all.
220
- .mw-btn-plain {
221
- display: inline-flex;
222
- align-items: center;
223
- appearance: none;
224
- background: none;
225
- border: 0;
226
- padding: 0;
227
- margin: 0;
228
- font: inherit;
229
- color: inherit;
230
- text-align: inherit;
231
- cursor: pointer;
232
-
233
- @include focus-ring;
234
-
235
- &:disabled {
236
- cursor: not-allowed;
237
- opacity: 0.6;
238
- }
239
- }
175
+ width: var(--mw-btn-icon-size);
176
+ height: var(--mw-btn-icon-size);
177
+ min-width: 0;
178
+ padding: 0;
179
+ flex-shrink: 0;
240
180
 
241
- // Size modifiers
242
- // Buttons run one step above the fields on font size: a button carries a label,
243
- // a field carries what the user typed, and the label may be the louder of the
244
- // two. The heights still match, which is the part that shows.
245
- .mw-btn-sm {
246
- padding: spacing('1') spacing('3');
247
- font-size: font-size('sm');
248
- min-height: var(--mw-control-height-sm);
249
- }
250
- .mw-btn-lg {
251
- padding: spacing('3') spacing('5');
252
- font-size: font-size('md');
253
- min-height: var(--mw-control-height-lg);
254
- }
181
+ &.mw-btn-sm {
182
+ --mw-btn-icon-size: 2rem;
183
+ }
255
184
 
256
- // In a row of buttons a two-letter label like "Ja" ends up half the width
257
- // of its neighbour, which reads as an accident.
258
- .mw-modal-footer,
259
- .mw-form-actions,
260
- .mw-panel-footer,
261
- .mw-button-bar,
262
- .mw-kanban-composer-actions {
263
- .mw-btn:not(.mw-btn-icon) {
264
- min-width: 80px;
265
- }
266
- }
185
+ &.mw-btn-lg {
186
+ --mw-btn-icon-size: 2.9rem;
187
+ }
188
+
189
+ // The floor a thumb needs, over the visual size above
190
+ @media (pointer: coarse), (max-width: #{breakpoint('md')}) {
191
+ --mw-btn-icon-size: 2.75rem;
267
192
 
268
- // A line of text above a row of actions - "This action cannot be undone", what
269
- // a save applies to, why a button is disabled.
270
- //
271
- // It goes *inside* the action row, so no extra wrapper is needed: a full-width
272
- // flex line pushes the buttons onto the row below. Only rows that actually
273
- // carry a note start wrapping, so nothing existing changes its behaviour.
274
- //
275
- // `mw-form-actions-hint` was the form-only version of this and stays as an
276
- // alias - the name is wrong the moment the same line sits in a modal.
277
- .mw-modal-footer,
278
- .mw-form-actions,
279
- .mw-panel-footer,
280
- .mw-card-footer {
281
- &:has(.mw-actions-note),
282
- &:has(.mw-form-actions-hint) {
283
- flex-wrap: wrap;
284
- // The column gap between buttons is too tight to double as the gap to the
285
- // line above them
286
- row-gap: spacing('3');
193
+ &.mw-btn-sm {
194
+ --mw-btn-icon-size: 2.5rem;
195
+ }
196
+ }
287
197
  }
288
- }
289
198
 
290
- .mw-actions-note,
291
- .mw-form-actions-hint {
292
- flex: 1 0 100%;
293
- margin: spacing('0');
294
- text-align: right;
295
- font-size: font-size('sm');
296
- color: var(--mw-text-muted-color);
297
- text-wrap: pretty;
298
- }
199
+ // Full width. Mostly a phone thing - a sign-in button, the one action on a
200
+ // sheet - but also right for a narrow sidebar. `flex` rather than `block`, so
201
+ // the icon-and-label centering the base class sets up still holds.
202
+ .mw-btn-block {
203
+ display: flex;
204
+ width: 100%;
205
+ }
206
+
207
+ // A button that brings nothing but its operability - settings tabs, calendar
208
+ // days, the time in a request row, a modal backdrop. Everywhere a <button> is
209
+ // the right element and a button is the wrong look.
210
+ //
211
+ // Not the same as `mw-btn-link`: that one is a button dressed as a link, with
212
+ // its own colour and a control height. Nor `mw-link`, which is the link inside
213
+ // a sentence. This one has no look at all.
214
+ .mw-btn-plain {
215
+ display: inline-flex;
216
+ align-items: center;
217
+ appearance: none;
218
+ background: none;
219
+ border: 0;
220
+ padding: 0;
221
+ margin: 0;
222
+ font: inherit;
223
+ color: inherit;
224
+ text-align: inherit;
225
+ cursor: pointer;
226
+
227
+ @include focus-ring;
228
+
229
+ &:disabled {
230
+ cursor: not-allowed;
231
+ opacity: 0.6;
232
+ }
233
+ }
299
234
 
300
- .mw-btn-mini {
301
- display: inline-flex;
302
- align-items: center;
303
- justify-content: center;
304
- width: 18px;
305
- height: 18px;
306
- border-radius: radius('full');
307
- background: var(--mw-gray-color);
308
- color: $fixed-surface-text;
309
- border: none;
310
- padding: 0;
311
- line-height: 1;
312
- font-weight: bold;
313
- cursor: pointer;
314
- transition: var(--mw-transition);
315
- text-decoration: none;
316
- box-sizing: border-box;
317
- margin-left: spacing('1');
318
-
319
- i,
320
- fa-icon,
321
- svg,
322
- [class*='fa-'],
323
- [class*='fas-'] {
324
- font-size: 0.6rem;
235
+ // Size modifiers
236
+ // Buttons run one step above the fields on font size: a button carries a label,
237
+ // a field carries what the user typed, and the label may be the louder of the
238
+ // two. The heights still match, which is the part that shows.
239
+ .mw-btn-sm {
240
+ padding: spacing('1') spacing('3');
241
+ font-size: font-size('sm');
242
+ min-height: var(--mw-control-height-sm);
243
+ }
244
+ .mw-btn-lg {
245
+ padding: spacing('3') spacing('5');
246
+ font-size: font-size('md');
247
+ min-height: var(--mw-control-height-lg);
248
+ }
249
+
250
+ // In a row of buttons a two-letter label like "Ja" ends up half the width
251
+ // of its neighbour, which reads as an accident.
252
+ .mw-modal-footer,
253
+ .mw-form-actions,
254
+ .mw-panel-footer,
255
+ .mw-button-bar,
256
+ .mw-kanban-composer-actions {
257
+ .mw-btn:not(.mw-btn-icon) {
258
+ min-width: 80px;
259
+ }
325
260
  }
326
261
 
327
- &:disabled {
328
- cursor: not-allowed;
329
- opacity: 0.4;
262
+ // A line of text above a row of actions - "This action cannot be undone", what
263
+ // a save applies to, why a button is disabled.
264
+ //
265
+ // It goes *inside* the action row, so no extra wrapper is needed: a full-width
266
+ // flex line pushes the buttons onto the row below. Only rows that actually
267
+ // carry a note start wrapping, so nothing existing changes its behaviour.
268
+ //
269
+ // `mw-form-actions-hint` was the form-only version of this and stays as an
270
+ // alias - the name is wrong the moment the same line sits in a modal.
271
+ .mw-modal-footer,
272
+ .mw-form-actions,
273
+ .mw-panel-footer,
274
+ .mw-card-footer {
275
+ &:has(.mw-actions-note),
276
+ &:has(.mw-form-actions-hint) {
277
+ flex-wrap: wrap;
278
+ // The column gap between buttons is too tight to double as the gap to the
279
+ // line above them
280
+ row-gap: spacing('3');
281
+ }
330
282
  }
331
283
 
332
- @include focus-ring(1px);
333
- @include tappable;
284
+ .mw-actions-note,
285
+ .mw-form-actions-hint {
286
+ flex: 1 0 100%;
287
+ margin: spacing('0');
288
+ text-align: right;
289
+ font-size: font-size('sm');
290
+ color: var(--mw-text-muted-color);
291
+ text-wrap: pretty;
292
+ }
293
+
294
+ .mw-btn-mini {
295
+ display: inline-flex;
296
+ align-items: center;
297
+ justify-content: center;
298
+ width: 18px;
299
+ height: 18px;
300
+ border-radius: radius('full');
301
+ background: var(--mw-gray-color);
302
+ color: $fixed-surface-text;
303
+ border: none;
304
+ padding: 0;
305
+ line-height: 1;
306
+ font-weight: bold;
307
+ cursor: pointer;
308
+ transition: var(--mw-transition);
309
+ text-decoration: none;
310
+ box-sizing: border-box;
311
+ margin-left: spacing('1');
312
+
313
+ i,
314
+ fa-icon,
315
+ svg,
316
+ [class*='fa-'],
317
+ [class*='fas-'] {
318
+ font-size: 0.6rem;
319
+ }
334
320
 
335
- &:hover:not(:disabled) {
336
- background: var(--mw-primary-color);
337
- color: var(--mw-primary-accent-text-color);
338
- }
321
+ &:disabled {
322
+ cursor: not-allowed;
323
+ opacity: 0.4;
324
+ }
325
+
326
+ @include focus-ring(1px);
327
+ @include tappable;
339
328
 
340
- // Springs back rather than easing back - an 18px circle is small enough that
341
- // a plain return reads as nothing having happened
342
- &:active:not(:disabled) {
343
- transform: scale(0.88);
344
- transition:
345
- transform var(--mw-duration-instant) var(--mw-ease-spring),
346
- var(--mw-transition-fast);
329
+ &:hover:not(:disabled) {
330
+ background: var(--mw-primary-color);
331
+ color: var(--mw-primary-accent-text-color);
332
+ }
333
+
334
+ // Springs back rather than easing back - an 18px circle is small enough that
335
+ // a plain return reads as nothing having happened
336
+ &:active:not(:disabled) {
337
+ transform: scale(0.88);
338
+ transition:
339
+ transform var(--mw-duration-instant) var(--mw-ease-spring),
340
+ var(--mw-transition-fast);
341
+ }
347
342
  }
348
- }
349
343
 
350
- .mw-btn-mini-primary {
351
- &:hover:not(:disabled) {
352
- background: var(--mw-primary-color);
353
- color: var(--mw-primary-accent-text-color);
344
+ .mw-btn-mini-primary {
345
+ &:hover:not(:disabled) {
346
+ background: var(--mw-primary-color);
347
+ color: var(--mw-primary-accent-text-color);
348
+ }
354
349
  }
355
- }
356
350
 
357
- .mw-btn-mini-secondary {
358
- &:hover:not(:disabled) {
359
- background: var(--mw-secondary-color);
360
- color: var(--mw-secondary-accent-text-color);
351
+ .mw-btn-mini-secondary {
352
+ &:hover:not(:disabled) {
353
+ background: var(--mw-secondary-color);
354
+ color: var(--mw-secondary-accent-text-color);
355
+ }
361
356
  }
362
- }
363
357
 
364
- .mw-btn-mini-danger {
365
- &:hover:not(:disabled) {
366
- background: var(--mw-danger-color);
367
- color: var(--mw-danger-accent-text-color);
358
+ .mw-btn-mini-danger {
359
+ &:hover:not(:disabled) {
360
+ background: var(--mw-danger-color);
361
+ color: var(--mw-danger-accent-text-color);
362
+ }
368
363
  }
369
- }
370
364
 
371
- .mw-btn-mini-success {
372
- &:hover:not(:disabled) {
373
- background: var(--mw-success-color);
374
- color: var(--mw-success-accent-text-color);
365
+ .mw-btn-mini-success {
366
+ &:hover:not(:disabled) {
367
+ background: var(--mw-success-color);
368
+ color: var(--mw-success-accent-text-color);
369
+ }
375
370
  }
376
371
  }