maverick-wave 5.29.0 → 5.31.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.
- package/README.md +2 -2
- package/maverick-wave.min.css +2 -2
- package/package.json +8 -2
- package/src/scss/components/_avatars.scss +35 -3
- package/src/scss/components/_dropdown.scss +24 -1
- package/src/scss/components/_lang-switch.scss +4 -8
- package/src/scss/components/_modals.scss +33 -5
- package/.claude/settings.local.json +0 -43
- package/.claude/skills/mw-maverick-wave/SKILL.md +0 -532
- package/.claude/skills/mw-maverick-wave/examples/angular-form.md +0 -279
- package/.claude/skills/mw-maverick-wave/examples/angular-list-page.md +0 -309
- package/.claude/skills/mw-maverick-wave/examples/angular-services.md +0 -538
- package/.claude/skills/mw-maverick-wave/examples/static-landing-page.md +0 -530
- package/.claude/skills/mw-maverick-wave/references/components.md +0 -2169
- package/.claude/skills/mw-maverick-wave/references/forms.md +0 -358
- package/.claude/skills/mw-maverick-wave/references/javascript.md +0 -164
- package/.claude/skills/mw-maverick-wave/references/layout.md +0 -764
- package/.claude/skills/mw-maverick-wave/references/theming.md +0 -528
- package/.github/workflows/ci.yml +0 -41
- package/.idea/codeStyles/Project.xml +0 -59
- package/.idea/codeStyles/codeStyleConfig.xml +0 -5
- package/.idea/maverick-wave.iml +0 -12
- package/.idea/modules.xml +0 -8
- package/.idea/prettier.xml +0 -6
- package/.idea/vcs.xml +0 -6
- package/.prettierignore +0 -8
- package/.prettierrc.json +0 -7
- package/CHANGELOG.md +0 -950
- package/CLAUDE.md +0 -60
- package/gulpfile.js +0 -167
- package/index.html +0 -1730
- package/release.sh +0 -31
- package/scripts/verify.js +0 -252
- package/src/assets/favicon/apple-touch-icon.png +0 -0
- package/src/assets/favicon/favicon-96x96.png +0 -0
- package/src/assets/favicon/favicon.svg +0 -1
- package/src/assets/favicon/site.webmanifest +0 -37
- package/src/assets/favicon/web-app-manifest-192x192.png +0 -0
- package/src/assets/favicon/web-app-manifest-512x512.png +0 -0
- package/src/assets/favicon.ico +0 -0
- package/src/assets/header-logo.svg +0 -24
- package/src/assets/images/gallery-city.svg +0 -49
- package/src/assets/images/gallery-desert.svg +0 -25
- package/src/assets/images/gallery-forest.svg +0 -46
- package/src/assets/images/gallery-lake.svg +0 -26
- package/src/assets/images/gallery-mountain.svg +0 -19
- package/src/assets/images/gallery-ocean.svg +0 -26
- package/src/assets/images/gallery-oldtown.svg +0 -41
- package/src/assets/images/gallery-snow.svg +0 -39
- package/src/assets/images/photo-balloon.svg +0 -35
- package/src/assets/images/photo-forest-path.svg +0 -31
- package/src/assets/images/photo-lighthouse.svg +0 -42
- package/src/assets/images/photo-palm.svg +0 -27
- package/src/assets/images/photo-peak.svg +0 -27
- package/src/assets/images/photo-tower.svg +0 -34
- package/src/assets/images/photo-waterfall.svg +0 -32
- package/src/assets/images/slider-field.svg +0 -124
- package/src/assets/images/slider-forest.svg +0 -33
- package/src/assets/images/slider-lake.svg +0 -35
- package/src/assets/images/slider-mountains.svg +0 -29
- package/src/assets/images/slider-trees.svg +0 -41
- package/src/assets/images/story-aurora.svg +0 -36
- package/src/assets/images/story-beach.svg +0 -34
- package/src/assets/images/story-stars.svg +0 -35
- package/src/assets/images/tile-analytics.svg +0 -22
- package/src/assets/images/tile-cloud.svg +0 -19
- package/src/assets/images/tile-ecommerce.svg +0 -14
- package/src/assets/images/tile-enterprise.svg +0 -22
- package/src/assets/images/tile-marketing.svg +0 -16
- package/src/assets/media/demo-chime.wav +0 -0
- package/src/assets/media/story-sunrise.jpg +0 -0
- package/src/assets/media/story-sunrise.mp4 +0 -0
- package/src/partials/accordions-container.html +0 -179
- package/src/partials/alerts-container.html +0 -151
- package/src/partials/announcement-container.html +0 -67
- package/src/partials/avatars-container.html +0 -229
- package/src/partials/badges-container.html +0 -114
- package/src/partials/blog-posts-container.html +0 -158
- package/src/partials/breadcrumbs-container.html +0 -126
- package/src/partials/button-bar-container.html +0 -175
- package/src/partials/buttons-container.html +0 -272
- package/src/partials/calendar-container.html +0 -203
- package/src/partials/cards-container.html +0 -727
- package/src/partials/code-container.html +0 -194
- package/src/partials/colors-container.html +0 -263
- package/src/partials/coming-soon-container.html +0 -10
- package/src/partials/contact-container.html +0 -85
- package/src/partials/content-slider-container.html +0 -36
- package/src/partials/divider-container.html +0 -70
- package/src/partials/documentation-container.html +0 -204
- package/src/partials/dropdown-container.html +0 -119
- package/src/partials/empty-state-container.html +0 -79
- package/src/partials/feed-container.html +0 -506
- package/src/partials/footer-container.html +0 -113
- package/src/partials/form-container.html +0 -262
- package/src/partials/form-elements-container.html +0 -616
- package/src/partials/form-field-container.html +0 -166
- package/src/partials/gallery-container.html +0 -62
- package/src/partials/get-started-container.html +0 -423
- package/src/partials/grid-container.html +0 -191
- package/src/partials/header-container.html +0 -69
- package/src/partials/header-utilities-container.html +0 -331
- package/src/partials/highlights-container.html +0 -71
- package/src/partials/history-container.html +0 -67
- package/src/partials/home-container.html +0 -31
- package/src/partials/html-lists-container.html +0 -63
- package/src/partials/info-container.html +0 -104
- package/src/partials/input-group-container.html +0 -299
- package/src/partials/item-lists-container.html +0 -368
- package/src/partials/kanban-container.html +0 -459
- package/src/partials/kbd-container.html +0 -63
- package/src/partials/leader-row-container.html +0 -139
- package/src/partials/login-container.html +0 -65
- package/src/partials/lunch-menu-container.html +0 -341
- package/src/partials/media-container.html +0 -27
- package/src/partials/meta-info-container.html +0 -21
- package/src/partials/modals-container.html +0 -199
- package/src/partials/mosaic-container.html +0 -173
- package/src/partials/page-header-container.html +0 -78
- package/src/partials/pagination-container.html +0 -64
- package/src/partials/palette-container.html +0 -480
- package/src/partials/panels-container.html +0 -126
- package/src/partials/parallax-container.html +0 -147
- package/src/partials/portrait-gallery-container.html +0 -175
- package/src/partials/preview-container.html +0 -136
- package/src/partials/pricing-container.html +0 -523
- package/src/partials/progress-container.html +0 -230
- package/src/partials/prose-container.html +0 -43
- package/src/partials/ratings-container.html +0 -104
- package/src/partials/section-head-container.html +0 -77
- package/src/partials/segmented-container.html +0 -66
- package/src/partials/skeleton-container.html +0 -87
- package/src/partials/spinners-container.html +0 -96
- package/src/partials/stepper-container.html +0 -111
- package/src/partials/stories-container.html +0 -182
- package/src/partials/tables-container.html +0 -309
- package/src/partials/tabs-container.html +0 -290
- package/src/partials/tags-container.html +0 -242
- package/src/partials/techstack-bucket-container.html +0 -187
- package/src/partials/testimonials-container.html +0 -88
- package/src/partials/tiles-container.html +0 -247
- package/src/partials/timelines-container.html +0 -196
- package/src/partials/typography-container.html +0 -74
- package/src/partials/utilities-container.html +0 -553
|
@@ -1,532 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: mw-maverick-wave
|
|
3
|
-
description: Complete usage guide for the MaverickWave CSS framework - mw-* classes, --mw-* design tokens, grid, components, forms, theming and integration into Angular, other SPAs or plain HTML. Use whenever markup or styles are written in a project that loads maverick-wave (CSS/SCSS/CDN), when a mw-* class or --mw-* token appears, or when a UI has to be built with it.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# MaverickWave
|
|
7
|
-
|
|
8
|
-
A CSS-only component framework: it ships classes and design tokens, no components,
|
|
9
|
-
no directives, no build-time API. You write plain HTML with `mw-*` classes - in a
|
|
10
|
-
template, a JSX file, a Twig partial, it makes no difference. Everything below is
|
|
11
|
-
therefore framework-neutral; the Angular notes are marked as such because Angular
|
|
12
|
-
is the reference integration.
|
|
13
|
-
|
|
14
|
-
**One rule dominates all others: only use classes that actually exist.** The
|
|
15
|
-
framework is not utility-complete, invented class names fail silently (no error,
|
|
16
|
-
just unstyled markup). Verify with `grep -o '\.mw-[a-z0-9-]*' dist/maverick-wave.min.css | sort -u`
|
|
17
|
-
or, in the framework repo, `npm run verify`.
|
|
18
|
-
|
|
19
|
-
## Reference files
|
|
20
|
-
|
|
21
|
-
Load the one you need - do not read them all up front.
|
|
22
|
-
|
|
23
|
-
| File | Content |
|
|
24
|
-
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
25
|
-
| `references/layout.md` | Page skeleton, grid, container, section, page header, header/navbar, footer, spacing/flex/display/text utilities |
|
|
26
|
-
| `references/components.md` | Every component: markup, variants, sizes, state classes |
|
|
27
|
-
| `references/forms.md` | Inputs, select, textarea, checkbox, radio, toggle, slider, input group, `mw-field` pattern, validation |
|
|
28
|
-
| `references/theming.md` | Token model, `color-mix` derivation, light/dark, site-wide variants, SCSS configuration, cherry-picking single components |
|
|
29
|
-
| `references/javascript.md` | What the shipped `main.js` does, why SPAs must not load it, what to implement instead |
|
|
30
|
-
|
|
31
|
-
## Examples
|
|
32
|
-
|
|
33
|
-
| File | Content |
|
|
34
|
-
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
35
|
-
| `examples/angular-list-page.md` | Full list/CRUD page: page header, meta counters, filter bar, table with status tags, empty state, delete modal, toasts |
|
|
36
|
-
| `examples/angular-form.md` | Reactive form: `mw-field`, validation states, input groups, numeric input, toggles, form actions |
|
|
37
|
-
| `examples/angular-services.md` | Theme service, toast service, modal/scroll-lock, tabs and accordion without `main.js` |
|
|
38
|
-
| `examples/static-landing-page.md` | Plain HTML page: announcement ribbon, hero with scroll cue, feature and offer cards, testimonials, scroll reveal, accordion, footer, theme toggle |
|
|
39
|
-
|
|
40
|
-
## Setup
|
|
41
|
-
|
|
42
|
-
### Plain HTML / CDN
|
|
43
|
-
|
|
44
|
-
```html
|
|
45
|
-
<meta
|
|
46
|
-
name="viewport"
|
|
47
|
-
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
|
|
48
|
-
/>
|
|
49
|
-
<link
|
|
50
|
-
rel="stylesheet"
|
|
51
|
-
href="https://cdn.jsdelivr.net/npm/maverick-wave@5/maverick-wave.min.css"
|
|
52
|
-
/>
|
|
53
|
-
<link
|
|
54
|
-
rel="stylesheet"
|
|
55
|
-
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
|
|
56
|
-
/>
|
|
57
|
-
...
|
|
58
|
-
<script src="https://cdn.jsdelivr.net/npm/maverick-wave@5/maverick-wave.min.js"></script>
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
`@5` keeps this snippet current; in a real project pin the exact version so a
|
|
62
|
-
build stays reproducible. The JS file is optional and only for
|
|
63
|
-
server-rendered/static pages - see below. `viewport-fit=cover` is not optional -
|
|
64
|
-
see pitfall 30.
|
|
65
|
-
|
|
66
|
-
### Angular (or any SPA)
|
|
67
|
-
|
|
68
|
-
```jsonc
|
|
69
|
-
// angular.json
|
|
70
|
-
"styles": ["src/assets/maverick-wave.min.css", "src/styles.scss"]
|
|
71
|
-
// no "scripts" entry - see the warning below
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Or from the npm package via SCSS: `@use 'maverick-wave/src/scss/main';`
|
|
75
|
-
(details and configuration in `references/theming.md`). The viewport meta above
|
|
76
|
-
belongs in `src/index.html` there, with `viewport-fit=cover` just the same.
|
|
77
|
-
|
|
78
|
-
**`main-lean` for a page that uses a handful of components.** The full build is
|
|
79
|
-
~41 kB gzipped and carries all 48 of them. `main-lean` is the same framework
|
|
80
|
-
without any component - tokens, reset, typography, layout, utilities - and the
|
|
81
|
-
components come in one by one next to it:
|
|
82
|
-
|
|
83
|
-
```scss
|
|
84
|
-
@use 'maverick-wave/src/scss/main-lean' with (
|
|
85
|
-
$primary-color: #1b1b1d
|
|
86
|
-
);
|
|
87
|
-
@use 'maverick-wave/src/scss/components/buttons';
|
|
88
|
-
@use 'maverick-wave/src/scss/components/cards';
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
That lands at ~16 kB gzipped plus what the components add (three of them ≈ 19 kB
|
|
92
|
-
in total). The configuration goes on `main-lean`, not on the component imports.
|
|
93
|
-
|
|
94
|
-
> **Never load `maverick-wave.min.js` in a SPA.** Everything in it is wired up
|
|
95
|
-
> once on `DOMContentLoaded` and writes straight into the DOM. In an Angular
|
|
96
|
-
> app that fires once during bootstrap: components rendered later are never
|
|
97
|
-
> initialised, and the theme toggle mutates the DOM behind change detection.
|
|
98
|
-
> Reimplement the handful of behaviours in your own components -
|
|
99
|
-
> `references/javascript.md` lists all of them, `examples/angular-services.md`
|
|
100
|
-
> shows the code.
|
|
101
|
-
|
|
102
|
-
### Icons
|
|
103
|
-
|
|
104
|
-
The framework styles icon slots but ships no icons. Examples use FontAwesome
|
|
105
|
-
(`<i class="fas fa-save"></i>`); any icon element works - inline SVG, an Angular
|
|
106
|
-
`fa-icon`, a `<span>` with a webfont.
|
|
107
|
-
|
|
108
|
-
### Fonts
|
|
109
|
-
|
|
110
|
-
No font is bundled. The defaults are system stacks - `--mw-font-family-base`
|
|
111
|
-
and `-heading` resolve to the platform UI font, `-mono` to Fira Code with the
|
|
112
|
-
system monospace stack behind it. Load a font yourself and either set the three
|
|
113
|
-
`$font-family-*` variables in SCSS or override the tokens in CSS.
|
|
114
|
-
|
|
115
|
-
## Naming rules
|
|
116
|
-
|
|
117
|
-
- Classes: `mw-` prefix, kebab-case: `.mw-button-bar`, `.mw-item-list-compact`
|
|
118
|
-
- Tokens: `--mw-` prefix: `--mw-primary-color`, `--mw-border-accent`
|
|
119
|
-
- Keyframes: `mw-` prefix too (`mw-toast-in`, `mw-home-fade`). `@keyframes` is
|
|
120
|
-
global, so an unprefixed name in your app and one in the framework are the
|
|
121
|
-
same animation - the loser disappears without an error
|
|
122
|
-
- Variants are suffixes on the base class: `mw-btn` + `mw-btn-primary`,
|
|
123
|
-
`mw-alert` + `mw-alert-danger`
|
|
124
|
-
- Colour variant names are the same everywhere: `primary`, `secondary`,
|
|
125
|
-
`success`, `warning`, `danger`, `info` (plus `muted` on tags). Not every
|
|
126
|
-
component offers all of them - check `references/components.md`.
|
|
127
|
-
- Size variants: `-sm`, `-lg`, sometimes `-xs` / `-xl`. The unsuffixed class is
|
|
128
|
-
the medium size.
|
|
129
|
-
|
|
130
|
-
### State classes
|
|
131
|
-
|
|
132
|
-
Since 4.0.0 there is one spelling for "this one is on": **`mw-active`**. It
|
|
133
|
-
works on every component that previously wanted a bare `active` - accordion,
|
|
134
|
-
tabs, navbar link, timeline step, image slider, button, theme toggle, segmented
|
|
135
|
-
control - alongside gallery dot, stepper and kanban composer, which used it all
|
|
136
|
-
along. Write `mw-active` and stop looking things up.
|
|
137
|
-
|
|
138
|
-
The unprefixed `active` is still styled everywhere it used to be, so existing
|
|
139
|
-
markup keeps working, but it is deprecated. The shipped `main.js` clears both
|
|
140
|
-
when it switches a state off, precisely so a stale `active` in the HTML cannot
|
|
141
|
-
leave a second tab lit.
|
|
142
|
-
|
|
143
|
-
The classes that mean something _other_ than "on" keep their own names:
|
|
144
|
-
|
|
145
|
-
| Component | State class |
|
|
146
|
-
| -------------------------------------------- | -------------------------------------------------------- |
|
|
147
|
-
| Anything switchable, "on" | `mw-active` (`active` deprecated) |
|
|
148
|
-
| Burger button + navbar panel | `open` (no prefix), plus `mw-nav-open` on `<body>` |
|
|
149
|
-
| Stepper indicator / label / connector / step | `mw-active`, `mw-done` |
|
|
150
|
-
| Checkbox list item (`li`) | `mw-selected` |
|
|
151
|
-
| Calendar day, picked | `mw-selected` |
|
|
152
|
-
| Kanban ticket being edited | `mw-kanban-editing` |
|
|
153
|
-
| Modal, older overlay div | `mw-modal-open` (a `<dialog>` carries `open` itself) |
|
|
154
|
-
| Alert, dismissing / dismissed | `mw-alert-closing` → `mw-alert-closed` (`display: none`) |
|
|
155
|
-
| Field wrapper in error | `mw-field-has-error` |
|
|
156
|
-
| Single form control in error | `mw-form-element-error` |
|
|
157
|
-
|
|
158
|
-
`mw-active` and `mw-selected` are not the same thing and not interchangeable:
|
|
159
|
-
active is the one of several that is currently showing, selected is a choice the
|
|
160
|
-
user made and can undo.
|
|
161
|
-
|
|
162
|
-
Angular: `[class.mw-active]="i === current"`.
|
|
163
|
-
|
|
164
|
-
## Scales
|
|
165
|
-
|
|
166
|
-
**Spacing** (`mw-m-*`, `mw-p-*`, `mw-gap-*` and every internal value):
|
|
167
|
-
|
|
168
|
-
| key | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
|
|
169
|
-
| --- | --- | --- | ---- | --- | ---- | --- | ---- | ---- | --- | --- | --- | --- | --- | --- | --- |
|
|
170
|
-
| rem | 0 | 0.2 | 0.35 | 0.5 | 0.75 | 1 | 1.35 | 1.75 | 2 | 2.5 | 3.3 | 4.3 | 5.5 | 7 | 9 |
|
|
171
|
-
|
|
172
|
-
Negative margins exist for keys 1-6 (`mw-mt--3` = -0.5rem). Gap has no negative
|
|
173
|
-
keys at all (negative gap is invalid CSS and is not generated).
|
|
174
|
-
|
|
175
|
-
**Font sizes** (`mw-text-3xs` … `mw-text-6xl`): `3xs` 0.6, `2xs` 0.7, `xs` 0.8,
|
|
176
|
-
`sm` 0.9, `base` 1, `md` 1.1, `lg` 1.3, `xl` 1.5, `2xl` 1.8, `3xl` 2.2, `4xl` 2.5,
|
|
177
|
-
`5xl` 3, `6xl` 4.3 rem. The utility classes are single steps; `h1`, `h2`,
|
|
178
|
-
`mw-section-head-title` and `mw-section-subtitle` interpolate instead - `h1`
|
|
179
|
-
runs `3xl` to `5xl` between 375px and 768px, `h2` `2xl` to `4xl`, the head title
|
|
180
|
-
`2xl` to `4xl` up to 992px and the subtitle one step up to 576px. The endpoints are the values the old
|
|
181
|
-
breakpoint steps had, so a phone and a desktop look the same and only the widths
|
|
182
|
-
between them moved.
|
|
183
|
-
|
|
184
|
-
**Breakpoints**: `xs` 375, `sm` 576, `md` 768, `lg` 992, `xl` 1200, `2xl` 1400 px.
|
|
185
|
-
Column grids and most components are mobile-first. The mixins emit range syntax
|
|
186
|
-
(`media-up` is `width >= bp`, `media-down` is `width < bp`), so the two never
|
|
187
|
-
overlap at the breakpoint itself and neither has to stop a fraction short of it.
|
|
188
|
-
Write `media-up`: the base block is the phone and each breakpoint adds to it.
|
|
189
|
-
`media-down` is right in three cases - a rule that sets what the base never sets
|
|
190
|
-
(turned around it would hard-wire an inherited value), a narrow layout that costs
|
|
191
|
-
more properties than the wide one (the navbar sheet, the modal bottom sheet), and
|
|
192
|
-
a class that only ever means "below here", like `mw-hide-mobile`.
|
|
193
|
-
|
|
194
|
-
**Overriding.** Everything the framework emits sits in
|
|
195
|
-
`@layer mw.reset, mw.base, mw.forms, mw.components, mw.layout, mw.utilities`.
|
|
196
|
-
Any rule written outside a layer beats all of it, so a single `.mw-card {}` in
|
|
197
|
-
your own stylesheet wins - no `!important`, no doubled selectors. `!important`
|
|
198
|
-
is not a stronger version of this but a weaker one: important declarations
|
|
199
|
-
reverse the layer order and unlayered comes last, so an important rule in
|
|
200
|
-
`mw.base` beats an important one of yours even behind an ID selector. The flip
|
|
201
|
-
side: third-party CSS loaded unlayered also wins, so pull it into a layer of
|
|
202
|
-
its own:
|
|
203
|
-
`@import url('font-awesome.css') layer(vendor);` with `@layer vendor, mw;`
|
|
204
|
-
declared before it.
|
|
205
|
-
|
|
206
|
-
**Radius** (`mw-radius-none|xs|sm|md|lg|xl|2xl|full`): 0, 2, 5, 10, 15, 20, 30 px, 50%.
|
|
207
|
-
Every one of them is multiplied by `--mw-radius-scale` (default 1), so one number
|
|
208
|
-
squares the framework off or rounds it further; `none` and `full` pass through.
|
|
209
|
-
|
|
210
|
-
**The surface signature.** Every panel-like component - card, panel, modal,
|
|
211
|
-
accordion, tile, calendar, pagination, login box - shares one silhouette: sharp
|
|
212
|
-
5px corners on the top-left/bottom-right diagonal, round 20px ones on the other,
|
|
213
|
-
plus a 2px **corner accent** in the primary tone (`--mw-corner-accent`) sitting
|
|
214
|
-
on the two round corners. It is not a class and not opt-in; the components carry
|
|
215
|
-
it. `mw-corner-plain` drops the accent on a box too small to hold it - see
|
|
216
|
-
`references/layout.md` - and `mw-corners-even` on `<html>` drops the whole
|
|
217
|
-
signature site-wide.
|
|
218
|
-
|
|
219
|
-
**Elevation** (`mw-elevation-0` … `-5`, and `var(--mw-elevation-N)` inside SCSS).
|
|
220
|
-
Two shadows per level - a tight contact layer plus a wide ambient one:
|
|
221
|
-
`1` resting (inputs, tags), `2` raised (cards, panels at rest), `3` floating
|
|
222
|
-
(a card under the pointer), `4` overlay (dropdown, popover, drawer), `5` modal.
|
|
223
|
-
`0` is explicitly flat. Never write a `box-shadow` by hand - the twelve one-off
|
|
224
|
-
values that used to exist are exactly what this replaced.
|
|
225
|
-
|
|
226
|
-
**Glow** (`mw-glow`, `mw-glow-{primary,secondary,info,success,warning,danger}`).
|
|
227
|
-
The same two-layer idea without the offset, so the surface reads as giving off
|
|
228
|
-
the light rather than casting a shadow. For the one element on a screen that has
|
|
229
|
-
to be seen first, and for nothing else.
|
|
230
|
-
|
|
231
|
-
**Motion** `--mw-duration-instant|fast|base|slow|slower` = 110/180/300/520/900ms
|
|
232
|
-
plus `--mw-duration-zoom` (650ms, for a large surface actually travelling),
|
|
233
|
-
`--mw-ease-out` (things arriving - the default), `--mw-ease-in-out` (A to B and
|
|
234
|
-
back), `--mw-ease-spring` (a pop). Two ready-made transitions:
|
|
235
|
-
`var(--mw-transition)` for hover and focus states, `var(--mw-transition-fast)`
|
|
236
|
-
for anything that should feel instant under the pointer. Both list their
|
|
237
|
-
properties explicitly rather than saying `all`. All six durations are multiplied
|
|
238
|
-
by `--mw-motion-scale` (default 1), the tempo counterpart to
|
|
239
|
-
`--mw-radius-scale`; `prefers-reduced-motion` overrides the result.
|
|
240
|
-
|
|
241
|
-
**Control sizes** `--mw-control-height-sm|base|lg` = 1.875 / 2.125 / 2.375rem (an
|
|
242
|
-
even 30 / 34 / 38px step, moved by `mw-density-compact` and `-roomy`) and
|
|
243
|
-
`--mw-control-font-sm|base|lg` = 0.8 / 0.9 / 1rem, shared by `mw-input`,
|
|
244
|
-
`mw-select`, `mw-textarea` and `mw-btn`. A field and the button beside it are
|
|
245
|
-
the same height by construction. Buttons run one font step above the fields.
|
|
246
|
-
|
|
247
|
-
**Focus** `--mw-focus-ring-width` 2px, `--mw-focus-ring-offset` 2px,
|
|
248
|
-
`--mw-focus-ring-color`, plus `--mw-focus-halo-size` 3px /
|
|
249
|
-
`--mw-focus-halo-opacity` 28% for the soft ring a form field gets instead of a
|
|
250
|
-
hard outline. SCSS: `@include focus-ring`, `focus-ring-inset`, `field-focus`.
|
|
251
|
-
|
|
252
|
-
**SCSS helpers** - `@use 'maverick-wave/src/scss/abstracts' as *` brings them in;
|
|
253
|
-
none of them survive into the compiled CSS. Full list in `references/theming.md`.
|
|
254
|
-
|
|
255
|
-
- `fluid($min, $max, $from: 'xs', $to: 'md')` - a clamp between two sizes, each
|
|
256
|
-
end a key of `$font-sizes` or a plain rem/px length. The rem term is the
|
|
257
|
-
point: a vw-only clamp ignores the reader's font size and stops responding to
|
|
258
|
-
zoom. A headline passes `$to: 'xl'`.
|
|
259
|
-
- `fluid-container($min, $max, $from, $to)` - the same ramp in `cqi` against the
|
|
260
|
-
container. Use it instead of `fluid()` inside a `@container` block.
|
|
261
|
-
- `media-up($bp)` / `media-down($bp)` - the breakpoint map as a query. `media-up`
|
|
262
|
-
is the default direction, see **Breakpoints** above.
|
|
263
|
-
- `touch-context($bp: 'md')` - coarse pointer _or_ narrow viewport, the condition
|
|
264
|
-
every target-size rule in the framework hangs under.
|
|
265
|
-
- `touch-floor($size: 2.75rem)` - that condition plus a `min-height`.
|
|
266
|
-
- `hit-area($grow: 6px, $box: 1.5rem)` - grows the hit area through `::after`
|
|
267
|
-
without touching the silhouette. An element carrying a `data-tooltip` owns that
|
|
268
|
-
pseudo for its arrow, so those are skipped and grow to `$box` instead.
|
|
269
|
-
- `hover` / `hover-move`, `focus-ring`, `focus-ring-inset`, `field-focus`,
|
|
270
|
-
`truncate`, `surface`.
|
|
271
|
-
|
|
272
|
-
## Component index
|
|
273
|
-
|
|
274
|
-
Everything below is documented in `references/components.md` unless marked otherwise.
|
|
275
|
-
|
|
276
|
-
**Actions** `mw-btn` (+ `primary`, `secondary`, `danger`, `success`, `outline`,
|
|
277
|
-
`ghost`, `ghost-danger`, `link`, `link-muted`, `plain`, `icon`, `block`, `sm`,
|
|
278
|
-
`lg`) · `mw-btn-mini` · `mw-link` / `mw-link-muted` (the link in running text) ·
|
|
279
|
-
`mw-button-bar`
|
|
280
|
-
(+ `left`, `right`, `center`, `between`) · `mw-segmented` · `mw-actions-note`
|
|
281
|
-
|
|
282
|
-
**Containers** `mw-card` (+ `simple`, `lg`, `xl`, `stack`, badge, ribbon,
|
|
283
|
-
feature frame) ·
|
|
284
|
-
`mw-panel` · `mw-tile` · `mw-accordion` · `mw-tabs` · `mw-modal` ·
|
|
285
|
-
`mw-item-list` family · `mw-offer` (+ `-head`, `-name`) ·
|
|
286
|
-
`mw-leader-row` (+ `-label`, `-value`, `-top`, `-dashed`, `-solid`) ·
|
|
287
|
-
`mw-date-stamp` (+ `-day`, `-date`, `-body`, `-today`) ·
|
|
288
|
-
`mw-contact` (+ `-row`, `-label`)
|
|
289
|
-
|
|
290
|
-
**Pricing** `mw-price` (+ `-amount`, `-fraction`, `-currency`, `-original`,
|
|
291
|
-
`-period`, `-word`, `-note`, `xs`/`sm`/`lg`, `inline`, `center`, `plain`)
|
|
292
|
-
|
|
293
|
-
**Data & status** `mw-table` (+ `subtle`, `sticky-head`, `cards`, `compact`,
|
|
294
|
-
`hover`, responsive wrappers) · `mw-kanban` (+ `plain`, `compact`) ·
|
|
295
|
-
`mw-calendar` (+ `compact`, `plain`) · `mw-tag` /
|
|
296
|
-
`mw-tags` · `mw-badge` (+ `-dot`, `-status`, `-anchor`, `-float`, `-pulse`) ·
|
|
297
|
-
`mw-info` / `mw-info-mini` / `mw-info-counter` · `mw-progress-bar` ·
|
|
298
|
-
`mw-rating` · `mw-meta-header` · `mw-stepper` · `mw-timeline-big` /
|
|
299
|
-
`mw-timeline-simple`
|
|
300
|
-
|
|
301
|
-
**Feedback** `mw-alert` · `mw-toast-stack` · `mw-announcement` (+ `-content`,
|
|
302
|
-
`-highlight`, `-static`, color variants) · `mw-empty-state` ·
|
|
303
|
-
`mw-spinner-border` / `mw-spinner-dots` / `mw-spinner-dual-ring` · `mw-skeleton`
|
|
304
|
-
|
|
305
|
-
**Navigation** `mw-header` (+ `mw-header-reveal`, `mw-header-keep`) +
|
|
306
|
-
`mw-navbar` · `mw-breadcrumbs` · `mw-pagination` ·
|
|
307
|
-
`mw-dropdown` (+ `-menu`, `-item`, `-item-danger`, `-divider`, `-label`,
|
|
308
|
-
`-caret`, `-end`, `-up`) · `mw-lang-switch` (+ `-code`, `-name`, `-check`,
|
|
309
|
-
`inverted`) · `mw-flag` (+ 23 country codes) ·
|
|
310
|
-
`mw-section-nav` (`references/layout.md`)
|
|
311
|
-
|
|
312
|
-
**Media & content** `mw-avatar` (+ `initials`, `group`, `landscape`,
|
|
313
|
-
`portrait`) · `mw-gallery` · `mw-image-slider` · `mw-mosaic` (+ lightbox) ·
|
|
314
|
-
`mw-portrait-gallery` · `mw-feed` · `mw-stories` / `mw-story-reel` ·
|
|
315
|
-
`mw-overlay-btn` · `mw-blog-post` · `mw-testimonial` (+ `-source`, `-detail`,
|
|
316
|
-
`-date`, `-featured`) · `mw-prose` · `mw-media` (+ `-caption`) · `mw-code-block` /
|
|
317
|
-
`mw-terminal` · `mw-techstack-bucket` · `mw-coming-soon` · `mw-divider` ·
|
|
318
|
-
`mw-kbd` · `mw-list` family
|
|
319
|
-
|
|
320
|
-
**Forms** (`references/forms.md`) `mw-field` · `mw-input` · `mw-select` ·
|
|
321
|
-
`mw-textarea` · `mw-checkbox` · `mw-radio` · `mw-toggle` · `mw-slider` ·
|
|
322
|
-
`mw-input-group` · `mw-prefilled` · `mw-form` / `mw-form-group` /
|
|
323
|
-
`mw-form-actions` · `mw-login`
|
|
324
|
-
|
|
325
|
-
**Layout** (`references/layout.md`) `mw-main` · `mw-container` (+ `-narrow`) ·
|
|
326
|
-
`mw-content` ·
|
|
327
|
-
`mw-section` · `mw-section-head` (+ `-title`, `-intro`, `-numbered`, colours) ·
|
|
328
|
-
`mw-page-header` · `mw-grid-*`
|
|
329
|
-
(+ `mw-grid-even`, `mw-grid-from-{sm,md,lg,xl}`) ·
|
|
330
|
-
`mw-columns-2/3` · `mw-row-split` · `mw-hero` (+ `mw-scroll-hint`, `-end`) ·
|
|
331
|
-
`mw-parallax` (+ `-media`, `-content`, `-dimmed`, `-sticky`, `-rise`,
|
|
332
|
-
`-slow`, `-pattern`) · `mw-footer`
|
|
333
|
-
|
|
334
|
-
**Utilities** (`references/layout.md`) `mw-sr-only` / `mw-sr-only-focusable` /
|
|
335
|
-
`mw-skip-link` · `mw-row-split` (+ `center`) · `mw-text-numeric` /
|
|
336
|
-
`mw-text-currency` · `mw-text-truncate` / `mw-text-clamp-2..5` /
|
|
337
|
-
`mw-text-break` / `mw-text-nowrap` · `mw-text-balance` / `mw-text-pretty` /
|
|
338
|
-
`mw-text-eyebrow` / `mw-text-measure` · `mw-elevation-0..5` · `mw-glow` /
|
|
339
|
-
`mw-glow-{primary,secondary,info,success,warning,danger}` ·
|
|
340
|
-
`mw-corner-plain` ·
|
|
341
|
-
`mw-aspect-square|video|wide|portrait|photo` · `mw-d-{sm,md,lg,xl}-*` /
|
|
342
|
-
`mw-hide-mobile` / `mw-hide-desktop` / `mw-hide-print` / `mw-print-only` · `mw-overflow-*` / `mw-snap-x` ·
|
|
343
|
-
`mw-reveal` / `mw-reveal-stagger` · spacing, flex, display, text
|
|
344
|
-
|
|
345
|
-
## Pitfalls
|
|
346
|
-
|
|
347
|
-
1. **`<section>` gets no padding by itself.** Since 3.4.0 the bare element
|
|
348
|
-
selector is gone - write `<section class="mw-section">`. `mw-section-alternate`
|
|
349
|
-
only paints the pattern, it does not space anything.
|
|
350
|
-
2. **`mw-form` has no padding** (removed in 3.4.0) - it is a flex column with a
|
|
351
|
-
gap. Safe to put on `mw-modal-body` or `mw-panel-body`.
|
|
352
|
-
3. **Use `mw-btn-danger` for destructive actions**, never `mw-btn-secondary`. The
|
|
353
|
-
secondary colour is a brand decision and turns yellow, teal or anything else
|
|
354
|
-
the moment the palette changes.
|
|
355
|
-
4. **One tag or many?** `mw-tag` is a standalone chip and carries its own colour -
|
|
356
|
-
right for a table cell. `mw-tags` is a container that colours all its
|
|
357
|
-
`mw-tags-item` children - right for a tag list. Mixing them (`mw-tag` inside
|
|
358
|
-
`mw-tags`) is wrong.
|
|
359
|
-
5. **A spinner needs a shape class.** `mw-spinner-primary` alone renders nothing;
|
|
360
|
-
use `mw-spinner-border`, `mw-spinner-dots` or `mw-spinner-dual-ring`.
|
|
361
|
-
6. **Sticky table headers need a height-limited scroll container** -
|
|
362
|
-
`mw-table-responsive` only scrolls horizontally. Use
|
|
363
|
-
`mw-table-responsive-scroll` (height via `--mw-table-scroll-height`).
|
|
364
|
-
7. **`--mw-text-muted-color` on a coloured surface is always wrong.** It follows
|
|
365
|
-
the theme; buttons, table headers and badges do not. Use
|
|
366
|
-
`--mw-*-accent-text-color` there, and `opacity` for disabled states.
|
|
367
|
-
`--mw-accent-text-color` is the shared label for all six colours; each one
|
|
368
|
-
also has its own `--mw-primary-accent-text-color`,
|
|
369
|
-
`--mw-secondary-accent-text-color`, `--mw-success/warning/danger/info-accent-text-color`,
|
|
370
|
-
defaulting to the shared token. Override a single one when that colour needs
|
|
371
|
-
the opposite label - a neon primary on an otherwise dark palette. The fixed
|
|
372
|
-
grey surfaces - tooltip, `mw-btn-mini`, `mw-info-mini`, gallery arrows -
|
|
373
|
-
hardcode white and ignore all of them.
|
|
374
|
-
8. **`mw-card` already lifts on hover** and `mw-btn` already has `inline-flex`
|
|
375
|
-
plus a gap for icons. Neither has a modifier class for it - adding one from
|
|
376
|
-
memory produces markup that does nothing.
|
|
377
|
-
9. **Overriding one root colour is enough.** Hover tones, translucent
|
|
378
|
-
backgrounds and borders are derived with `color-mix()` at runtime. Setting
|
|
379
|
-
`--mw-primary-color-hover` by hand is usually a sign the base token was not
|
|
380
|
-
set.
|
|
381
|
-
10. **Browser floor: `color-mix()` and `oklch(from ...)`** - Chrome 119+,
|
|
382
|
-
Safari 16.4+, Firefox 128+. Both carry the derived tones, so older browsers
|
|
383
|
-
get no colours at all, not merely worse ones.
|
|
384
|
-
11. **Touch targets grow on their own.** On `pointer: coarse` or below 768px,
|
|
385
|
-
`mw-btn` gets a 2.75rem minimum height, `mw-btn-sm`, `mw-input-sm`,
|
|
386
|
-
`mw-select-sm` and `mw-textarea-sm` 2.5rem, a tab 2.75rem, a calendar day
|
|
387
|
-
44px, `mw-section-btn` 2.75rem, and list rows / menu items / pager pages /
|
|
388
|
-
accordion headers 2.75rem.
|
|
389
|
-
`mw-btn-mini` keeps its 18px circle - it sits in tag rows and table cells
|
|
390
|
-
where a bigger one would shift the layout - and grows its _hit area_ to 28px
|
|
391
|
-
via a pseudo-element, and `mw-kanban-action` does the same - its 32px box
|
|
392
|
-
stays and the hit area around it reaches 44px.
|
|
393
|
-
`mw-techstack-item-sm` takes a real 2.5rem minimum instead, because half of
|
|
394
|
-
those chips carry a `data-tooltip` and that owns the pseudo-element.
|
|
395
|
-
Nothing to switch on, and no reason to write the media query again in an
|
|
396
|
-
app: your own control gets `@include touch-floor` for a height or
|
|
397
|
-
`@include hit-area` where the size is the design.
|
|
398
|
-
12. **`mw-empty-state` has a `-desc`, not a `-text`.** The parts are
|
|
399
|
-
`mw-empty-state-icon`, `-title`, `-desc`, plus the size variant
|
|
400
|
-
`mw-empty-state-sm`. Invented names fail silently, as always.
|
|
401
|
-
13. **`mw-text-numeric` gives digits, `mw-text-currency` gives a money column.**
|
|
402
|
-
The first is only `tabular-nums` - for a clock, a counter, an ID. The second
|
|
403
|
-
adds right alignment and `nowrap`. Before 4.0.0 the first did both, which
|
|
404
|
-
is why people wrote the declaration out by hand.
|
|
405
|
-
14. **A component host between a container and its children breaks the layout,
|
|
406
|
-
silently.** Every `mw-*` flex or grid container styles its _children_ -
|
|
407
|
-
`mw-grid-*`, `mw-tags`, `mw-button-bar`, `mw-form-actions`, `mw-modal-footer`,
|
|
408
|
-
`mw-toast-stack`. In plain HTML the children are right there; in a SPA a
|
|
409
|
-
component host often sits in between and becomes the item instead, so it
|
|
410
|
-
shrinks to content width or swallows a whole grid row. Put `mw-d-contents` on
|
|
411
|
-
that host - it then generates no box and the children take the item role
|
|
412
|
-
back. Angular: `host: { class: 'mw-d-contents' }`. `mw-header` handles this
|
|
413
|
-
case on its own, the others do not.
|
|
414
|
-
15. **A badge is not a tag.** `mw-tag` names something - a topic, a state - and
|
|
415
|
-
sits in a row of its own kind, with a tinted surface. `mw-badge` carries a
|
|
416
|
-
_count_ or a _status_ and usually sits **on** something, filled rather than
|
|
417
|
-
tinted. Number on a bell: badge. "Draft" next to a title: tag.
|
|
418
|
-
16. **A dropdown is a `<details>`, not a div.** `<details class="mw-dropdown">`
|
|
419
|
-
with a `<summary>` trigger - that is where the keyboard handling, the focus
|
|
420
|
-
and the open state come from, and it works without script. The framework JS
|
|
421
|
-
only adds Escape and click-outside. Writing your own div-plus-click loses all
|
|
422
|
-
of it.
|
|
423
|
-
17. **An open dropdown can be clipped by anything that hides its overflow.**
|
|
424
|
-
Where the browser supports anchor positioning the menu is `position: fixed`
|
|
425
|
-
and anchored to its trigger, so it escapes the clip on its own. Everywhere
|
|
426
|
-
else it is absolutely positioned and cut off. Either way the framework's own
|
|
427
|
-
containers (panel, card, tile, modal body, responsive table) lift the clip
|
|
428
|
-
while a menu is open. On your own container it is one line:
|
|
429
|
-
`:has(.mw-dropdown[open]) { overflow: visible }`.
|
|
430
|
-
18. **Never write `box-shadow` by hand.** Use `var(--mw-elevation-1..5)` or the
|
|
431
|
-
`mw-elevation-*` class. A hand-rolled shadow is the wrong colour in one of
|
|
432
|
-
the two themes - the dark theme's shadow is a light rim over a dark contact
|
|
433
|
-
layer, not a black blur. The one place the ramp is wrong is a shadow that
|
|
434
|
-
lands on a picture instead of on a theme surface: its light-theme layers are
|
|
435
|
-
cut for paper and vanish over a photograph. That is why the edge after a
|
|
436
|
-
parallax block carries fixed values, and why `mw-parallax-dimmed` hardcodes
|
|
437
|
-
its brightness and text-shadow.
|
|
438
|
-
19. **Never write a duration or an easing curve by hand** either. Use
|
|
439
|
-
`var(--mw-transition)` for a hover or focus state,
|
|
440
|
-
`var(--mw-transition-fast)` for something that should feel instant, and
|
|
441
|
-
`var(--mw-duration-*)` with `var(--mw-ease-*)` for anything else. That is
|
|
442
|
-
also what makes `prefers-reduced-motion` work - it turns the duration tokens
|
|
443
|
-
down, so anything built on them is covered for free.
|
|
444
|
-
20. **A hover effect that _moves_ something needs the `hover` mixin.** On touch
|
|
445
|
-
`:hover` latches after a tap and stays on, so a lifted card stays lifted,
|
|
446
|
-
visibly out of line with its row. `@include hover { transform: ... }` -
|
|
447
|
-
colour changes are fine unguarded, movement is not. The framework's own
|
|
448
|
-
components already do this.
|
|
449
|
-
21. **Below 576px a modal is a bottom sheet.** Full width, anchored to the bottom
|
|
450
|
-
edge, rounded on the top two corners, with a grab handle and full-width
|
|
451
|
-
actions in the footer. Nothing to switch on - do not fight it with your own
|
|
452
|
-
media query, and do not put a fixed height on `mw-modal`.
|
|
453
|
-
22. **Press states exist on every control**, because a finger never hovers.
|
|
454
|
-
`mw-btn` and friends dip 1px and invert their highlight, `mw-btn-mini` and
|
|
455
|
-
`mw-modal-close` scale down. If you build your own control, give it an
|
|
456
|
-
`:active` - on touch it is the only feedback there is.
|
|
457
|
-
23. **Never set a height on a form control.** `mw-input`, `mw-select`,
|
|
458
|
-
`mw-textarea` and `mw-btn` all take their minimum height from the control
|
|
459
|
-
scale, so a field and the button next to it line up on their own. Pick the
|
|
460
|
-
size step (`-sm` / nothing / `-lg`) and leave the height alone - a hand-set
|
|
461
|
-
one puts that control back out of line with everything around it.
|
|
462
|
-
24. **Put the size modifier on the input group, not inside it.**
|
|
463
|
-
`mw-input-group-sm` and `-lg` size the prefix, the suffix _and_ the field.
|
|
464
|
-
Adding `mw-input-sm` inside as well is redundant, and mixing the two steps
|
|
465
|
-
is what makes a group look broken.
|
|
466
|
-
25. **Loops keep their own timing, entrances go on the scale.** A spinner, a
|
|
467
|
-
skeleton shimmer and a pulse ring are ambient - running them at 300ms would
|
|
468
|
-
be frantic, and they are the one place a hand-written duration is right.
|
|
469
|
-
Anything that plays once - a panel appearing, a card sliding in, a drawer -
|
|
470
|
-
uses `var(--mw-duration-*)`.
|
|
471
|
-
26. **`transition: all` is out.** `var(--mw-transition)` lists paint-only
|
|
472
|
-
properties on purpose. The one exception in the framework is the header
|
|
473
|
-
burger, which morphs by animating `top` and `bottom`, and it says so in a
|
|
474
|
-
comment. If your component really does need to animate a size, name that
|
|
475
|
-
property - do not reach for `all`.
|
|
476
|
-
27. **A control is a `<button>`, never a styled `<div>`.** `mw-tabs-nav-item`,
|
|
477
|
-
`mw-theme-toggle`, `mw-gallery-dot`, `mw-accordion-header` and `mw-menu-btn`
|
|
478
|
-
are all written for one, and all five shipped as divs and spans - the first
|
|
479
|
-
three until 4.11, the accordion header until 4.12, the burger after that -
|
|
480
|
-
that no keyboard could reach. Each class clears what a `<button>` brings
|
|
481
|
-
with it, so `<button type="button" class="mw-tabs-nav-item" data-tab="...">`
|
|
482
|
-
is the whole markup. The burger is the worst of the five to get wrong:
|
|
483
|
-
below the collapse breakpoint it is the only route to the navigation.
|
|
484
|
-
`mw-tile` is the same rule from the other side: the class paints a surface
|
|
485
|
-
on anything, but the hand cursor, the focus ring and the tap handling only
|
|
486
|
-
come with `<a class="mw-tile">` or `<button class="mw-tile">`. On a `<div>`
|
|
487
|
-
you get the look and nothing a keyboard can reach.
|
|
488
|
-
If you build your own clickable thing: the element decides whether anyone
|
|
489
|
-
without a mouse can use it, the class only decides how it looks.
|
|
490
|
-
28. **A link in running text is `mw-link`, not `mw-btn mw-btn-link`.** Since
|
|
491
|
-
4.13.0 there is a class for exactly that. `mw-btn` is `inline-flex` with
|
|
492
|
-
`min-height: var(--mw-control-height)`, so a link written that way pulls its
|
|
493
|
-
own line up to 2.125rem while every line around it keeps the paragraph's
|
|
494
|
-
height - in a footer disclaimer at `font-size: sm` that is nearly double,
|
|
495
|
-
and it reads as a layout bug. `mw-p-0` is not the fix it looks like: the
|
|
496
|
-
height does it, not the padding. `mw-link` is the same look without the
|
|
497
|
-
control height and works on an `<a>` and a `<button>` alike.
|
|
498
|
-
`mw-btn mw-btn-link` stays right where the link really is one of several
|
|
499
|
-
buttons and has to line up with them - a card's actions, a button bar.
|
|
500
|
-
29. **`mw-parallax-sticky` goes on the section, not on the hero.** Sticky pins
|
|
501
|
-
inside its parent, and the rule that lifts the page above the pinned picture
|
|
502
|
-
reaches that content as a _sibling_. Put the class on the hero itself and
|
|
503
|
-
nothing pins and nothing covers - no error, no effect, and the picture shows
|
|
504
|
-
through every transparent section below. `mw-parallax` and the
|
|
505
|
-
`mw-parallax-media` child stay where the image is: on the container. Same
|
|
506
|
-
split for `mw-parallax-slow`, and `--mw-parallax-slow-travel` goes with the
|
|
507
|
-
class on the section - on the inner block it never reaches the animation.
|
|
508
|
-
That same sibling rule also puts an upward shadow on the one section
|
|
509
|
-
directly after the block, so the overlap reads as a surface and not a cut.
|
|
510
|
-
It sits at `:where()` weight, so a plain `box-shadow` of your own on that
|
|
511
|
-
section replaces it.
|
|
512
|
-
30. **A stored theme needs a script in the `<head>`.** `main.js` runs at the
|
|
513
|
-
end of the body, so a reader whose choice differs from the OS sees the
|
|
514
|
-
other theme for one frame. Five inline lines in the head apply it before
|
|
515
|
-
the first paint - the snippet is in `references/javascript.md`. The theme
|
|
516
|
-
classes live on `<html>` for exactly this reason.
|
|
517
|
-
31. **`viewport-fit=cover` belongs in the viewport meta.** The container
|
|
518
|
-
gutter, the mobile nav panel and the modal padding all budget for the
|
|
519
|
-
cutout with `env(safe-area-inset-*)`, and iOS resolves every one of those
|
|
520
|
-
to `0` without it - on a notched phone the content then sits under the
|
|
521
|
-
rounded corner. Nothing errors, which is why the shipped JS writes a
|
|
522
|
-
console warning on localhost when the meta is missing.
|
|
523
|
-
32. **Half the layout reads its own width, not the viewport.** `mw-card`,
|
|
524
|
-
`mw-tile`, `mw-stepper`, both timelines and - since 5.13.0 -
|
|
525
|
-
`mw-gallery-container` and `mw-image-slider` are `@container` queries, so
|
|
526
|
-
any of them in a half-width column takes its narrow layout there while the
|
|
527
|
-
window is still a desktop. Two consequences: the query only reaches
|
|
528
|
-
_descendants_, which is why the gallery wrapper around `mw-gallery`,
|
|
529
|
-
`mw-gallery-desc` and `mw-gallery-dots` cannot be dropped; and
|
|
530
|
-
`container-type: inline-size` computes the width as if the element were
|
|
531
|
-
empty, so one dropped into a flex or grid slot needs a width - the
|
|
532
|
-
framework sets `width: 100%` on its own containers already.
|