maverick-wave 3.3.0 → 3.3.2

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 (77) hide show
  1. package/.claude/skills/maverick-wave/SKILL.md +208 -0
  2. package/.claude/skills/maverick-wave/examples/angular-form.md +275 -0
  3. package/.claude/skills/maverick-wave/examples/angular-list-page.md +304 -0
  4. package/.claude/skills/maverick-wave/examples/angular-services.md +348 -0
  5. package/.claude/skills/maverick-wave/examples/static-landing-page.md +362 -0
  6. package/.claude/skills/maverick-wave/references/components.md +812 -0
  7. package/.claude/skills/maverick-wave/references/forms.md +289 -0
  8. package/.claude/skills/maverick-wave/references/javascript.md +70 -0
  9. package/.claude/skills/maverick-wave/references/layout.md +300 -0
  10. package/.claude/skills/maverick-wave/references/theming.md +192 -0
  11. package/.github/workflows/ci.yml +41 -0
  12. package/CHANGELOG.md +13 -0
  13. package/README.md +115 -21
  14. package/index.html +15 -9
  15. package/maverick-wave.min.css +1 -1
  16. package/maverick-wave.min.js +1 -1
  17. package/package.json +3 -1
  18. package/scripts/verify.js +137 -0
  19. package/src/js/main.js +39 -11
  20. package/src/partials/accordions-container.html +22 -27
  21. package/src/partials/alerts-container.html +26 -0
  22. package/src/partials/avatars-container.html +22 -0
  23. package/src/partials/buttons-container.html +11 -15
  24. package/src/partials/cards-container.html +8 -8
  25. package/src/partials/colors-container.html +33 -20
  26. package/src/partials/documentation-container.html +3 -0
  27. package/src/partials/form-field-container.html +16 -12
  28. package/src/partials/get-started-container.html +93 -35
  29. package/src/partials/header-utilities-container.html +64 -6
  30. package/src/partials/input-group-container.html +5 -3
  31. package/src/partials/page-header-container.html +78 -0
  32. package/src/partials/tables-container.html +130 -0
  33. package/src/partials/tabs-container.html +20 -16
  34. package/src/partials/tags-container.html +55 -1
  35. package/src/scss/abstracts/_index.scss +4 -1
  36. package/src/scss/abstracts/_variables.scss +128 -106
  37. package/src/scss/base/_base.scss +32 -136
  38. package/src/scss/base/_reset.scss +1 -1
  39. package/src/scss/base/_typography.scss +0 -92
  40. package/src/scss/components/_accordions.scss +3 -3
  41. package/src/scss/components/_avatars.scss +28 -1
  42. package/src/scss/components/_blog-post.scss +1 -1
  43. package/src/scss/components/_button-bar.scss +6 -6
  44. package/src/scss/components/_buttons.scss +33 -10
  45. package/src/scss/components/_cards.scss +7 -7
  46. package/src/scss/components/_coming-soon.scss +4 -4
  47. package/src/scss/components/_gallery.scss +2 -2
  48. package/src/scss/components/_index.scss +1 -0
  49. package/src/scss/components/_info.scss +20 -3
  50. package/src/scss/components/_lists.scss +11 -10
  51. package/src/scss/components/_modals.scss +14 -7
  52. package/src/scss/components/_pagination.scss +3 -3
  53. package/src/scss/components/_panels.scss +4 -4
  54. package/src/scss/components/_progress.scss +1 -1
  55. package/src/scss/components/_ratings.scss +1 -1
  56. package/src/scss/components/_spinners.scss +2 -2
  57. package/src/scss/components/_stepper.scss +3 -2
  58. package/src/scss/components/_tables.scss +42 -1
  59. package/src/scss/components/_tabs.scss +5 -5
  60. package/src/scss/components/_tags.scss +43 -27
  61. package/src/scss/components/_tiles.scss +3 -3
  62. package/src/scss/components/_timelines.scss +2 -2
  63. package/src/scss/components/_toasts.scss +92 -0
  64. package/src/scss/form-elements/_form.scss +11 -3
  65. package/src/scss/form-elements/_input.scss +24 -0
  66. package/src/scss/form-elements/_toggle.scss +1 -1
  67. package/src/scss/layout/_footer.scss +4 -4
  68. package/src/scss/layout/_header.scss +219 -59
  69. package/src/scss/layout/_index.scss +1 -0
  70. package/src/scss/layout/_main.scss +1 -1
  71. package/src/scss/layout/_page-header.scss +48 -0
  72. package/src/scss/layout/_section.scss +15 -14
  73. package/src/scss/main.scss +4 -0
  74. package/src/scss/utilities/_flex.scss +4 -0
  75. package/src/scss/utilities/_index.scss +1 -0
  76. package/src/scss/utilities/_text.scss +105 -0
  77. package/.claude/commands/mw.md +0 -595
