maverick-wave 4.3.0 → 4.4.1

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 (71) hide show
  1. package/.claude/skills/maverick-wave/SKILL.md +5 -3
  2. package/.claude/skills/maverick-wave/examples/angular-form.md +4 -0
  3. package/.claude/skills/maverick-wave/examples/static-landing-page.md +1 -1
  4. package/.claude/skills/maverick-wave/references/forms.md +27 -0
  5. package/.claude/skills/maverick-wave/references/theming.md +91 -67
  6. package/CHANGELOG.md +16 -0
  7. package/CLAUDE.md +10 -10
  8. package/README.md +109 -31
  9. package/maverick-wave.min.css +2 -2
  10. package/package.json +2 -2
  11. package/scripts/verify.js +13 -7
  12. package/src/assets/header-logo.svg +4 -4
  13. package/src/js/main.js +3 -3
  14. package/src/partials/accordions-container.html +9 -9
  15. package/src/partials/blog-posts-container.html +1 -1
  16. package/src/partials/buttons-container.html +1 -1
  17. package/src/partials/colors-container.html +75 -3
  18. package/src/partials/footer-container.html +3 -3
  19. package/src/partials/form-elements-container.html +98 -0
  20. package/src/partials/form-field-container.html +20 -4
  21. package/src/partials/get-started-container.html +36 -33
  22. package/src/partials/header-utilities-container.html +1 -1
  23. package/src/partials/modals-container.html +1 -1
  24. package/src/partials/ratings-container.html +1 -1
  25. package/src/partials/segmented-container.html +2 -2
  26. package/src/partials/tables-container.html +4 -4
  27. package/src/partials/tabs-container.html +7 -6
  28. package/src/partials/tags-container.html +1 -1
  29. package/src/partials/timelines-container.html +5 -5
  30. package/src/partials/utilities-container.html +1 -1
  31. package/src/scss/abstracts/_variables.scss +158 -46
  32. package/src/scss/base/_base.scss +1 -1
  33. package/src/scss/base/_typography.scss +2 -2
  34. package/src/scss/components/_alerts.scss +2 -2
  35. package/src/scss/components/_avatars.scss +2 -2
  36. package/src/scss/components/_blog-post.scss +5 -5
  37. package/src/scss/components/_breadcrumbs.scss +3 -3
  38. package/src/scss/components/_button-bar.scss +4 -4
  39. package/src/scss/components/_buttons.scss +6 -6
  40. package/src/scss/components/_calendar.scss +10 -10
  41. package/src/scss/components/_cards.scss +2 -2
  42. package/src/scss/components/_divider.scss +3 -3
  43. package/src/scss/components/_empty-state.scss +4 -4
  44. package/src/scss/components/_gallery.scss +1 -1
  45. package/src/scss/components/_info.scss +3 -3
  46. package/src/scss/components/_kanban.scss +12 -12
  47. package/src/scss/components/_lists.scss +12 -12
  48. package/src/scss/components/_localhost-indicator.scss +2 -2
  49. package/src/scss/components/_meta-info.scss +1 -1
  50. package/src/scss/components/_ratings.scss +1 -1
  51. package/src/scss/components/_segmented.scss +3 -3
  52. package/src/scss/components/_spinners.scss +10 -10
  53. package/src/scss/components/_stepper.scss +4 -4
  54. package/src/scss/components/_tabs.scss +5 -5
  55. package/src/scss/components/_techstack-bucket.scss +2 -2
  56. package/src/scss/components/_timelines.scss +10 -10
  57. package/src/scss/form-elements/_checkbox.scss +1 -1
  58. package/src/scss/form-elements/_form.scss +4 -4
  59. package/src/scss/form-elements/_index.scss +1 -0
  60. package/src/scss/form-elements/_input-group.scss +1 -1
  61. package/src/scss/form-elements/_input.scss +3 -3
  62. package/src/scss/form-elements/_login.scss +2 -2
  63. package/src/scss/form-elements/_prefilled.scss +65 -0
  64. package/src/scss/form-elements/_select.scss +2 -2
  65. package/src/scss/form-elements/_slider.scss +1 -1
  66. package/src/scss/form-elements/_textarea.scss +2 -2
  67. package/src/scss/layout/_footer.scss +3 -3
  68. package/src/scss/layout/_header.scss +5 -5
  69. package/src/scss/layout/_section.scss +5 -5
  70. package/src/scss/utilities/_flex.scss +1 -1
  71. package/src/scss/utilities/_text.scss +6 -6
@@ -186,7 +186,8 @@ Everything below is documented in `references/components.md` unless marked other
186
186
 
187
187
  **Forms** (`references/forms.md`) `mw-field` · `mw-input` · `mw-select` ·
188
188
  `mw-textarea` · `mw-checkbox` · `mw-radio` · `mw-toggle` · `mw-slider` ·
189
- `mw-input-group` · `mw-form` / `mw-form-group` / `mw-form-actions` · `mw-login`
189
+ `mw-input-group` · `mw-prefilled` · `mw-form` / `mw-form-group` /
190
+ `mw-form-actions` · `mw-login`
190
191
 
191
192
  **Layout** (`references/layout.md`) `mw-main` · `mw-container` · `mw-content` ·
