@maggioli-design-system/magma-react 2.0.1 → 2.2.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/AGENTS.md ADDED
@@ -0,0 +1,72 @@
1
+ <!--
2
+ GENERATED FILE - do not edit by hand.
3
+ Source of truth: docs/agents/ in the magma monorepo.
4
+ Regenerate with: npm run sync.agent-docs (from the stencil package).
5
+ -->
6
+ # @maggioli-design-system/magma-react - agent install guide
7
+
8
+ > Version 2.2.0. You (the agent) are installing Magma into THIS project. Do not
9
+ > assume the setup - detect it from the project, then ask the user only for what you
10
+ > cannot infer. The detailed steps live in [`agents/install.md`](agents/install.md)
11
+ > (this target) and [`agents/assets.md`](agents/assets.md) (shared styles, fonts,
12
+ > icons). This package targets: **React / Next.js**.
13
+
14
+ ## Step 1 - detect (read, do not ask)
15
+
16
+ Inspect the consumer project before asking anything:
17
+
18
+ | What | Where to look |
19
+ | ---- | ------------- |
20
+ | Framework | `package.json` deps: `@angular/core` -> Angular, `react`/`next` -> React, else vanilla |
21
+ | Magma wrapper installed | presence of `magma-angular` / `magma-react` / `magma` in deps |
22
+ | Bundler / static dir | `angular.json` (Angular CLI assets), `vite.config.*`, `next.config.*` (`public/`), webpack |
23
+ | Tailwind + version | `tailwindcss` in deps: v4 -> the CSS imports, v3 -> the JS preset (see agents/assets.md) |
24
+ | SSR | `@angular/ssr` / Angular Universal, or Next App Router |
25
+ | Compatible versions | derive from the installed `@maggioli-design-system/magma` major (see matrix in install.md) |
26
+
27
+ ## Step 2 - ask only the gaps
28
+
29
+ Ask the user only what detection left undecided. Typical questions:
30
+
31
+ 1. **Icons**: use the prebuilt set (`@maggioli-design-system/svg-icons`) or do you need
32
+ **iconsauce** for tree-shaking / custom icons? Most consumers do NOT need iconsauce -
33
+ Magma already ships resolved SVGs; iconsauce is an internal build dependency. Only
34
+ add `@iconsauce/*` if the user wants their own icon pipeline.
35
+ 2. **Static assets path**: where are static files served from? This sets `mdsIconSvgPath`
36
+ and the SVG copy destination.
37
+ 3. **Dark mode / preferences**: needed? If yes, wire the preference classes and components.
38
+ 4. Confirm the version row if the installed major is ambiguous.
39
+
40
+ ## Step 3 - execute
41
+
42
+ 1. Install packages and the shared assets - see [`agents/install.md`](agents/install.md).
43
+ 2. Wire styles in the exact cascade-layer order - see [`agents/assets.md`](agents/assets.md).
44
+ 3. Copy the icon SVGs to the static path and set `mdsIconSvgPath`.
45
+ 4. Register components: import the Mds* components from '@maggioli-design-system/magma-react' (no defineCustomElements needed).
46
+
47
+ ## Step 4 - verify
48
+
49
+ Build the app and confirm an `mds-*` component renders and at least one icon loads from
50
+ the configured path. Report what was installed, the cascade order used, and the icon path.
51
+
52
+ ## Using the components
53
+
54
+ Once installed, do not guess component APIs or rules - read only the file you need:
55
+
56
+ | You need | Read |
57
+ | -------- | ---- |
58
+ | Which component to reach for | [`agents/components.md`](agents/components.md) - the catalogue, one line each |
59
+ | One component's API (props with allowed values, events, methods, slots, parts, CSS vars) | its `AGENTS.md`, linked from the catalogue |
60
+ | Correct usage and mistakes for one component | `pattern.md` / `antipattern.md` beside its `AGENTS.md` |
61
+ | Rules shared by every component: naming, events, slots, compound, icons, a11y, styling from outside | [`agents/conventions.md`](agents/conventions.md) |
62
+ | `variant` and `tone` values | [`agents/variants.md`](agents/variants.md) |
63
+ | Mistakes to avoid with any component | [`agents/anti-patterns.md`](agents/anti-patterns.md) |
64
+ | Coloring your own UI | [`agents/color.md`](agents/color.md) |
65
+ | Typography utilities | [`agents/typography.md`](agents/typography.md) |
66
+ | Dark mode, preferences, named themes, surface levels and elevation, global design decisions, corner geometry | [`agents/theming.md`](agents/theming.md) |
67
+ | Reporting a problem that is Magma's, not this project's (bug, wrong guide, missing token), with this project's origin label | [`agents/reporting.md`](agents/reporting.md) |
68
+
69
+ Tooling that needs structured data reads `documentation.json`: one per component beside
70
+ its `AGENTS.md`, or `@maggioli-design-system/magma/dist/documentation.json` for all of them
71
+ (over 2 MB - do not load it into context). `dist/types/components.d.ts` drives editor
72
+ IntelliSense.
@@ -0,0 +1,39 @@
1
+ <!--
2
+ GENERATED FILE - do not edit by hand.
3
+ Source of truth: docs/agents/ in the magma monorepo.
4
+ Regenerate with: npm run sync.agent-docs (from the stencil package).
5
+ -->
6
+ # Magma components - system-level anti-patterns
7
+
8
+ > Scope: mistakes that apply to **every** component. Each component's own
9
+ > `antipattern.md` (next to its `AGENTS.md`) covers the component-specific ones; the
10
+ > ones below are universal. The rules they break: [`conventions.md`](conventions.md),
11
+ > [`variants.md`](variants.md), [`color.md`](color.md), [`theming.md`](theming.md).
12
+
13
+ - Replacing a Magma component with a raw HTML element (`<button>`, `<input>`, `<a>` for
14
+ an action) when an `mds-*` equivalent exists.
15
+ - Wrapping an interactive `mds-*` component in another interactive element
16
+ (`<a><mds-button></mds-button></a>` - use the `href` prop instead).
17
+ - Reaching into shadow DOM past the documented API: undocumented `::part()` names,
18
+ internal class names, `>>>`, `/deep/`, or attribute-selector hacks. Use the CSS custom
19
+ properties and, for a deep customisation, the parts listed in the component's
20
+ `AGENTS.md` (see [`conventions.md`](conventions.md)).
21
+ - Setting boolean attributes to the string `"false"` (e.g. `disabled="false"`,
22
+ `await="false"`). Stencil reads `"false"` as `false`, but the attribute stays in the
23
+ DOM on a prop that is not reflected (and until the first render on one that is), so
24
+ `[disabled]` selectors and scripts reading the attribute still see it set. **Remove
25
+ the attribute** to turn it off.
26
+ - Embedding nested HTML in a default slot when the component documents a `label` prop.
27
+ - Using raw Tailwind colour utilities (`bg-white`, `text-gray-700`) on or inside Magma
28
+ components - use the semantic role classes (`bg-surface-default`, `text-fg-muted`),
29
+ see [`color.md`](color.md).
30
+ - Writing `@media (prefers-color-scheme: dark)` overrides - dark mode is handled by the
31
+ palette layer.
32
+ - Hand-rolling focus styles instead of `focus-bounce` / `focus-zoom`.
33
+ - Listening for native DOM events (`change`, `input`) when the component emits a
34
+ documented `mds*` event - they may not bubble out of shadow DOM the way you expect.
35
+ - Applying a `tone`, `variant`, or `size` value to a component without checking its
36
+ typed signature (the Props table of its `AGENTS.md`, or
37
+ `dist/types/components.d.ts`). The same prop name accepts different value sets per
38
+ component - e.g. `<mds-banner tone="outline">` is invalid because `mds-banner.tone` is
39
+ `ToneMinimalBoxVariantType` (`strong | weak | box` only).
@@ -0,0 +1,203 @@
1
+ <!--
2
+ GENERATED FILE - do not edit by hand.
3
+ Source of truth: docs/agents/ in the magma monorepo.
4
+ Regenerate with: npm run sync.agent-docs (from the stencil package).
5
+ -->
6
+ # install assets.md
7
+
8
+ ## Purpose
9
+
10
+ Canonical setup for the assets every Magma consumer needs, **identical for all three
11
+ targets** (web components, React, Angular): styles, fonts, icons and optional brand
12
+ identity. The per-target tracks ([`install.md`](install.md)) link here instead of repeating
13
+ this. If something about styles/fonts/icons setup is unclear, this file wins.
14
+
15
+ This file is the minimum to get a consumer running. Once it runs: coloring your own UI
16
+ in [`color.md`](color.md), the typography utilities in [`typography.md`](typography.md),
17
+ dark mode, preferences, named themes, the `--magma-*` global decisions and the corner
18
+ geometry in [`theming.md`](theming.md).
19
+
20
+ ## 1. Styles
21
+
22
+ ### Packages
23
+
24
+ ```bash
25
+ npm i @maggioli-design-system/styles @maggioli-design-system/design-tokens
26
+ ```
27
+
28
+ Pin both to the row matching your `magma` major (see [`AGENTS.md`](../AGENTS.md) matrix).
29
+
30
+ ### Import order (mandatory)
31
+
32
+ Magma styles rely on a fixed cascade-layer order. Import them in exactly this order
33
+ in your global CSS entry point, or specificity conflicts and dark mode will break:
34
+
35
+ ```css
36
+ @layer reset, vendor, theme, base, components, utilities, overrides;
37
+ /* or @import '@maggioli-design-system/styles/dist/css/layer.css'; */
38
+
39
+ @import 'normalize.css' layer(reset);
40
+
41
+ /* Fonts - see section 2 */
42
+ @import '@fontsource/karla/400.css' layer(vendor);
43
+ @import '@fontsource/karla/700.css' layer(vendor);
44
+ @import '@fontsource/merriweather/300.css' layer(vendor);
45
+ @import '@fontsource/merriweather/400.css' layer(vendor);
46
+ @import '@fontsource/merriweather/700.css' layer(vendor);
47
+ @import '@fontsource/roboto/500.css' layer(vendor);
48
+ @import '@fontsource/roboto/700.css' layer(vendor);
49
+ @import '@fontsource/roboto/900.css' layer(vendor);
50
+ @import '@fontsource/roboto-mono/400.css' layer(vendor);
51
+
52
+ /* Magma styles */
53
+ @import '@maggioli-design-system/styles/dist/css/colors-rgb.css' layer(theme);
54
+ @import '@maggioli-design-system/styles/dist/css/typography.css' layer(theme);
55
+ @import '@maggioli-design-system/styles/dist/css/reset.css' layer(reset);
56
+ @import '@maggioli-design-system/styles/dist/css/hydrated.css' layer(base);
57
+ @import '@maggioli-design-system/styles/dist/css/transitions.css' layer(base);
58
+ @import '@maggioli-design-system/styles/dist/css/animations.css' layer(base);
59
+ @import '@maggioli-design-system/styles/dist/css/globals.css' layer(theme);
60
+ @import '@maggioli-design-system/styles/dist/css/semantic.css' layer(theme);
61
+ @import '@maggioli-design-system/styles/dist/css/themes.css' layer(theme);
62
+ @import '@maggioli-design-system/styles/dist/css/base.css' layer(base);
63
+
64
+ /* your Tailwind entry point, if any */
65
+ @import './tailwind.css';
66
+ ```
67
+
68
+ What each file provides:
69
+
70
+ | File | Purpose |
71
+ | ---- | ------- |
72
+ | `colors-rgb.css` | RGB color tokens (`--tone-*`, `--status-*`, ...). Required by components and Tailwind. Also redefines tokens for dark / high-contrast |
73
+ | `typography.css` | The non-color tokens as CSS vars: fonts, type sizes, spacing, radius, shadows (`--shadow-md-sharp`, ...). Components carry their own fallbacks; your CSS needs this file for `var(--shadow-*)`, `var(--radius-*)` and the `--magma-radius-*` corner scale |
74
+ | `reset.css` | Opinionated CSS reset |
75
+ | `hydrated.css` | Anti-FOUC for Stencil - hides components until hydrated |
76
+ | `transitions.css`, `animations.css` | Shared motion |
77
+ | `globals.css` | Global `--magma-*` design decisions |
78
+ | `semantic.css` | The semantic color roles (`--magma-surface-*`, `--magma-text-*`, ..., see [`color.md`](color.md)). Required: without it the page `body` has no colour, the Tailwind role utilities paint nothing, and components lose named themes and high contrast |
79
+ | `themes.css` | The named themes (`data-theme-name`): retint the semantic roles. Import it after `semantic.css` |
80
+ | `base.css` | Base element styles (sets `--font-info` body font, etc.) |
81
+
82
+ DO NOT import `colors-hex-*.css` when using components or Tailwind - they cannot be
83
+ used with opacity modifiers and bypass dark mode. Use `colors-rgb.css`.
84
+
85
+ ### Tailwind (optional)
86
+
87
+ With Tailwind 4, import Magma's Tailwind layer in your Tailwind entry point (the
88
+ `./tailwind.css` of the block above), after Tailwind's own theme and utilities. Leave out
89
+ `@import 'tailwindcss'`: its preflight would duplicate Magma's reset.
90
+
91
+ ```css
92
+ /* tailwind.css */
93
+ @import 'tailwindcss/theme.css' layer(theme);
94
+ @import 'tailwindcss/utilities.css' layer(utilities);
95
+ @import '@maggioli-design-system/styles/dist/tailwind/theme.css';
96
+ @import '@maggioli-design-system/styles/dist/tailwind/typography.css';
97
+ @import '@maggioli-design-system/styles/dist/tailwind/utilities.css';
98
+ ```
99
+
100
+ `theme.css` brings the palette, the typography tokens and the semantic color utilities
101
+ (`bg-surface-raised`, `text-fg-muted`, ..., see [`color.md`](color.md)), `typography.css`
102
+ the `text-title-*` / `text-info-*` / `text-read-*` / `text-code-*` utilities,
103
+ `utilities.css` the `focus-bounce` / `focus-zoom` helpers.
104
+
105
+ Do not use the JS preset (`presets: [require('@maggioli-design-system/styles')]`) with
106
+ Tailwind 4: it is the Tailwind 3 path (with the layers in
107
+ `@maggioli-design-system/styles/dist/tailwind3/`), its colours are Tailwind 3 colour
108
+ functions, and Tailwind 4 generates none of the Magma utilities from it.
109
+
110
+ ## 2. Fonts
111
+
112
+ Magma does NOT bundle webfonts. The typography tokens point to **Roboto** (title),
113
+ **Karla** (info / UI), **Merriweather** (read / editorial) and **Roboto Mono**
114
+ (code), each with a system fallback. The consumer must load the actual fonts, easiest
115
+ via [`@fontsource`](https://fontsource.org/):
116
+
117
+ ```bash
118
+ npm i @fontsource/karla @fontsource/merriweather @fontsource/roboto @fontsource/roboto-mono
119
+ ```
120
+
121
+ The `@import` lines are already in the section 1 block (under `layer(vendor)`). They
122
+ are the weights the type scale uses: Roboto 500/700/900 (actions, h6, h1-h5), Karla
123
+ 400/700, Merriweather 300/400 (reading paragraph and detail, caption) plus 700 for bold in
124
+ reading text, Roboto Mono 400. Add more weights as needed.
125
+
126
+ Self-hosting via `@fontsource` is preferred over a CDN `<link>` so the fonts respect
127
+ the `vendor` cascade layer and ship offline.
128
+
129
+ ## 3. Icons
130
+
131
+ Icons are consumed at runtime by `mds-icon`, which fetches each icon as an SVG file from
132
+ a path the host app configures. A slug starts with its icon set (`mi/` Material Icons,
133
+ `mdi/` Material Design Icons, `mgg/` Maggioli) and resolves to
134
+ `<mdsIconSvgPath><slug>.svg`: with the path `/svg/`, `mi/baseline/email` is fetched from
135
+ `/svg/mi/baseline/email.svg`.
136
+
137
+ ### Package and asset copy
138
+
139
+ ```bash
140
+ npm i @maggioli-design-system/svg-icons
141
+ ```
142
+
143
+ Copy the SVG library to a publicly served path. The package ships the files under
144
+ `@maggioli-design-system/svg-icons/dist/svg/`. Copy them to e.g. `public/svg/` (the
145
+ mechanism depends on the bundler - see each track file).
146
+
147
+ ### Tell mds-icon where the icons are
148
+
149
+ The simplest way: set `mdsIconSvgPath` in `sessionStorage` before components hydrate.
150
+ The value is the public URL of the folder you copied the SVGs into:
151
+
152
+ ```javascript
153
+ window.sessionStorage.setItem('mdsIconSvgPath', '/svg/');
154
+ ```
155
+
156
+ Alternatives, documented in
157
+ the mds-icon readme:
158
+
159
+ - `IconsSetService.setSvgPath('/svg/')`, imported from
160
+ `@maggioli-design-system/magma/services`: sets the path in code, without
161
+ `sessionStorage`, and reloads the icons already mounted
162
+ - `mdsIcon.setSvgPath('/svg/')` - instance method on a temporary `mds-icon` node, after
163
+ `defineCustomElements()` has run
164
+ - dispatch `new CustomEvent('mdsIconSvgPathUpdate')` on `window` to force a refresh
165
+ after changing the path
166
+
167
+ Reference an icon by slug, never inline SVG and never import from an icon-set package:
168
+
169
+ ```html
170
+ <mds-icon name="mi/baseline/email"></mds-icon>
171
+ <mds-button icon="mi/baseline/send">Send</mds-button>
172
+ ```
173
+
174
+ The mgg-icons webfont (`@maggioli-design-system/icons`) is an alternative output and
175
+ is NOT used by Magma at runtime - prefer the SVG-file strategy above.
176
+
177
+ ## 4. Identity / brand (optional)
178
+
179
+ Logos and avatars for Maggioli Group products. Install only if the app renders brand
180
+ assets:
181
+
182
+ ```bash
183
+ npm i @maggioli-design-system/identity
184
+ ```
185
+
186
+ Assets live under `@maggioli-design-system/identity/dist/`:
187
+
188
+ - `dist/brand/` - logos per brand (gruppo-maggioli, maggioli-editore, rnd, ...)
189
+ - `dist/avatar/` - avatar illustrations (svg / webp / png / pdf)
190
+ - `dist/illustrations/`, `dist/products/` - additional brand imagery
191
+
192
+ These are static read-only files - serve them like any other asset, do not modify
193
+ them in the consumer project.
194
+
195
+ ## Checklist
196
+
197
+ - [ ] `styles` + `design-tokens` installed on the matching version row
198
+ - [ ] Global CSS imports in the exact cascade-layer order above
199
+ - [ ] `@fontsource` fonts installed and imported in the `vendor` layer
200
+ - [ ] `svg-icons` SVGs copied to a public path
201
+ - [ ] `mdsIconSvgPath` set to that public path before hydration
202
+ - [ ] (optional) `identity` installed if brand assets are used
203
+ - [ ] Components registered per your target track
@@ -0,0 +1,193 @@
1
+ <!--
2
+ GENERATED FILE - do not edit by hand.
3
+ Source of truth: docs/agents/ in the magma monorepo.
4
+ Regenerate with: npm run sync.agent-docs (from the stencil package).
5
+ -->
6
+ # Magma styles - color
7
+
8
+ > Scope: coloring your own UI with Magma's semantic color roles, in Tailwind and in
9
+ > plain CSS. Requires the styles setup in [`assets.md`](assets.md), including
10
+ > `semantic.css`. Dark mode, contrast and named themes: [`theming.md`](theming.md).
11
+ > The `variant` prop of the components: [`variants.md`](variants.md).
12
+
13
+ ## Name the role, not the colour
14
+
15
+ Paint your UI with the semantic roles (`--magma-*`), not with a raw palette step and never
16
+ with Tailwind's own palette:
17
+
18
+ ```html
19
+ <!-- correct: roles follow the mode, the named theme and high contrast -->
20
+ <section class="bg-surface-raised text-fg-default border border-border-muted">
21
+ <p class="text-fg-muted">Secondary text</p>
22
+ </section>
23
+
24
+ <!-- incorrect: raw Magma steps only flip with the mode -->
25
+ <section class="bg-tone-neutral-seed text-tone-neutral-01 border-tone-neutral-09">...</section>
26
+
27
+ <!-- incorrect: Tailwind's palette ignores Magma entirely -->
28
+ <section class="bg-white text-gray-700">...</section>
29
+ ```
30
+
31
+ A role resolves per mode (light / dark), per named theme (`data-theme-name` retints the
32
+ neutral scaffolding and the accent) and per contrast preference (`pref-contrast-more`
33
+ promotes text and borders, and the page). A raw step (`tone-neutral-03`,
34
+ `status-error-05`, `variant-primary-04`) only flips with the mode: it stays grey under a
35
+ tinted theme and gains no contrast when the user asks for more.
36
+
37
+ ## One token, two faces
38
+
39
+ Every role is a CSS custom property holding an RGB channel triplet, and a Tailwind color
40
+ of the same role.
41
+
42
+ ```css
43
+ /* plain CSS: always inside rgb(), alpha with the slash syntax */
44
+ .panel {
45
+ background: rgb(var(--magma-surface-raised));
46
+ color: rgb(var(--magma-text-default));
47
+ border: 1px solid rgb(var(--magma-border-muted));
48
+ box-shadow: 0 2px 8px rgb(var(--magma-shadow-ink) / 0.12);
49
+ }
50
+ ```
51
+
52
+ Tailwind names the TEXT roles `fg-*`, so a utility never reads `text-text-*`:
53
+ `--magma-text-muted` is `text-fg-muted`, `--magma-danger-text-default` is
54
+ `text-danger-fg-default`. Every other role keeps its name: `bg-surface-raised`,
55
+ `border-border-default`, `bg-accent-emphasis`, `bg-danger-wash-base`.
56
+
57
+ Both faces need the setup in [`assets.md`](assets.md): the values come from
58
+ `styles/dist/css/semantic.css` (without it every role paints nothing), the Tailwind
59
+ utilities from `styles/dist/tailwind/theme.css`. A Tailwind modifier works as usual
60
+ (`bg-surface-raised/80`).
61
+
62
+ ## The roles
63
+
64
+ ### Neutral scaffolding
65
+
66
+ Backgrounds, text and borders of everything that is neither an action nor a state. A
67
+ named theme retints all of it at once.
68
+
69
+ | Token (`--magma-*`) | Tailwind | Use |
70
+ | --- | --- | --- |
71
+ | `surface-default` | `bg-surface-default` | the page canvas (the `body` already has it) |
72
+ | `surface-raised` | `bg-surface-raised` | cards, panels, sticky headers |
73
+ | `surface-overlay` | `bg-surface-overlay` | modal, dropdown, popover, sheet |
74
+ | `surface-sunken` | `bg-surface-sunken` | wells, insets, code blocks, tracks |
75
+ | `surface-muted` | `bg-surface-muted` | same-plane grouping: zebra rows, a subtle section |
76
+ | `wash-soft` / `wash-base` / `wash-strong` | `bg-wash-*` | a neutral pill or chip, by how marked it is |
77
+ | `surface-inverse` / `surface-inverse-muted` | `bg-surface-inverse*` | the chip that flips with the mode (dark on a light UI) |
78
+ | `on-inverse` | `text-on-inverse` | text and icons on either inverse level |
79
+ | `text-default` | `text-fg-default` | body text, titles, primary data |
80
+ | `text-muted` | `text-fg-muted` | secondary text that is still essential (an address, a phone) |
81
+ | `text-subtle` | `text-fg-subtle` | non-essential text only: captions, units, hints |
82
+ | `text-disabled` | `text-fg-disabled` | disabled labels |
83
+ | `text-on-emphasis` | `text-fg-on-emphasis` | text on a solid fill |
84
+ | `border-muted` | `border-border-muted` | decorative: dividers, table grid |
85
+ | `border-default` | `border-border-default` | functional outlines: inputs, cards |
86
+ | `border-strong` | `border-border-strong` | a border that conveys state (selected) |
87
+ | `border-focus` | `border-border-focus` | focus indication; follows the accent |
88
+ | `neutral-fg` / `neutral-border` | `text-neutral-fg` / `border-neutral-border` | neutral ink and border on a colored context |
89
+ | `shadow-ink` | `shadow-shadow-ink` | the colour of a projected shadow; compose it with your own geometry and alpha |
90
+
91
+ `--magma-on-backdrop` (in `globals.css`) is the ink on the modal scrim, fixed in both modes.
92
+
93
+ How the five surfaces stack, their values in light and dark, why a raised element needs a
94
+ shadow in light, and how themes and high contrast move them: [`theming.md`](theming.md#surfaces-and-elevation).
95
+
96
+ ### Accent: actions and selection
97
+
98
+ Two accents with the same nine roles: `accent` (the brand action colour) and `accent-ai`
99
+ (AI-driven features). A named theme can repoint them.
100
+
101
+ | Token | Tailwind | Use |
102
+ | --- | --- | --- |
103
+ | `--magma-accent-emphasis` | `bg-accent-emphasis` | solid fill: the primary action |
104
+ | `--magma-accent-emphasis-hover` / `-emphasis-active` | `hover:bg-accent-emphasis-hover` | the fill hovered / pressed |
105
+ | `--magma-accent-on-emphasis` | `text-accent-on-emphasis` | text and icons on the fill |
106
+ | `--magma-accent-surface` | `bg-accent-surface` | tinted background: a selected row or chip |
107
+ | `--magma-accent-surface-subtle` / `-surface-hover` | `bg-accent-surface-*` | the tinted background, lighter / hovered |
108
+ | `--magma-accent-fg` | `text-accent-fg` | accent text or icon on a neutral surface (a link) |
109
+ | `--magma-accent-border` | `border-accent-border` | tinted border |
110
+
111
+ `accent-ai` is the same set with the infix: `--magma-accent-ai-emphasis`,
112
+ `bg-accent-ai-surface`, `text-accent-ai-fg`.
113
+
114
+ ### Status: info, success, warning, danger
115
+
116
+ Each status publishes the same vocabulary. The hue is named `danger` (the palette family
117
+ is `status-error`). A named theme never retints a status.
118
+
119
+ | Token (`<hue>` = `info`, `success`, `warning`, `danger`) | Tailwind | Use |
120
+ | --- | --- | --- |
121
+ | `--magma-<hue>-wash-soft` / `-wash-base` / `-wash-strong` | `bg-<hue>-wash-*` | colored background, by how marked it is |
122
+ | `--magma-<hue>-text-default` / `-muted` / `-subtle` / `-disabled` | `text-<hue>-fg-*` | colored text on that wash |
123
+ | `--magma-<hue>-border-muted` / `-default` / `-strong` | `border-<hue>-border-*` | colored border |
124
+ | `--magma-<hue>-emphasis` (+ `-hover`, `-active`) | `bg-<hue>-emphasis*` | solid fill: a destructive button, a solid badge |
125
+ | `--magma-<hue>-on-emphasis` | `text-<hue>-on-emphasis` | text and icons on the fill |
126
+
127
+ Shortcuts at the default prominence, kept for brevity: `--magma-<hue>-surface` =
128
+ `wash-base`, `--magma-<hue>-fg` = `text-default`, `--magma-<hue>-border` =
129
+ `border-default` (Tailwind `bg-<hue>-surface`, `text-<hue>-fg`, `border-<hue>-border`).
130
+
131
+ ## Pairing rules
132
+
133
+ These are the pairs the contrast gate measures in CI; any other combination is not
134
+ measured.
135
+
136
+ - **`-fg` on a neutral surface, `-on-emphasis` on the fill.** `--magma-accent-fg` is ink
137
+ for the page; on `--magma-accent-emphasis` use `--magma-accent-on-emphasis`. Swapping
138
+ them is the quickest way to break contrast.
139
+ - **Text on a wash is bounded.** `wash-soft` carries the whole text ladder, `wash-base`
140
+ carries `text-default` only, `wash-strong` carries icons only (no essential text). Same
141
+ rule for the neutral band and for every status.
142
+ - **Hierarchy without dropping contrast.** `text-muted` is for essential secondary text,
143
+ `text-subtle` only for what the user can skip. For more hierarchy use weight, size and
144
+ spacing, and soften the chrome (`border-muted`, zebra on `surface-muted`) instead of the
145
+ text.
146
+ - **Elevation is a role.** Page `surface-default`, card
147
+ `surface-raised`, floating layer `surface-overlay`, well `surface-sunken`: choose by
148
+ what the element is, not by the shade you want, and give `raised` / `overlay` a shadow
149
+ ([`theming.md`](theming.md#surfaces-and-elevation)). A grey that has to look marked in
150
+ both modes (a pill, a chip, a hover) is a wash, not a surface.
151
+ - **No `dark:` variants and no dark-mode media queries.** The roles already flip.
152
+
153
+ ## When a raw palette colour is right
154
+
155
+ Only when the colour encodes data rather than an interface role:
156
+
157
+ - `label-*` (`bg-label-sky-09`, `rgb(var(--label-orchid-04))`): a category, a tag, a
158
+ colour the user picked;
159
+ - `brand-*`: Maggioli brand identity;
160
+ - `--tone-neutral-seed` (`#fff` in light, `#000` in dark): the rare pure extreme, a
161
+ knockout; not a page or card background.
162
+
163
+ Never use `--magma-tint-*`: it is the internal pointer a named theme repoints, not a role.
164
+ `tone-porcelain` and `tone-bisque` back the named themes `cool` and `warm`: switch them on
165
+ with `data-theme-name` ([`theming.md`](theming.md)), do not paint them by hand.
166
+ `variant-*` has no role of its own: the accents are `accent` and `accent-ai`.
167
+
168
+ Deprecated: `--magma-neutral-emphasis` / `--magma-neutral-on-emphasis` are aliases of
169
+ `--magma-surface-inverse` / `--magma-on-inverse`.
170
+
171
+ ## Migrating Magma 1 colour classes
172
+
173
+ Magma 1 code paints raw steps, often with a hand-tuned `dark:` override. These steps have
174
+ a role with the same light value; switch to the role and delete the `dark:` override:
175
+
176
+ | Magma 1 step | As | Role |
177
+ | --- | --- | --- |
178
+ | `tone-neutral-01` / `-03` / `-04` / `-05` | text | `fg-default` / `fg-muted` / `fg-subtle` / `fg-disabled` |
179
+ | `tone-neutral-10` / `-09` / `-08` | background | `wash-soft` / `wash-base` / `wash-strong` |
180
+ | `tone-neutral-02` / `-03` | background | `surface-inverse` / `surface-inverse-muted` |
181
+ | `tone-neutral-06` | border | `neutral-border` |
182
+ | `tone-neutral` (the bare seed) | background | by context: `surface-default`, `-raised` or `-overlay` |
183
+ | `status-<x>-01` / `-02` / `-03` / `-05` | text | `<hue>-fg-default` / `-muted` / `-subtle` / `-disabled` |
184
+ | `status-<x>-04` / `-03` / `-02` | background | `<hue>-emphasis` / `-emphasis-hover` / `-emphasis-active` |
185
+ | `status-<x>-10` / `-09` / `-08` | background | `<hue>-wash-soft` / `-wash-base` / `-wash-strong` |
186
+ | `variant-primary-04` / `-03` / `-02` | background | `accent-emphasis` / `-emphasis-hover` / `-emphasis-active` |
187
+ | `variant-primary-09` / `-08` / `-10` | background | `accent-surface` / `-surface-hover` / `-surface-subtle` |
188
+ | `variant-primary-03` / `-06` | text / border | `accent-fg` / `accent-border` |
189
+
190
+ `variant-ai-*` maps the same way onto `accent-ai-*`. The codemod
191
+ (`@maggioli-design-system/magma-codemods`, `--accept-semantic=exact`) applies this table
192
+ to markup, `clsx()`, Angular bindings and `@apply`, and reports what a value cannot
193
+ decide.