@@ -0,0 +1,812 @@
1
+ # Components
2
+
3
+ Colour variants are always one of `primary`, `secondary`, `success`, `warning`,
4
+ `danger`, `info` - but not every component offers all six. The lists below are
5
+ exhaustive: what is not named does not exist.
6
+
7
+ ## Buttons
8
+
9
+ ```html
10
+ <button type="button" class="mw-btn mw-btn-primary">Save</button>
11
+ <button type="button" class="mw-btn mw-btn-primary">
12
+ <i class="fas fa-save"></i> Save
13
+ </button>
14
+ <a href="#" class="mw-btn mw-btn-outline">Link that looks like a button</a>
15
+ ```
16
+
17
+ - Variants: `mw-btn-primary`, `mw-btn-secondary`, `mw-btn-danger`,
18
+ `mw-btn-success`, `mw-btn-outline`, `mw-btn-link`, `mw-btn-link-muted`
19
+ - Sizes: `mw-btn-sm`, `mw-btn-lg`
20
+ - `mw-btn` is `inline-flex` with a gap - icons need no wrapper and no extra class
21
+ - `disabled` gets `opacity: .6` and `not-allowed`; there is no disabled class
22
+ - `active` (no prefix) gives the pressed/selected look on the coloured variants
23
+ - `mw-btn-link` still has the button padding - `mw-p-0` makes it read as inline
24
+ text
25
+
26
+ **Destructive actions use `mw-btn-danger`.** `mw-btn-secondary` is a brand
27
+ colour, not a semantic one.
28
+
29
+ ### Mini buttons
30
+
31
+ Round 18px icon buttons - remove a row, close an alert, drop a tag.
32
+
33
+ ```html
34
+ <button type="button" class="mw-btn-mini mw-btn-mini-danger">
35
+ <i class="fas fa-times"></i>
36
+ </button>
37
+ ```
38
+
39
+ Variants: `mw-btn-mini-primary`, `-secondary`, `-danger`, `-success`. Plain
40
+ `mw-btn-mini` is the neutral one. Works on `<a>` as well.
41
+
42
+ ### Button bar
43
+
44
+ Row of equally treated buttons, centered by default.
45
+
46
+ ```html
47
+ <div class="mw-button-bar mw-button-bar-primary">
48
+ <button class="mw-btn">Previous</button>
49
+ <button class="mw-btn">Overview</button>
50
+ <button class="mw-btn">Next</button>
51
+ </div>
52
+ ```
53
+
54
+ - Colouring: `mw-button-bar-primary`, `-secondary`, `-outline` style the bare
55
+ `mw-btn` children, so the buttons carry no variant class themselves.
56
+ `mw-button-bar-nav` mixes them for prev/center/next navigation.
57
+ - Alignment: `mw-button-bar-left`, `-right` (default is centered),
58
+ `mw-button-bar-between` pushes first and last apart.
59
+ - Sizes: `mw-button-bar-sm`, `mw-button-bar-lg`.
60
+
61
+ ## Cards
62
+
63
+ ```html
64
+ <div class="mw-card mw-card-content">
65
+ <div class="mw-card-img">
66
+ <img src="cover.jpg" alt="" />
67
+ </div>
68
+ <div class="mw-card-body">
69
+ <h3 class="mw-card-title">Title</h3>
70
+ <hr class="mw-card-title-divider" />
71
+ <p class="mw-card-subtitle">Subtitle in muted italics</p>
72
+ <p class="mw-card-text">Body copy.</p>
73
+ <div class="mw-card-footer">
74
+ <button class="mw-btn mw-btn-primary">Open</button>
75
+ <span class="mw-text-muted">12 items</span>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ ```
80
+
81
+ - `mw-card` is the shell; the hover lift is built in and has no modifier class.
82
+ - `mw-card-simple` is the flat variant with even padding for arbitrary content.
83
+ Use it when you only need a padded surface.
84
+ - `mw-card-content` turns the card into a flex column so `mw-card-footer` sticks
85
+ to the bottom - needed whenever cards sit next to each other in a grid.
86
+ - Image height: 210px, `mw-card-lg` 340px, `mw-card-xl` 480px.
87
+ `mw-card-img-contain` shows the whole image instead of cropping it.
88
+ - In `mw-card-footer` the last child is pushed to the right; below `lg` the
89
+ footer stacks and children go full width.
90
+ - `mw-card-badge` (top right corner) and `mw-card-ribbon` (diagonal banner) are
91
+ absolutely positioned overlays; colour them with `mw-card-addon-primary`,
92
+ `-secondary`, `-success`, `-warning`, `-danger`, `-info`.
93
+
94
+ ```html
95
+ <div class="mw-card mw-card-content">
96
+ <div class="mw-card-badge mw-card-addon-success">New</div>
97
+ ...
98
+ </div>
99
+ ```
100
+
101
+ **Stack card** - icon + title header with a gradient rule, for feature or
102
+ tech-stack grids:
103
+
104
+ ```html
105
+ <div class="mw-card mw-card-stack">
106
+ <div class="mw-card-stack-header">
107
+ <div class="mw-card-stack-icon"><i class="fas fa-server"></i></div>
108
+ <h5 class="mw-card-stack-title">Backend</h5>
109
+ </div>
110
+ <div class="mw-card-stack-body">
111
+ <div class="mw-tags"><span class="mw-tags-item">Kotlin</span></div>
112
+ <p class="mw-card-stack-text">Description.</p>
113
+ </div>
114
+ </div>
115
+ ```
116
+
117
+ ## Panels
118
+
119
+ A bordered box with a header rule - the "titled section" of an application.
120
+
121
+ ```html
122
+ <div class="mw-panel mw-panel-primary">
123
+ <h4 class="mw-panel-header">Filters</h4>
124
+ <div class="mw-panel-body">...</div>
125
+ <div class="mw-panel-footer">
126
+ <button class="mw-btn mw-btn-outline">Reset</button>
127
+ <button class="mw-btn mw-btn-primary">Apply</button>
128
+ </div>
129
+ </div>
130
+ ```
131
+
132
+ - Header colour: `mw-panel-primary`, `mw-panel-secondary`; without them the
133
+ header is neutral.
134
+ - Height: `mw-panel-scrollable` (500px), `mw-panel-max-height-sm` (300px),
135
+ `-md` (500px), `-lg` (700px) - the body scrolls, header and footer stay.
136
+ - `mw-panel` has `min-height: 100%`, so panels in a grid row end up equally tall.
137
+
138
+ ## Tiles
139
+
140
+ Compact, clickable info blocks in a fixed 3-column grid.
141
+
142
+ ```html
143
+ <div class="mw-tiles mw-tiles-2col">
144
+ <div class="mw-tile">
145
+ <div class="mw-tile-img"><img src="icon.png" alt="" /></div>
146
+ <h3 class="mw-tile-header">Billing</h3>
147
+ <div class="mw-tile-body">
148
+ <p>Invoices and payments</p>
149
+ </div>
150
+ <div class="mw-tile-footer">Updated 2026-01-02</div>
151
+ </div>
152
+ </div>
153
+ ```
154
+
155
+ Container: `mw-tiles` (3 columns), `mw-tiles-2col`, `mw-tiles-4col`.
156
+ Tile sizes: `mw-tile-sm`, `mw-tile-lg`.
157
+
158
+ ## Accordion
159
+
160
+ ```html
161
+ <div class="mw-accordion">
162
+ <div class="mw-accordion-item">
163
+ <div class="mw-accordion-header active">
164
+ <h3>Question</h3>
165
+ <i class="fas fa-chevron-down mw-accordion-icon"></i>
166
+ </div>
167
+ <div class="mw-accordion-content active">
168
+ <div class="mw-accordion-content-inner">Answer</div>
169
+ </div>
170
+ </div>
171
+ </div>
172
+ ```
173
+
174
+ Open state = `active` (no prefix) on header **and** content. The icon rotates
175
+ via the header state. Content taller than 500px scrolls. Toggling is JS - see
176
+ `references/javascript.md`.
177
+
178
+ ## Tabs
179
+
180
+ ```html
181
+ <div class="mw-tabs">
182
+ <div class="mw-tabs-nav">
183
+ <div class="mw-tabs-nav-item active" data-tab="tab1">Details</div>
184
+ <div class="mw-tabs-nav-item" data-tab="tab2">History</div>
185
+ </div>
186
+ <div class="mw-tabs-content">
187
+ <div class="mw-tabs-panel active" id="tab1">...</div>
188
+ <div class="mw-tabs-panel" id="tab2">...</div>
189
+ </div>
190
+ </div>
191
+ ```
192
+
193
+ - Variants: `mw-tabs-vertical` (nav on the left, horizontal again below `sm`),
194
+ `mw-tabs-pills`.
195
+ - `data-tab` matches the panel `id` - that pairing is only needed for the
196
+ shipped JS. In a SPA, bind `active` yourself and drop the attribute.
197
+ - The nav scrolls horizontally on small screens instead of wrapping.
198
+
199
+ ## Modal
200
+
201
+ ```html
202
+ <div id="delete-modal" class="mw-modal-overlay">
203
+ <div class="mw-modal mw-modal-sm">
204
+ <div class="mw-modal-header">
205
+ <h4 class="mw-modal-title">Delete invoice</h4>
206
+ <button class="mw-modal-close" type="button">&#120299;</button>
207
+ </div>
208
+ <div class="mw-modal-body">
209
+ <p>This cannot be undone.</p>
210
+ </div>
211
+ <div class="mw-modal-footer">
212
+ <button class="mw-btn mw-btn-outline">Cancel</button>
213
+ <button class="mw-btn mw-btn-danger">Delete</button>
214
+ </div>
215
+ </div>
216
+ <div class="mw-modal-backdrop"></div>
217
+ </div>
218
+ ```
219
+
220
+ - The overlay is `display: none` until `mw-modal-open` is added to it. That
221
+ class is the whole open/close mechanism.
222
+ - Body scroll lock is automatic: the stylesheet uses
223
+ `body:has(.mw-modal-open)`. Nothing to implement.
224
+ - Sizes: `mw-modal-sm` 370px, default 550px, `mw-modal-lg` 680px,
225
+ `mw-modal-xl` 900px. Height is capped at 80-92dvh, the body scrolls.
226
+ - `mw-modal-backdrop` is the click-to-close surface; put the close handler on it.
227
+ - `mw-modal-body` takes a `mw-form` directly - the form brings the field gaps,
228
+ the body brings the padding.
229
+
230
+ Angular: `<div class="mw-modal-overlay" [class.mw-modal-open]="isOpen()">`.
231
+
232
+ ## Alerts & toasts
233
+
234
+ ```html
235
+ <div class="mw-alert mw-alert-success">
236
+ <div class="mw-alert-icon"><i class="fas fa-check-circle"></i></div>
237
+ <div class="mw-alert-content">
238
+ <span class="mw-alert-title">Saved</span>
239
+ <p>The invoice was created.</p>
240
+ </div>
241
+ <button type="button" class="mw-btn-mini mw-btn-mini-danger mw-alert-close">
242
+ <i class="fas fa-times"></i>
243
+ </button>
244
+ </div>
245
+ ```
246
+
247
+ Variants: `mw-alert-primary`, `-secondary`, `-success`, `-warning`, `-danger`,
248
+ `-info`. `mw-alert-title` and the close button are optional. `mw-alert-closed`
249
+ hides a dismissed alert (`display: none`) - in a SPA prefer removing it from the
250
+ list instead.
251
+
252
+ **Toasts** are alerts inside a fixed stack:
253
+
254
+ ```html
255
+ <div class="mw-toast-stack mw-toast-stack-top-right">
256
+ <div class="mw-alert mw-alert-success">...</div>
257
+ </div>
258
+ ```
259
+
260
+ Positions: `mw-toast-stack-top-right` (also the default without a position
261
+ class), `-top-center`, `-bottom-right`. Width is capped at
262
+ `min(380px, 100vw - 2rem)`, clicks pass through everywhere except on a toast,
263
+ the entry animation respects `prefers-reduced-motion`. Auto-dismiss is the
264
+ application's job.
265
+
266
+ ## Empty state
267
+
268
+ ```html
269
+ <div class="mw-empty-state mw-empty-state-warning mw-empty-state-sm">
270
+ <div class="mw-empty-state-icon"><i class="fas fa-inbox"></i></div>
271
+ <p class="mw-empty-state-title">No results</p>
272
+ <p class="mw-empty-state-desc">Try a different filter.</p>
273
+ <button class="mw-btn mw-btn-outline">Clear filters</button>
274
+ </div>
275
+ ```
276
+
277
+ Variants: `mw-empty-state-primary`, `-success`, `-warning`, `-danger`. Size:
278
+ `mw-empty-state-sm`.
279
+
280
+ ## Spinners
281
+
282
+ ```html
283
+ <div class="mw-spinner-container">
284
+ <div class="mw-spinner-border mw-spinner-primary"></div>
285
+ </div>
286
+ ```
287
+
288
+ - Shapes (one is mandatory): `mw-spinner-border`, `mw-spinner-dual-ring`,
289
+ `mw-spinner-dots` (needs three empty `<div>` children).
290
+ - Sizes `mw-spinner-sm`, `mw-spinner-lg`; colours `mw-spinner-primary`,
291
+ `mw-spinner-secondary`.
292
+ - `mw-spinner-container` centers in the available space.
293
+ `mw-spinner-container-overlay` lays a dimmed, blurred scrim over the parent -
294
+ the parent needs `position: relative`.
295
+
296
+ ## Skeleton
297
+
298
+ ```html
299
+ <div class="mw-skeleton-card">
300
+ <div class="mw-skeleton-row">
301
+ <span class="mw-skeleton mw-skeleton-circle"></span>
302
+ <div class="mw-skeleton-body">
303
+ <span class="mw-skeleton mw-skeleton-text" style="width: 55%"></span>
304
+ <span class="mw-skeleton mw-skeleton-text"></span>
305
+ </div>
306
+ </div>
307
+ <span class="mw-skeleton mw-skeleton-rect"></span>
308
+ <span class="mw-skeleton mw-skeleton-title"></span>
309
+ <span class="mw-skeleton mw-skeleton-text"></span>
310
+ </div>
311
+ ```
312
+
313
+ Shapes: `mw-skeleton-title`, `-text`, `-circle`, `-rect` (+ `-rect-sm`,
314
+ `-rect-lg`). Widths are set inline when a line should look ragged.
315
+
316
+ ## Tables
317
+
318
+ ```html
319
+ <div class="mw-table-responsive">
320
+ <table class="mw-table mw-table-cards">
321
+ <thead>
322
+ <tr>
323
+ <th>Name</th>
324
+ <th>Status</th>
325
+ <th class="mw-text-numeric">Amount</th>
326
+ </tr>
327
+ </thead>
328
+ <tbody>
329
+ <tr>
330
+ <td data-label="Name">Jane Doe</td>
331
+ <td data-label="Status">
332
+ <span class="mw-tag mw-tag-success">Paid</span>
333
+ </td>
334
+ <td data-label="Amount" class="mw-text-numeric">1.204,50</td>
335
+ </tr>
336
+ </tbody>
337
+ </table>
338
+ </div>
339
+ ```
340
+
341
+ | Class | Effect |
342
+ | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
343
+ | `mw-table` | Base: zebra rows, row hover, primary-coloured header |
344
+ | `mw-table-subtle` | Quiet grey header with an accent rule - for data-heavy lists |
345
+ | `mw-table-compact` | Less padding, smaller type |
346
+ | `mw-table-hover` | Stronger row hover |
347
+ | `mw-table-cards` | Below `md` every row becomes a card; keep `<thead>` (hidden via CSS) and give each cell a `data-label` |
348
+ | `mw-table-responsive` | Wrapper, horizontal scroll |
349
+ | `mw-table-responsive-scroll` | Wrapper with a height cap (`--mw-table-scroll-height`, 400px / 260px below `sm`) and vertical scroll |
350
+ | `mw-table-sticky-head` | Header stays put while the body scrolls - only works inside a height-limited wrapper, i.e. `mw-table-responsive-scroll` |
351
+
352
+ ```html
353
+ <div class="mw-table-responsive-scroll" style="--mw-table-scroll-height: 250px">
354
+ <table class="mw-table mw-table-subtle mw-table-sticky-head">
355
+ ...
356
+ </table>
357
+ </div>
358
+ ```
359
+
360
+ ## Tags
361
+
362
+ Two forms, picked by count - see also the pitfall list in `SKILL.md`.
363
+
364
+ **Single chip** (table cells, status columns) - carries its colour itself:
365
+
366
+ ```html
367
+ <span class="mw-tag mw-tag-success">Paid</span>
368
+ ```
369
+
370
+ Variants: `mw-tag-primary`, `-secondary`, `-success`, `-info`, `-warning`,
371
+ `-danger`, `-muted`. Size: `mw-tag-lg`. `mw-tag-muted` is the neutral tone for
372
+ states that should not shout (draft, archived).
373
+
374
+ **List** - the container carries the colour for all its items:
375
+
376
+ ```html
377
+ <div class="mw-tags mw-tags-primary">
378
+ <span class="mw-tags-item"
379
+ ><i class="fas fa-check mw-tags-icon"></i>Angular</span
380
+ >
381
+ <span class="mw-tags-item mw-tags-removable">
382
+ Kotlin
383
+ <button type="button" class="mw-btn-mini mw-btn-mini-danger mw-tags-remove">
384
+ <i class="fas fa-times"></i>
385
+ </button>
386
+ </span>
387
+ </div>
388
+ ```
389
+
390
+ Container variants: `mw-tags-primary`, `-secondary`, `-success`, `-info`,
391
+ `-warning`, `-danger`, `-muted`, size `mw-tags-lg`. `mw-tags-remove` only
392
+ positions the button - its look comes from `mw-btn-mini` plus a colour variant.
393
+
394
+ ## Info badges & counters
395
+
396
+ ```html
397
+ <span class="mw-info mw-info-primary">Active</span>
398
+
399
+ <a href="/invoices" class="mw-info mw-info-counter mw-info-success">
400
+ <div class="mw-info-value">150</div>
401
+ <div class="mw-info-label">Invoices</div>
402
+ </a>
403
+
404
+ <span class="mw-info-mini mw-info-mini-danger"
405
+ ><i class="fas fa-times"></i
406
+ ></span>
407
+ ```
408
+
409
+ - `mw-info`: sizes `mw-info-sm`, `-lg`, `-xl`; colours `mw-info-primary`,
410
+ `-secondary`, `-success`, `-warning`, `-danger`, `-info` (tinted background +
411
+ a 6px left border).
412
+ - `mw-info-counter` turns it into a big number over a small label
413
+ (`mw-info-value`, `mw-info-label`).
414
+ - The cursor is `default` because a figure is usually not clickable. On `<a>`
415
+ and `<button>` it turns into a pointer automatically; on anything else use
416
+ `mw-info-clickable`.
417
+ - `mw-info-mini` is the 20px status dot: sizes `-sm`, `-lg`, `-xl`, colours
418
+ `-primary`, `-secondary`, `-success`, `-warning`, `-danger`, `-info`.
419
+
420
+ ## Progress
421
+
422
+ ```html
423
+ <div class="mw-progress-container">
424
+ <div class="mw-progress-barinfo">
425
+ <span class="mw-progress-label">Completion</span>
426
+ <span class="mw-progress-value mw-progress-percent">75</span>
427
+ </div>
428
+ <div class="mw-progress-bar">
429
+ <div class="mw-progress-fill mw-progress-primary" style="width: 75%"></div>
430
+ </div>
431
+ </div>
432
+ ```
433
+
434
+ - The value element only prints what you put in it; `mw-progress-percent`
435
+ appends `%`, `mw-progress-numeric` appends `/10`. Neither computes anything.
436
+ - The fill width is set by you (`style="width: 75%"`). The shipped JS instead
437
+ reads `data-value="75"` and animates it into view - in a SPA bind the style.
438
+ - Colours: `mw-progress-primary`, `-secondary`, `-success`, `-warning`,
439
+ `-danger`, `-info` (default fill is the secondary colour).
440
+ - Sizes on the container: `mw-progress-sm`, `mw-progress-lg`.
441
+ - `mw-progress-hide-info` on the info row hides the labels while keeping the
442
+ layout; `mw-progress-inline-label` on the container puts the text inside the
443
+ bar.
444
+
445
+ ## Rating
446
+
447
+ ```html
448
+ <div class="mw-rating-container">
449
+ <p class="mw-rating-info">Product rating</p>
450
+ <div class="mw-rating mw-rating-lg" data-rating="4">
451
+ <i class="mw-rating-icon fas fa-thumbs-up" aria-hidden="true"></i>
452
+ <!-- five icons total -->
453
+ </div>
454
+ </div>
455
+ ```
456
+
457
+ `data-rating` is `0`-`5` and highlights the first N icons - pure CSS, any icon
458
+ works. Sizes: `mw-rating-sm`, `mw-rating-lg`.
459
+
460
+ ## Meta header
461
+
462
+ Small icon + text counters, e.g. under a page title.
463
+
464
+ ```html
465
+ <div class="mw-meta-header">
466
+ <div class="mw-meta-item">
467
+ <i class="fas fa-list"></i><span>Total: 14</span>
468
+ </div>
469
+ <div class="mw-meta-item">
470
+ <i class="fas fa-pen"></i><span>Drafts: 3</span>
471
+ </div>
472
+ </div>
473
+ ```
474
+
475
+ ## Stepper
476
+
477
+ ```html
478
+ <div class="mw-stepper">
479
+ <div class="mw-stepper-step">
480
+ <div class="mw-stepper-indicator mw-done"><i class="fas fa-check"></i></div>
481
+ <span class="mw-stepper-label mw-done">Account</span>
482
+ </div>
483
+ <div class="mw-stepper-connector mw-done"></div>
484
+ <div class="mw-stepper-step">
485
+ <div class="mw-stepper-indicator mw-active">2</div>
486
+ <span class="mw-stepper-label mw-active">Details</span>
487
+ </div>
488
+ <div class="mw-stepper-connector"></div>
489
+ <div class="mw-stepper-step">
490
+ <div class="mw-stepper-indicator">3</div>
491
+ <span class="mw-stepper-label">Review</span>
492
+ </div>
493
+ </div>
494
+ ```
495
+
496
+ State classes here are prefixed: `mw-done`, `mw-active`. The horizontal variant
497
+ needs the explicit `mw-stepper-connector` elements between the steps; the
498
+ vertical one (`mw-stepper-vertical`) draws the line itself and takes
499
+ `mw-stepper-content` with `mw-stepper-content-title` / `-desc` instead of a
500
+ label:
501
+
502
+ ```html
503
+ <div class="mw-stepper-vertical">
504
+ <div class="mw-stepper-step mw-done">
505
+ <div class="mw-stepper-indicator mw-done"><i class="fas fa-check"></i></div>
506
+ <div class="mw-stepper-content">
507
+ <p class="mw-stepper-content-title">Dependencies installed</p>
508
+ <p class="mw-stepper-content-desc">All packages resolved.</p>
509
+ </div>
510
+ </div>
511
+ </div>
512
+ ```
513
+
514
+ ## Timelines
515
+
516
+ Both are chronicles (CV, changelog), not schedulable time axes.
517
+
518
+ ```html
519
+ <div class="mw-timeline-big">
520
+ <div class="mw-timeline-big-step active">
521
+ <div class="mw-timeline-big-date-container">
522
+ <div class="mw-timeline-big-date-main">01/2023 - today</div>
523
+ <div class="mw-timeline-big-date-sub">(3 years)</div>
524
+ </div>
525
+ <div class="mw-timeline-big-content">
526
+ <div class="mw-card mw-card-content">...</div>
527
+ <div class="mw-timeline-big-event">
528
+ <span class="mw-timeline-big-event-date">05/2023</span>
529
+ <span class="mw-timeline-big-event-title">Certification</span>
530
+ </div>
531
+ </div>
532
+ </div>
533
+ </div>
534
+
535
+ <div class="mw-timeline-simple">
536
+ <div class="mw-timeline-simple-step active">
537
+ <div class="mw-timeline-simple-date">2024-03-22</div>
538
+ <div class="mw-timeline-simple-content">
539
+ <div class="mw-card mw-card-simple">...</div>
540
+ </div>
541
+ </div>
542
+ </div>
543
+ ```
544
+
545
+ The current step gets `active` (no prefix). Any card fits into the content
546
+ wrapper.
547
+
548
+ ## Avatars
549
+
550
+ ```html
551
+ <div class="mw-avatar mw-avatar-lg mw-avatar-primary">
552
+ <img src="me.jpg" alt="" />
553
+ </div>
554
+
555
+ <div class="mw-avatar mw-avatar-initials mw-avatar-xs">MW</div>
556
+ ```
557
+
558
+ - Sizes: `mw-avatar-xs` 32, `-sm` 64, default 96, `-lg` 144, `-xl` 250 px.
559
+ - Shape: `mw-avatar-square`.
560
+ - Colours `mw-avatar-primary`, `-secondary`, `-success`, `-warning`, `-danger`,
561
+ `-info` tint the **border**. On `mw-avatar-initials` the same class also tints
562
+ the **surface**, so both can be combined.
563
+ - `mw-avatar-initials` centers text and scales the font with the size class -
564
+ the standard display for a signed-in user without a picture.
565
+ - `mw-avatar-group` overlaps its avatars; `mw-avatar-group-sm` / `-lg` change
566
+ the overlap.
567
+
568
+ ## Item lists
569
+
570
+ Layout containers for arbitrary children - the children need no classes.
571
+
572
+ | Class | Look |
573
+ | ------------------------- | ---------------------------------------------------------------------------- |
574
+ | `mw-item-list` | Plain flex column with gaps |
575
+ | `mw-item-list-horizontal` | Row, wrapping; column below `sm` |
576
+ | `mw-item-list-cards` | Wider gaps, for cards |
577
+ | `mw-item-list-compact` | Bordered box, divided rows, hover indent (nests) |
578
+ | `mw-item-list-menu` | Elevated menu card, pointer cursor, press feedback |
579
+ | `mw-item-list-slide` | Cards with a sliding accent border on hover (`mw-item-list-slide-secondary`) |
580
+ | `mw-item-list-scroll` | Scroll box, 300px (`-sm` 200, `-lg` 400, `-xl` 500) |
581
+
582
+ ```html
583
+ <div class="mw-item-list-compact">
584
+ <div>Quick settings</div>
585
+ <div>
586
+ Privacy
587
+ <div class="mw-item-list-compact">
588
+ <div>Cookies</div>
589
+ </div>
590
+ </div>
591
+ </div>
592
+ ```
593
+
594
+ **Checkbox lists** are the one variant with required inner markup - a `<ul>` of
595
+ `<li>` each holding a `mw-checkbox`:
596
+
597
+ ```html
598
+ <ul class="mw-item-list-checkbox">
599
+ <li class="mw-selected">
600
+ <label class="mw-checkbox">
601
+ <input type="checkbox" checked />
602
+ <span class="mw-checkbox-box"></span>
603
+ <div class="mw-checkbox-content">
604
+ <h4 class="mw-checkbox-header">Task management</h4>
605
+ <p class="mw-checkbox-label">Track your daily tasks</p>
606
+ </div>
607
+ </label>
608
+ </li>
609
+ </ul>
610
+ ```
611
+
612
+ Variants: `mw-item-list-checkbox-compact`, `-large`, `-secondary`,
613
+ `-scroll`. `mw-selected` on the `<li>` is the selected-row highlight - bind it
614
+ to the checkbox state yourself in a SPA. The `mw-checkbox-content` block is
615
+ optional; a bare `mw-checkbox-label` renders a single-line row.
616
+
617
+ ## HTML lists
618
+
619
+ `mw-list` is the base (spacing for `li`), combined with one of:
620
+ `mw-list-unstyled`, `mw-list-inline`, `mw-list-link` (underlined anchors),
621
+ `mw-list-dot` (coloured markers), `mw-list-check` (✓ prefix).
622
+
623
+ ```html
624
+ <ul class="mw-list mw-list-check">
625
+ <li>Done</li>
626
+ </ul>
627
+ ```
628
+
629
+ ## Breadcrumbs
630
+
631
+ ```html
632
+ <nav class="mw-breadcrumbs mw-breadcrumbs-collapse" aria-label="Breadcrumb">
633
+ <ol class="mw-breadcrumbs-list">
634
+ <li class="mw-breadcrumbs-item">
635
+ <a href="/"><i class="fas fa-home"></i></a>
636
+ </li>
637
+ <li class="mw-breadcrumbs-item">
638
+ <a href="/invoices"><span>Invoices</span></a>
639
+ </li>
640
+ <li class="mw-breadcrumbs-item mw-breadcrumbs-current">
641
+ <a href="#" class="mw-breadcrumbs-active"><span>2026-001</span></a>
642
+ </li>
643
+ </ol>
644
+ </nav>
645
+ ```
646
+
647
+ The last item takes `mw-breadcrumbs-current` on the `li` and
648
+ `mw-breadcrumbs-active` on the anchor. `mw-breadcrumbs-sm` is the small variant,
649
+ `mw-breadcrumbs-collapse` hides middle items on narrow screens.
650
+
651
+ ## Pagination
652
+
653
+ A titled content frame with prev/next controls - not a page-number list.
654
+
655
+ ```html
656
+ <div class="mw-pagination">
657
+ <div class="mw-pagination-header">
658
+ <button class="mw-pagination-nav"><i class="fas fa-arrow-left"></i></button>
659
+ <h3 class="mw-pagination-title">Week 10</h3>
660
+ <button class="mw-pagination-nav">
661
+ <i class="fas fa-arrow-right"></i>
662
+ </button>
663
+ </div>
664
+ <div class="mw-pagination-content">...</div>
665
+ </div>
666
+ ```
667
+
668
+ `mw-pagination-loading` on the container dims the content while it swaps;
669
+ `mw-pagination-slide-left` / `-slide-right` are the directional transitions.
670
+
671
+ ## Divider
672
+
673
+ ```html
674
+ <hr class="mw-divider mw-divider-dashed" />
675
+ <div class="mw-divider-text"><span>or</span></div>
676
+ <div class="mw-divider-vertical"></div>
677
+ ```
678
+
679
+ Variants: `mw-divider-thick`, `mw-divider-dashed`, `mw-divider-primary`,
680
+ `mw-divider-secondary`. `mw-divider-text` is a labelled rule (the colour
681
+ variants apply to it too), `mw-divider-vertical` needs a flex row with a height.
682
+
683
+ ## Gallery & image slider
684
+
685
+ ```html
686
+ <div class="mw-gallery-container">
687
+ <div class="mw-gallery">
688
+ <button type="button" class="mw-gallery-navi mw-gallery-navi-prev">
689
+ &#10094;
690
+ </button>
691
+ <div class="mw-gallery-track">
692
+ <div class="mw-gallery-slide" data-desc="Mountains">
693
+ <img src="1.jpg" alt="" />
694
+ </div>
695
+ </div>
696
+ <button type="button" class="mw-gallery-navi mw-gallery-navi-next">
697
+ &#10095;
698
+ </button>
699
+ </div>
700
+ <div class="mw-gallery-desc">Mountains</div>
701
+ <div class="mw-gallery-dots"></div>
702
+ </div>
703
+ ```
704
+
705
+ The dots (`mw-gallery-dot`, active one gets `mw-active`) are generated by the
706
+ shipped JS, as is the track transform. In a SPA, render the dots and set
707
+ `transform: translateX(...)` yourself.
708
+
709
+ `mw-image-slider` swaps a base image against overlays through indexed buttons:
710
+
711
+ ```html
712
+ <div class="mw-image-slider">
713
+ <div class="mw-image-slider-base" data-index="0">
714
+ <img class="mw-image-slider-base-image" src="base.jpg" alt="" />
715
+ </div>
716
+ <div class="mw-image-slider-overlay">
717
+ <div class="mw-image-slider-overlay-image active" data-index="1">
718
+ <img src="a.jpg" alt="" />
719
+ </div>
720
+ </div>
721
+ <div class="mw-image-slider-controls-grid-3">
722
+ <button class="mw-btn mw-btn-primary active" data-index="0">Base</button>
723
+ </div>
724
+ </div>
725
+ ```
726
+
727
+ Control grids: `mw-image-slider-controls-grid-2`, `-grid-3`. Visible overlay and
728
+ current button carry `active`.
729
+
730
+ ## Blog post
731
+
732
+ ```html
733
+ <article class="mw-blog-post">
734
+ <h2 class="mw-blog-post-title">Title</h2>
735
+ <div class="mw-blog-post-header">
736
+ <div class="mw-blog-post-header-icon"><i class="fas fa-code"></i></div>
737
+ <div class="mw-blog-post-meta">
738
+ <div class="mw-blog-post-meta-item">
739
+ <i class="far fa-calendar"></i><span>2026-04-10</span>
740
+ </div>
741
+ </div>
742
+ </div>
743
+ <img class="mw-blog-post-featured-image" src="cover.jpg" alt="" />
744
+ <div class="mw-blog-post-content-markdown">
745
+ <!-- raw h3/p/ul/blockquote/pre from a markdown renderer -->
746
+ </div>
747
+ <div class="mw-blog-post-footer">
748
+ <button class="mw-btn mw-blog-post-footer-button">
749
+ <i class="fas fa-arrow-left"></i><span>Previous</span>
750
+ </button>
751
+ </div>
752
+ </article>
753
+ ```
754
+
755
+ `mw-blog-post-content-markdown` styles unclassed HTML - the target for rendered
756
+ markdown. `mw-blog-post-content` is the same wrapper for hand-written markup.
757
+
758
+ ## Code & terminal
759
+
760
+ ```html
761
+ <div class="mw-code-block">
762
+ <div class="mw-code-block-header">
763
+ <span class="mw-code-block-filename">main.kt</span>
764
+ <span class="mw-code-block-language">Kotlin</span>
765
+ </div>
766
+ <div class="mw-code-container">
767
+ <pre><code>fun main() {}</code></pre>
768
+ </div>
769
+ </div>
770
+
771
+ <div class="mw-terminal">
772
+ <span class="mw-terminal-line">npm install maverick-wave</span>
773
+ <span class="mw-terminal-line mw-terminal-output">added 1 package</span>
774
+ </div>
775
+ ```
776
+
777
+ Token classes for manual highlighting: `mw-code-keyword`, `mw-code-function`,
778
+ `mw-code-string`, `mw-code-number`, `mw-code-comment`, `mw-code-operator`. There
779
+ is no highlighting engine - wrap spans yourself or plug in Prism/highlight.js.
780
+ `mw-code-nowrap` disables wrapping. `<code>` on its own is styled as inline code.
781
+
782
+ ## Tech stack bucket
783
+
784
+ ```html
785
+ <div class="mw-techstack-bucket mw-techstack-bucket-dashed">
786
+ <a href="https://angular.dev" class="mw-techstack-item">
787
+ <img class="mw-techstack-logo" src="angular.svg" alt="Angular" />
788
+ <div class="mw-techstack-info">
789
+ <span class="mw-techstack-name">Angular</span>
790
+ <span class="mw-techstack-desc">Frontend</span>
791
+ </div>
792
+ </a>
793
+ <a
794
+ href="#"
795
+ class="mw-techstack-item mw-techstack-item-sm"
796
+ data-tooltip="Docker"
797
+ >
798
+ <img class="mw-techstack-logo" src="docker.svg" alt="Docker" />
799
+ </a>
800
+ </div>
801
+ ```
802
+
803
+ `mw-techstack-item-sm` is the logo-only chip; the info block is optional.
804
+
805
+ ## Coming soon
806
+
807
+ ```html
808
+ <div class="mw-coming-soon">
809
+ <i class="mw-coming-soon-icon fas fa-tools"></i>
810
+ <div class="mw-coming-soon-text">Coming soon</div>
811
+ </div>
812
+ ```