192
193
  `mw-section` · `mw-page-header` · `mw-grid-*` · `mw-row-split` · `mw-hero` ·
@@ -229,8 +230,9 @@ text
229
230
  backgrounds and borders are derived with `color-mix()` at runtime. Setting
230
231
  `--mw-primary-color-hover` by hand is usually a sign the base token was not
231
232
  set.
232
- 10. **Browser floor: `color-mix()`** - Chrome 111+, Safari 16.2+, Firefox 113+.
233
- Older browsers get no colours at all, not merely worse ones.
233
+ 10. **Browser floor: `color-mix()` and `oklch(from ...)`** - Chrome 119+,
234
+ Safari 16.4+, Firefox 128+. Both carry the derived tones, so older browsers
235
+ get no colours at all, not merely worse ones.
234
236
  11. **Touch targets grow on their own.** On `pointer: coarse` or below 768px,
235
237
  `mw-btn-sm`, `mw-input-sm`, `mw-select-sm` and `mw-textarea-sm` get a 2.5rem
236
238
  minimum height, a tab 2.75rem, a calendar day 44px. `mw-btn-mini` keeps its
@@ -238,6 +238,10 @@ export class ProjectFormComponent {
238
238
  container - use `mw-form-element-error` instead.
239
239
  - **`disabled`/`readonly` are attributes**, not classes. With reactive forms use
240
240
  `control.disable()`; the muted look comes from the `:disabled` selector.
241
+ - **Prefilled values** take `mw-prefilled` on the control, not on the wrapper.
242
+ In an edit form that starts from `patchValue()`, bind it to your own flag:
243
+ `[class.mw-prefilled]="loaded() && !form.controls.name.dirty"`. Repeat the
244
+ information in the `mw-field-hint`, the marker itself is decoration.
241
245
  - **The slider needs two bindings**: `data-value` for the badge text,
242
246
  `--value` for the filled part of the track.
243
247
  - **A spinner inside a button** needs its shape class (`mw-spinner-border`) plus
@@ -26,7 +26,7 @@ wired up by hand.
26
26
  /* Brand colours - one token per family, the rest is derived */
27
27
  :root {
28
28
  --mw-primary-color: #0f766e;
29
- --mw-secondary-color: #f39c12;
29
+ --mw-secondary-color: #b45309;
30
30
  --mw-hero-background: url('/assets/hero.jpg');
31
31
  }
32
32
  </style>
@@ -170,6 +170,33 @@ Sizes: `mw-textarea-sm`, `mw-textarea-lg`. Resizing is off by default; enable it
170
170
  with `mw-textarea-resizable`, `mw-textarea-resizable-vertical` or
171
171
  `mw-textarea-resizable-horizontal`.
172
172
 
173
+ ## Prefilled values
174
+
175
+ `mw-prefilled` marks a control whose value did not come from the user in this
176
+ session - loaded from an existing record, restored from a draft, filled with a
177
+ default. It draws a small triangle into the top left corner of the control.
178
+
179
+ ```html
180
+ <input type="text" class="mw-input mw-prefilled" value="Max Mustermann" />
181
+ <select class="mw-select mw-select-sm mw-prefilled">
182
+ ...
183
+ </select>
184
+ <textarea class="mw-textarea mw-prefilled" rows="3"></textarea>
185
+ ```
186
+
187
+ - Works on `mw-input`, `mw-select` and `mw-textarea`, and goes on the control
188
+ itself, not on the `mw-field` wrapper - so it also works in an input group or
189
+ on a standalone control.
190
+ - The triangle follows the size modifier (`mw-input-sm`, `mw-select-lg`, ...)
191
+ and stays visible on `readonly` and `disabled` controls.
192
+ - Colour is `--mw-info-color`, deliberately not primary or danger: it is an
193
+ information about the value, not a state or an error.
194
+ - Decoration only. Screen readers do not see it, so put the same information in
195
+ an `mw-field-hint` and reference it with `aria-describedby`.
196
+ - It is drawn as a background layer, not a pseudo element (`input` and `select`
197
+ never render `::before`/`::after`). A rule that sets the `background`
198
+ shorthand on the same control wipes it - use `background-color` there.
199
+
173
200
  ## Checkbox
174
201
 
175
202
  The native input is hidden; `mw-checkbox-box` is the visible control, so the
@@ -2,11 +2,15 @@
2
2
 
3
3
  ## The model
4
4
 
5
- Twelve colours are configured, everything else is derived from them **at
6
- runtime** with `color-mix()`. Overriding a root token therefore retunes its
7
- whole family - hover tone, translucent backgrounds, borders. That is the
8
- difference to pre-3.4.0, where derived values were baked in at compile time and
9
- a palette switch meant setting 41 variables.
5
+ Thirteen colours are configured, everything else is derived from them **at
6
+ runtime** with `color-mix()` and relative colour syntax. Overriding a root token
7
+ therefore retunes its whole family - hover tone, translucent backgrounds,
8
+ borders, the theme's surface stack, the ink variant the dark theme needs. That is
9
+ the difference to pre-3.4.0, where derived values were baked in at compile time
10
+ and a palette switch meant setting 41 variables.
11
+
12
+ Browser floor for that: `color-mix()` **and** `oklch(from ...)` - Chrome 119+,
13
+ Safari 16.4+, Firefox 128+.
10
14
 
11
15
  ```css
12
16
  /* loaded after maverick-wave.min.css */
@@ -14,21 +18,22 @@ a palette switch meant setting 41 variables.
14
18
  --mw-primary-color: #0f766e; /* also retunes hover, backgrounds, border accent */
15
19
  --mw-secondary-color: #f39c12;
16
20
 
17
- --mw-success-color: #218838;
18
- --mw-warning-color: #d4a310;
19
- --mw-danger-color: #c82333;
20
- --mw-info-color: #17a2b8;
21
+ --mw-success-color: #157f4b;
22
+ --mw-warning-color: #bda817;
23
+ --mw-danger-color: #c42b1c;
24
+ --mw-info-color: #14618f;
21
25
 
22
- --mw-gray-color: #565656;
26
+ --mw-gray-color: #5a6478;
23
27
 
24
- --mw-dark-page-background: #0b111a;
25
- --mw-dark-text-color: #d6dbdf;
26
- --mw-light-page-background: #d2d1e1;
27
- --mw-light-text-color: #1a1a1d;
28
+ --mw-dark-page-background: #171f30;
29
+ --mw-dark-text-color: #e8ecf1;
30
+ --mw-light-page-background: #f2f5f8;
31
+ --mw-light-text-color: #0c1119;
28
32
 
29
- --mw-form-elements-background: #efefef;
33
+ --mw-form-elements-background: #f4f7fb;
30
34
 
31
- /* text on every solid coloured surface */
35
+ /* text on every solid coloured surface, and the one token that cannot be
36
+ derived: light brand colours need a dark label, dark ones a light label */
32
37
  --mw-accent-text-color: #ffffff;
33
38
 
34
39
  --mw-font-family-base: 'Inter', sans-serif;
@@ -37,48 +42,55 @@ a palette switch meant setting 41 variables.
37
42
 
38
43
  ## Which token for what
39
44
 
40
- | Token | Role |
41
- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
42
- | `--mw-primary-color` | Brand colour: primary buttons, table headers, focus rings, active states |
43
- | `--mw-primary-color-hover` | Solid hover surface (derived: base + 18% black) |
44
- | `--mw-primary-background` | 20% tint - focus halo, scrollbar tracks |
45
- | `--mw-primary-background-hover` | 50% tint - row and list hover |
46
- | `--mw-primary-info-background` | 70% tint - alert and info surfaces |
47
- | `--mw-border-accent` | Translucent accent **line**: panel rules, dividers, tab underlines |
48
- | `--mw-secondary-*` | Same set for the second brand colour |
49
- | `--mw-success/warning/danger/info-color` | Status colours, each with `-color-hover`, `-info-background`, `-info-background-hover` |
50
- | `--mw-accent-text-color` | Text on any solid coloured surface (buttons, table/panel headers, badges, stepper dots) |
51
- | `--mw-gray-color` | Neutral foreground: muted icons, tooltips |
52
- | `--mw-gray-background` | Subtle neutral surface (20% alpha): zebra rows, disabled fields, tracks, skeletons |
53
- | `--mw-surface-muted` | Alias of `--mw-gray-background` under the name you reach for: a slightly set-off area _inside_ a card - hint block, framed paragraph, form summary |
54
- | `--mw-overlay-background` | Heavy scrim (60%) behind modals and blocking spinners |
55
- | `--mw-page-background`, `--mw-card-background`, `--mw-footer-background`, `--mw-border`, `--mw-shadow`, `--mw-text-color`, `--mw-text-muted-color`, `--mw-hero-overlay-background` | The **active theme** - aliases pointing at the `--mw-dark-*` or `--mw-light-*` set |
56
- | `--mw-header-*` | Header chrome: `background`, `text-color`, `navbar-list-color`, `navbar-list-active-color`, `burgerbutton-color`, `border` - dark in both themes |
57
- | `--mw-form-elements-background`, `--mw-form-elements-color` | Form controls stay light in both themes and therefore have their own pair |
58
- | `--mw-font-family-base`, `-heading`, `-mono` | Font stacks - system stacks by default (`-mono` leads with Fira Code); no font is bundled. Configurable in SCSS, see below |
59
- | `--mw-hero-background` | Hero image (`url(...)`) |
60
- | `--mw-transition` | Global transition (`all 0.3s ease`) |
61
- | `--mw-card-img-height` | Per-card image height (default `210px`; `mw-card-lg`/`-xl` set it to 340px/480px) |
62
- | `--mw-card-addon-color` | Background of `mw-card-badge` / `mw-card-ribbon`; the `mw-card-addon-*` classes set it, override it for a custom colour |
63
- | `--mw-table-scroll-height` | Per-table height cap for `mw-table-responsive-scroll` |
64
- | `--mw-kanban-background`, `--mw-kanban-lane-border`, `--mw-kanban-column-min-height` | Per-board surface, lane border and lane floor (120px, 90px on `mw-kanban-compact`) |
65
- | `--mw-container-width`, `--mw-container-width-sm` | Content width of `mw-container` (`min(1200px, 89%)`, below 576px a 1rem gutter) |
66
- | `--mw-section-padding-block` | Top/bottom rhythm of `mw-section` (1.75rem) |
67
- | `--mw-calendar-dot` | Colour of a single calendar dot - set it per dot or per cell; the `mw-calendar-dot-*` classes are presets for it |
68
- | `--mw-scroll-hint-cover` | Colour the scroll hint on a tab bar fades into. Preset to the page, re-pointed to the card background inside `mw-card`, `mw-panel`, `mw-modal`, `mw-tile`, `mw-calendar` |
69
- | `--mw-internal-theme-mode` | Read-only: what `$mw-theme-mode` was compiled to |
70
-
71
- The four above are the knobs a good default cannot settle, because the right
72
- answer differs per project: what reads as generous on a landing page costs
73
- visible content in an application with a sticky header.
45
+ | Token | Role |
46
+ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
47
+ | `--mw-primary-color` | Brand colour as a **fill**: primary buttons, table headers, bars, badges - the label on top is `--mw-accent-text-color` |
48
+ | `--mw-primary-text-color` | Brand colour as **ink** on a theme surface: text, icons, focus rings, accent borders. Derived by clamping OKLch lightness (`max(l, .68)` on dark, `min(l, .55)` on light), so a colour already in range is used untouched |
49
+ | `--mw-primary-color-hover` | Solid hover surface (derived: base + `$hover-shift` black, in both themes) |
50
+ | `--mw-primary-background` | 20% tint - focus halo, alert/badge/tag surface, scrollbar tracks |
51
+ | `--mw-primary-background-hover` | 45% tint - row and list hover |
52
+ | `--mw-primary-info-background` | Alias of `--mw-primary-background`, so a component can interpolate one name across all six colours |
53
+ | `--mw-border-accent` | Translucent accent **line**: panel rules, dividers, tab underlines. Theme-aware (70% of `--mw-*-text-color`) |
54
+ | `--mw-secondary-*` | Same set for the second brand colour |
55
+ | `--mw-success/warning/danger/info-color` | Status colours, each with `-text-color`, `-color-hover`, `-info-background`, `-info-background-hover` |
56
+ | `--mw-accent-text-color` | Text on any solid coloured surface (buttons, table/panel headers, badges, stepper dots) |
57
+ | `--mw-gray-color` | Neutral foreground: muted icons, tooltips |
58
+ | `--mw-gray-background` | Subtle neutral surface (20% alpha): zebra rows, disabled fields, tracks, skeletons |
59
+ | `--mw-surface-muted` | Alias of `--mw-gray-background` under the name you reach for: a slightly set-off area _inside_ a card - hint block, framed paragraph, form summary |
60
+ | `--mw-overlay-background` | Heavy scrim (60%) behind modals and blocking spinners |
61
+ | `--mw-page-background`, `--mw-card-background`, `--mw-footer-background`, `--mw-border`, `--mw-shadow`, `--mw-text-color`, `--mw-text-muted-color`, `--mw-hero-overlay-background` | The **active theme** - aliases pointing at the `--mw-dark-*` or `--mw-light-*` set |
62
+ | `--mw-header-*` | Header chrome: `background`, `text-color`, `navbar-list-color`, `navbar-list-active-color`, `burgerbutton-color`, `border` - dark in both themes |
63
+ | `--mw-form-elements-background`, `--mw-form-elements-color` | Form controls stay light in both themes and therefore have their own pair |
64
+ | `--mw-font-family-base`, `-heading`, `-mono` | Font stacks - system stacks by default (`-mono` leads with Fira Code); no font is bundled. Configurable in SCSS, see below |
65
+ | `--mw-hero-background` | Hero image (`url(...)`) |
66
+ | `--mw-transition` | Global transition (`all 0.3s ease`) |
67
+ | `--mw-card-img-height` | Per-card image height (default `210px`; `mw-card-lg`/`-xl` set it to 340px/480px) |
68
+ | `--mw-card-addon-color` | Background of `mw-card-badge` / `mw-card-ribbon`; the `mw-card-addon-*` classes set it, override it for a custom colour |
69
+ | `--mw-table-scroll-height` | Per-table height cap for `mw-table-responsive-scroll` |
70
+ | `--mw-kanban-background`, `--mw-kanban-lane-border`, `--mw-kanban-column-min-height` | Per-board surface, lane border and lane floor (120px, 90px on `mw-kanban-compact`) |
71
+ | `--mw-container-width`, `--mw-container-width-sm` | Content width of `mw-container` (`min(1200px, 89%)`, below 576px a 1rem gutter) |
72
+ | `--mw-section-padding-block` | Top/bottom rhythm of `mw-section` (1.75rem) |
73
+ | `--mw-calendar-dot` | Colour of a single calendar dot - set it per dot or per cell; the `mw-calendar-dot-*` classes are presets for it |
74
+ | `--mw-scroll-hint-cover` | Colour the scroll hint on a tab bar fades into. Preset to the page, re-pointed to the card background inside `mw-card`, `mw-panel`, `mw-modal`, `mw-tile`, `mw-calendar` |
75
+ | `--mw-internal-theme-mode` | Read-only: what `$mw-theme-mode` was compiled to |
76
+
77
+ `--mw-container-width`, `--mw-container-width-sm` and
78
+ `--mw-section-padding-block` are the knobs a good default cannot settle, because
79
+ the right answer differs per project: what reads as generous on a landing page
80
+ costs visible content in an application with a sticky header.
74
81
 
75
82
  Two rules that prevent most colour bugs:
76
83
 
77
- 1. **Surfaces are opaque, lines are translucent.** For a coloured surface use
78
- `--mw-*-color` / `--mw-*-color-hover`; for a rule or outline use
79
- `--mw-border-accent` or `--mw-border`.
84
+ 1. **Fill or ink.** A colour that _fills_ something is `--mw-*-color`; a colour
85
+ _drawn on_ a theme surface - text, icon, focus ring, accent border, thin
86
+ divider - is `--mw-*-text-color`. A colour picked to carry a label is by
87
+ definition unreadable on the page it sits on, so ink is always the
88
+ `-text-color` variant. For a generic rule or outline use `--mw-border-accent`
89
+ or `--mw-border`.
80
90
  2. **`--mw-text-muted-color` is only for text on theme surfaces** (cards, page
81
- background) - it follows the theme. On a colour surface that stays the same
91
+ background) - it follows the theme. It is a true gray with `$muted-tint`
92
+ (12%) of the primary mixed in, not a stepped-back text colour, so it stays
93
+ gray no matter how tinted the palette is. On a colour surface that stays the same
82
94
  in both themes it is always wrong: use `--mw-accent-text-color`, or `opacity`
83
95
  for a disabled look.
84
96
 
@@ -86,6 +98,11 @@ Two rules that prevent most colour bugs:
86
98
 
87
99
  - Dark is the base. Light is applied by putting `mw-theme-light` on `<body>` -
88
100
  that class only re-points the theme aliases at the `--mw-light-*` set.
101
+ - Card, footer and border are derived from the page background by scaling its
102
+ OKLch lightness and chroma by one factor. A card steps **away from the text
103
+ colour** - darker than the page in the dark theme, lighter in the light one.
104
+ A near-black `--mw-dark-page-background` leaves no headroom underneath and
105
+ cards collapse into it; keep it around OKLch lightness 0.24.
89
106
  - Header, footer chrome and form controls deliberately stay dark/light
90
107
  respectively in both themes.
91
108
  - Persisting the choice, the toggle UI and the initial class are the
@@ -106,17 +123,23 @@ effect, because the root colours are declared with `!default`.
106
123
  $mw-theme-mode: 'switchable',
107
124
  // 'switchable' | 'dark' | 'light'
108
125
  $primary-color: #0f766e,
109
- $secondary-color: #f39c12,
110
- $success-color: #218838,
111
- $warning-color: #d4a310,
112
- $danger-color: #c82333,
113
- $info-color: #17a2b8,
114
- $gray-color: #565656,
115
- $dark-background: #0b111a,
116
- $dark-text-color: #d6dbdf,
117
- $light-background: #d2d1e1,
118
- $light-text-color: #1a1a1d,
119
- $form-elements-background: #efefef,
126
+ $secondary-color: #b45309,
127
+ $success-color: #15803d,
128
+ $warning-color: #a16207,
129
+ $danger-color: #b91c1c,
130
+ $info-color: #0e7490,
131
+ $gray-color: #64748b,
132
+ $dark-background: #172127,
133
+ $dark-text-color: #e8eef0,
134
+ $light-background: #f2f6f7,
135
+ $light-text-color: #172127,
136
+ $form-elements-background: #f5f9fa,
137
+ $accent-text-color: #f2fafa,
138
+ // the three derivation knobs, all optional
139
+ $hover-shift: 15%,
140
+ $ink-lightness-dark: 0.68,
141
+ $ink-lightness-light: 0.55,
142
+ $muted-tint: 12%,
120
143
  $mw-hero-image: url('/assets/hero.jpg'),
121
144
  $font-family-base: (
122
145
  'Inter',
@@ -162,7 +185,7 @@ they are all `var()` references anyway:
162
185
 
163
186
  ## Importing only what you need
164
187
 
165
- The full stylesheet is ~147 kB raw / ~22.5 kB gzipped. Marketing components
188
+ The full stylesheet is ~172 kB raw / ~26 kB gzipped. Marketing components
166
189
  (`blog-post`, `gallery`, `content-slider`, `techstack-bucket`, `tiles`,
167
190
  `coming-soon`, `ratings`, `home`, `hero`) are dead weight in an application, and
168
191
  Angular bundle budgets notice.
@@ -201,7 +224,8 @@ colourless.
201
224
  @use 'maverick-wave/src/scss/utilities';
202
225
  ```
203
226
 
204
- That set compiles to ~98 kB raw / ~15 kB gzipped - a third off the full build.
227
+ That set compiles to ~77 kB raw / ~13 kB gzipped - well under half the full
228
+ build.
205
229
 
206
230
  Details worth knowing:
207
231
 
package/CHANGELOG.md CHANGED
@@ -6,6 +6,22 @@ Patch releases are only for test purposes - here I only document major and minor
6
6
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
7
7
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [4.5.0] - 2026-08-21
10
+
11
+ ### Changed
12
+
13
+ - new color concept and new default color palette
14
+
15
+ ## [4.4.0] - 2026-08-20
16
+
17
+ ### Added
18
+
19
+ - prefilled marker for form controls (`mw-prefilled`)
20
+
21
+ ### Fixed
22
+
23
+ - disabled select lost its arrow
24
+
9
25
  ## [4.3.0] - 2026-08-19
10
26
 
11
27
  ### Fixed
package/CLAUDE.md CHANGED
@@ -21,21 +21,21 @@ There are no test or lint scripts.
21
21
 
22
22
  ## Architecture
23
23
 
24
- **Build pipeline** `gulpfile.js` orchestrates everything: SCSS compilation (autoprefixed, minified), JS minification via Terser, HTML templating via `gulp-file-include`, asset copying, and build-info injection (`{{VERSION}}`, `{{LAST_BUILD_DATE}}`, `{{LAST_BUILD_YEAR}}` placeholders replaced in HTML at build time).
24
+ **Build pipeline** - `gulpfile.js` orchestrates everything: SCSS compilation (autoprefixed, minified), JS minification via Terser, HTML templating via `gulp-file-include`, asset copying, and build-info injection (`{{VERSION}}`, `{{LAST_BUILD_DATE}}`, `{{LAST_BUILD_YEAR}}` placeholders replaced in HTML at build time).
25
25
 
26
26
  **SCSS layers** (`src/scss/`) follow an ITCSS-inspired structure:
27
27
 
28
- - `abstracts/` CSS custom properties, mixins, SCSS functions (color variant generation)
29
- - `base/` Reset, element defaults, typography
30
- - `components/` Self-contained component styles (25+ files, one per component)
31
- - `form-elements/` Form input/select/checkbox-specific styles
32
- - `layout/` Grid, container, header/footer, section
33
- - `utilities/` Spacing, flex, display utility classes
34
- - `main.scss` Entry point using `@use`/`@forward` (not `@import`)
28
+ - `abstracts/` - CSS custom properties, mixins, SCSS functions (color variant generation)
29
+ - `base/` - Reset, element defaults, typography
30
+ - `components/` - Self-contained component styles (25+ files, one per component)
31
+ - `form-elements/` - Form input/select/checkbox-specific styles
32
+ - `layout/` - Grid, container, header/footer, section
33
+ - `utilities/` - Spacing, flex, display utility classes
34
+ - `main.scss` - Entry point using `@use`/`@forward` (not `@import`)
35
35
 
36
- **JavaScript** (`src/js/main.js`) Single file. All components auto-initialize on `DOMContentLoaded`. Includes: gallery slider, theme toggle (persisted to localStorage), accordion, mobile nav, progress bar (IntersectionObserver), scroll spy, tabs, alerts/toasts, modals, range inputs.
36
+ **JavaScript** (`src/js/main.js`) - Single file. All components auto-initialize on `DOMContentLoaded`. Includes: gallery slider, theme toggle (persisted to localStorage), accordion, mobile nav, progress bar (IntersectionObserver), scroll spy, tabs, alerts/toasts, modals, range inputs.
37
37
 
38
- **HTML showcase** (`index.html` + `src/partials/`) The top-level `index.html` uses `@@include()` syntax to pull in 40+ partials from `src/partials/`. These compile into `dist/index.html`.
38
+ **HTML showcase** (`index.html` + `src/partials/`) - The top-level `index.html` uses `@@include()` syntax to pull in 40+ partials from `src/partials/`. These compile into `dist/index.html`.
39
39
 
40
40
  ## Naming Conventions
41
41
 
package/README.md CHANGED
@@ -38,12 +38,12 @@ The result is a framework that balances utility with simplicity, offering develo
38
38
  <title>My MaverickWave Project</title>
39
39
  <link
40
40
  rel="stylesheet"
41
- href="https://cdn.jsdelivr.net/npm/maverick-wave@3.7.0/maverick-wave.min.css"
41
+ href="https://cdn.jsdelivr.net/npm/maverick-wave@4.4.1/maverick-wave.min.css"
42
42
  />
43
43
  </head>
44
44
  <body>
45
45
  <!-- Your content here -->
46
- <script src="https://cdn.jsdelivr.net/npm/maverick-wave@3.7.0/maverick-wave.min.js"></script>
46
+ <script src="https://cdn.jsdelivr.net/npm/maverick-wave@4.4.1/maverick-wave.min.js"></script>
47
47
  </body>
48
48
  </html>
49
49
  ```
@@ -63,33 +63,35 @@ Download `maverick-wave.min.css` and `maverick-wave.min.js` from the [latest rel
63
63
 
64
64
  ### CSS Custom Properties
65
65
 
66
- There are thirteen root color tokens. Everything else hover tones, translucent
67
- backgrounds, borders, muted text is derived from them at runtime with
66
+ There are thirteen root color tokens. Everything else - hover tones, translucent
67
+ backgrounds, borders, muted text - is derived from them at runtime with
68
68
  `color-mix()`, so overriding a root token is enough. Load your stylesheet
69
69
  **after** `maverick-wave.min.css`:
70
70
 
71
71
  ```css
72
72
  :root {
73
73
  /* brand */
74
- --mw-primary-color: #e94560;
75
- --mw-secondary-color: #f39c12;
74
+ --mw-primary-color: #0f766e;
75
+ --mw-secondary-color: #b45309;
76
76
 
77
77
  /* status */
78
- --mw-success-color: #218838;
79
- --mw-warning-color: #d4a310;
80
- --mw-danger-color: #c82333;
81
- --mw-info-color: #17a2b8;
78
+ --mw-success-color: #15803d;
79
+ --mw-warning-color: #a16207;
80
+ --mw-danger-color: #b91c1c;
81
+ --mw-info-color: #0e7490;
82
82
 
83
83
  /* neutrals and themes */
84
- --mw-gray-color: #565656;
85
- --mw-dark-page-background: #1a1a2e;
86
- --mw-dark-text-color: #d6dbdf;
87
- --mw-light-page-background: #f8f9fa;
88
- --mw-light-text-color: #1a1a1d;
89
- --mw-form-elements-background: #ffffff;
90
-
91
- /* text on solid colored surfaces: buttons, table and panel headers */
92
- --mw-accent-text-color: #ffffff;
84
+ --mw-gray-color: #64748b;
85
+ --mw-dark-page-background: #172127;
86
+ --mw-dark-text-color: #e8eef0;
87
+ --mw-light-page-background: #f2f6f7;
88
+ --mw-light-text-color: #172127;
89
+ --mw-form-elements-background: #f5f9fa;
90
+
91
+ /* text on every solid colored surface: buttons, table and panel headers.
92
+ The one token that cannot be derived - a light brand color needs a dark
93
+ label, a dark one a light label. Set it opposite your --mw-primary-color. */
94
+ --mw-accent-text-color: #f2fafa;
93
95
 
94
96
  --mw-font-family-base: 'Your Font Name', sans-serif;
95
97
  }
@@ -97,11 +99,82 @@ backgrounds, borders, muted text — is derived from them at runtime with
97
99
 
98
100
  Setting `--mw-primary-color` alone also retunes `--mw-primary-color-hover`,
99
101
  `--mw-primary-background`, `--mw-primary-background-hover`,
100
- `--mw-primary-info-background` and `--mw-border-accent`. The same holds for
102
+ `--mw-primary-text-color` and `--mw-border-accent`. The same holds for
101
103
  `--mw-dark-page-background`, which drives the dark card, footer and border
102
104
  tones. Each derived token can still be overridden individually if you want to
103
105
  break out of the scale.
104
106
 
107
+ > The derivation needs `color-mix()` **and** relative colour syntax
108
+ > (`oklch(from ...)`): Chrome 119+, Safari 16.4+, Firefox 128+. Older browsers
109
+ > get no colours at all, not merely worse ones.
110
+
111
+ ### Fill or ink
112
+
113
+ Every brand and status colour comes in two tokens, and picking the right one is
114
+ the whole trick:
115
+
116
+ - `--mw-primary-color` is the exact colour, for anything it **fills** - buttons,
117
+ badges, bars, progress. The label on top is `--mw-accent-text-color`.
118
+ - `--mw-primary-text-color` is the same colour tuned to the active theme, for
119
+ anything drawn **on** a theme surface - text, icons, focus rings, accent
120
+ borders and dividers.
121
+
122
+ The second one exists because a colour picked to carry a label is by definition
123
+ too dark or too light to be read _on_ the page it sits on. The ink token is
124
+ derived by clamping OKLch lightness and keeping hue and chroma:
125
+
126
+ ```css
127
+ --mw-dark-primary-text-color: oklch(
128
+ from var(--mw-primary-color) max(l, 0.68) c h
129
+ );
130
+ --mw-light-primary-text-color: oklch(
131
+ from var(--mw-primary-color) min(l, 0.55) c h
132
+ );
133
+ ```
134
+
135
+ That is a bound, not a target, which is what makes it work for any palette. A
136
+ dark brand colour gets lifted, a very light one gets deepened, and a colour
137
+ already inside the range passes through untouched - a neon green stays neon on
138
+ the dark page and only turns into a real green on the light one. The bounds are
139
+ `$ink-lightness-dark` and `$ink-lightness-light` in SCSS.
140
+ `--mw-secondary-text-color` and `--mw-success/warning/danger/info-text-color`
141
+ are derived the same way.
142
+
143
+ `--mw-text-muted-color` is built the other way round: a true gray at a fixed
144
+ lightness with `$muted-tint` (12%) of the primary colour mixed in, so the gray
145
+ belongs to the palette without carrying its saturation. Stepping the theme's
146
+ text colour back instead would hand its tint straight through - a mint white
147
+ page would end up with mint green secondary text. Set `$muted-tint: 0%` for a
148
+ neutral gray.
149
+
150
+ Tinted surfaces follow one rule as well: `--mw-*-background` is 20% of the
151
+ colour, `--mw-*-background-hover` 45%. Both stay close enough to the surface
152
+ underneath that `--mw-text-color` keeps working on top, which is what makes an
153
+ alert, badge or tag readable in either theme.
154
+
155
+ ### The surface stack
156
+
157
+ Card, footer and border are derived from the page background by scaling its
158
+ OKLch lightness _and_ chroma by one factor, keeping the hue:
159
+
160
+ ```css
161
+ --mw-dark-card-background: oklch(
162
+ from var(--mw-dark-page-background) calc(l * 0.75) calc(c * 0.75) h
163
+ );
164
+ ```
165
+
166
+ Both themes step a card **away from their text colour** - down into the dark
167
+ theme, up into the light one - so content always sits on the cleaner of the two
168
+ surfaces. Chroma rides along with lightness because that is what a hand-picked
169
+ stack does: a darker surface of the same hue carries less colour, not the same
170
+ colour at a lower lightness.
171
+
172
+ The one thing to know when picking `--mw-dark-page-background`: it needs
173
+ headroom underneath. On a near-black page the surfaces below it have nowhere to
174
+ go and cards collapse into the background, leaving only the border to separate
175
+ them. The default sits at OKLch lightness 0.24 for that reason. The factors sit
176
+ inline in `$dark-theme-colors` / `$light-theme-colors`, one per surface.
177
+
105
178
  ### SCSS Source
106
179
 
107
180
  For full control, clone the repository and integrate `src/scss/main.scss` into your Sass build (Dart Sass required). MaverickWave uses modern `@use`/`@forward` syntax. Pass your overrides through `with`:
@@ -114,14 +187,19 @@ For full control, clone the repository and integrate `src/scss/main.scss` into y
114
187
  $mw-theme-mode: 'switchable',
115
188
 
116
189
  // Override root colors
117
- $primary-color: #e94560,
118
- $secondary-color: #f39c12,
119
- $dark-background: #1f1f2e,
120
- $light-background: #f8f9fa
190
+ $primary-color: #0f766e,
191
+ $secondary-color: #b45309,
192
+ $dark-background: #172127,
193
+ $light-background: #f2f6f7,
194
+
195
+ // Optional: the three derivation knobs
196
+ $ink-lightness-dark: 0.68,
197
+ $ink-lightness-light: 0.55,
198
+ $muted-tint: 12%
121
199
  );
122
200
  ```
123
201
 
124
- > Plain variable assignments before `@use` have no effect the framework
202
+ > Plain variable assignments before `@use` have no effect - the framework
125
203
  > declares its root colors with `!default`, which only `@use ... with` feeds.
126
204
 
127
205
  ### Importing Only What You Need
@@ -133,7 +211,7 @@ have no use for the marketing components (`blog-post`, `gallery`,
133
211
  `home`), and Angular bundle budgets notice the difference.
134
212
 
135
213
  ```scss
136
- // styles.scss configuration first, then pick
214
+ // styles.scss - configuration first, then pick
137
215
  @use 'maverick-wave/src/scss/abstracts/variables' with (
138
216
  $primary-color: #0f766e
139
217
  );
@@ -154,7 +232,7 @@ have no use for the marketing components (`blog-post`, `gallery`,
154
232
  A typical application subset like the one above compiles to roughly 98 kB raw /
155
233
  15 kB gzipped, against 147 kB / 22.5 kB for the full build.
156
234
 
157
- > **`base` is not optional.** It carries the `:root` custom properties without
235
+ > **`base` is not optional.** It carries the `:root` custom properties - without
158
236
  > it every component renders without colors. If you bring your own reset, use
159
237
  > `@use 'maverick-wave/src/scss/base/base'` for the token block alone.
160
238
  > The `with (...)` configuration has to be the first statement in the file,
@@ -174,7 +252,7 @@ above):
174
252
  > are never initialized, and the theme toggle mutates the DOM behind Angular's
175
253
  > change detection. The behaviors it covers (accordion, tabs, modal close, mobile
176
254
  > nav, scroll spy, theme toggle, progress bars, sliders, alerts, galleries) are a
177
- > few lines each in a component the framework's state classes are the whole
255
+ > few lines each in a component - the framework's state classes are the whole
178
256
  > contract. Theme switching, for example, is a single class on `<body>`:
179
257
 
180
258
  ```typescript
@@ -183,7 +261,7 @@ document.body.classList.toggle('mw-theme-light', isLight);
183
261
  ```
184
262
 
185
263
  The `mw-field` wrapper groups label, control, hint and error. Bind the error
186
- state yourself the framework does not style Angular's `ng-invalid` /
264
+ state yourself - the framework does not style Angular's `ng-invalid` /
187
265
  `ng-touched` classes:
188
266
 
189
267
  ```html
@@ -202,8 +280,8 @@ state yourself — the framework does not style Angular's `ng-invalid` /
202
280
  </div>
203
281
  ```
204
282
 
205
- A complete usage guide for AI coding assistants every component, token,
206
- integration pattern and example ships with the package as a Claude Code skill
283
+ A complete usage guide for AI coding assistants - every component, token,
284
+ integration pattern and example - ships with the package as a Claude Code skill
207
285
  in `.claude/skills/maverick-wave/`.
208
286
 
209
287
  ## Development