@adia-ai/adia-ui-factory 0.8.2 → 0.8.3
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/.claude-plugin/plugin.json +1 -1
- package/.mcp.json +1 -1
- package/CHANGELOG.md +11 -0
- package/package.json +1 -1
- package/skills/adia-compose/SKILL.md +1 -1
- package/skills/adia-llm/SKILL.md +19 -3
- package/skills/adia-tokens/SKILL.md +78 -0
- package/skills/adia-tokens/evals/routing-corpus.json +39 -0
- package/skills/adia-tokens/references/a-alias-layer.md +218 -0
- package/skills/adia-tokens/references/pairing-laws.md +63 -0
- package/skills/adia-tokens/references/role-roster.md +26 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adia-factory",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "Author and verify apps built ON the adia-ui (@adia-ai) light-DOM web-component framework \u2014 orient, scaffold, compose, wire, verify, and migrate across SPA and SSR rendering modes. Wires the a2ui MCP for catalog retrieval, UI generation, and validation.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Kim",
|
package/.mcp.json
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
# Changelog — adia-factory
|
|
2
|
+
## [0.8.3] — 2026-07-16
|
|
3
|
+
|
|
4
|
+
### Added
|
|
5
|
+
- **`adia-tokens` knowledge pack** (`skills/adia-tokens/`, gh#265): the consumer-facing "which color token/role" answerer — role grammar + the six pairing laws (incl. the fill-contrast operator ruling), the `--a-*`-vs-Material layer choice, and two cut-time-GENERATED references (the 8×53 role roster and the full 206-row `--a-*` → Material bridge table), regenerated + CI-gated from the framework token sources so the corpus cannot drift. Routing evals included; `adia-compose` routes token questions here.
|
|
6
|
+
- **`skills/adia-llm` verify-gates table + debugging catalog**: the key-in-client gate now cites the `adia-lint` rule that mechanizes it; a source-grounded symptom→cause table headlines the two runtime traps whose docs Wave 0 corrected (`Unknown provider "google"` throw; `GEMINI_API_KEY` vs `GOOGLE_API_KEY`).
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- **`commands/` refreshed to the post-campaign estate**: `/adia-verify` dispatches the read-only consumer-verifier seat (generator ≠ critic); NEW `/adia-info`; `/adia-migrate` carries the shipped-guide path + consent options; `/adia-scaffold` surfaces inventory mode; `/adia-genui` closes with the Generation Record.
|
|
10
|
+
|
|
11
|
+
### Maintenance
|
|
12
|
+
- `.mcp.json` a2ui-mcp pin → 0.8.3 (invariant 8); `packages/plugins/adia-ui-factory/.claude-plugin/plugin.json` moves in lockstep (the `/plugin update` cache key).
|
|
2
13
|
## [0.8.2] — 2026-07-16
|
|
3
14
|
|
|
4
15
|
### The modernization campaign (gh#259, Waves 0–3 + the command refresh)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/adia-ui-factory",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "Author and verify apps built ON the adia-ui (@adia-ai) light-DOM web-component framework \u2014 orient, scaffold, compose, wire, verify, and migrate across SPA and SSR rendering modes. Wires the a2ui MCP for catalog retrieval, UI generation, and validation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adia-ui",
|
|
@@ -118,4 +118,4 @@ el.append(new Option('A', 'a')); // wrong: renders outside the popover
|
|
|
118
118
|
| Filing findings upstream to @adia-ai maintainers | [`references/feedback-discipline.md`](references/feedback-discipline.md) + [`assets/templates/`](assets/templates/) |
|
|
119
119
|
| Seeding a Figma Make kit with adia-ui | drop [`assets/figma-make/guidelines/`](assets/figma-make/guidelines/) into the kit |
|
|
120
120
|
|
|
121
|
-
Neighboring work routes out: shell selection/chrome → `adia-shells` · host registration/SSR → `adia-host` · hydration/state/CRUD → `adia-data` · generative-UI runtime → `adia-genui` · browser QA/a11y → `adia-verify`.
|
|
121
|
+
Neighboring work routes out: shell selection/chrome → `adia-shells` · host registration/SSR → `adia-host` · hydration/state/CRUD → `adia-data` · generative-UI runtime → `adia-genui` · browser QA/a11y → `adia-verify` · "which token/role" questions → `adia-tokens`.
|
package/skills/adia-llm/SKILL.md
CHANGED
|
@@ -26,9 +26,25 @@ Standing contract for wiring `@adia-ai/llm` (the lockstep version your app insta
|
|
|
26
26
|
- NOT in the package: tool-calling, structured-output modes, retry/backoff, token estimation — server-layer concerns, not client options.
|
|
27
27
|
- `<chat-shell proxy-url="/api/chat" model="…">` auto-sends on submit and renders the stream itself; without `proxy-url` it only emits `submit` for the app to handle.
|
|
28
28
|
|
|
29
|
-
## Verify
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
## Verify gates
|
|
30
|
+
|
|
31
|
+
| Gate | Pass condition | Enforcement |
|
|
32
|
+
| --- | --- | --- |
|
|
33
|
+
| Key never in client `[gate]` | no provider key reachable in browser source or network requests; production requests carry the provider-neutral smart-proxy body, no upstream auth headers | mechanized: `adia-lint` `LLM-KEY-IN-CLIENT` fires on every write (server/api/proxy paths exempt); the network half is checked in the browser gate |
|
|
34
|
+
| Streams live | streams in a real page, zero console/page errors | `adia-verify`'s browser gate (`bin/adia-probe.mjs`) |
|
|
35
|
+
| All 4 chunk branches drive UI | `text`/`thinking`/`done`/`error` each observably changes the surface; an `error` chunk renders, never drops | self-verified — exercise each branch (the stub provider exists for exactly this) |
|
|
36
|
+
| Provider name legal | `provider` ∈ anthropic \| openai \| gemini on the streamChat path — unknown names THROW | self-verified against `adapters/index.js`; the docs said `google` until 2026-07-16, real apps may carry it |
|
|
37
|
+
|
|
38
|
+
## Symptom → cause (the debugging catalog)
|
|
39
|
+
|
|
40
|
+
| Symptom | Cause → fix |
|
|
41
|
+
| --- | --- |
|
|
42
|
+
| `Unknown provider "google"` throw | the pre-0.8.2 docs' enum — use `gemini` (llm.md; the `google`/`stub` values belong to the separate `llm-bridge.js` entry) |
|
|
43
|
+
| Silent auth failure on a Gemini proxy | server reads `GEMINI_API_KEY`, not `GOOGLE_API_KEY` (server.js) |
|
|
44
|
+
| Chat renders but nothing streams on submit | no `proxy-url` on `<chat-shell>` — it only emits `submit` for the app to handle; set `proxy-url` for auto-send |
|
|
45
|
+
| Stream stops mid-answer, no error shown | the `error` StreamChunk branch is being dropped instead of rendered — every branch drives the UI |
|
|
46
|
+
| Works in dev, 401s deployed | the passthrough shape (`/api/llm/<provider>/…`) shipped to production — it puts the key in browser headers; production is the smart proxy |
|
|
47
|
+
| Composer is 0px | `<chat-input-ui>` isn't in the chat barrel — import it (and its internal `textarea-ui`/`select-ui`) separately (shell-chat.md §Gotchas) |
|
|
32
48
|
|
|
33
49
|
## References
|
|
34
50
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: adia-tokens
|
|
3
|
+
description: >-
|
|
4
|
+
Answers which color token/role an adia-ui surface should use — role
|
|
5
|
+
grammar, pairing laws, state families, the --a-* alias layer. Use when
|
|
6
|
+
asked "which token for this background/text/hover/border" or "--a-* or
|
|
7
|
+
--md-sys-color-*". ANSWERS only. NOT for composing the screen
|
|
8
|
+
(adia-compose) or designing/verifying palettes (framework-side).
|
|
9
|
+
disable-model-invocation: false
|
|
10
|
+
user-invocable: false
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# adia-tokens — which color role, answered
|
|
14
|
+
|
|
15
|
+
The color system's public API is semantic roles, never values: if a color
|
|
16
|
+
isn't a `--md-sys-color-*` role or an `--a-*` alias, it doesn't go in UI
|
|
17
|
+
code — no hex, no `oklch()`, no raw `-050…-950` stop, no `color-mix()`
|
|
18
|
+
state synthesis. This pack answers the "which role" question; the values
|
|
19
|
+
themselves live in the installed CSS and are never restated here.
|
|
20
|
+
|
|
21
|
+
## The grammar
|
|
22
|
+
|
|
23
|
+
`--md-sys-color-{palette}{suffix}` — 8 palettes (`neutral` chrome ·
|
|
24
|
+
`primary` brand accent · `secondary`/`tertiary` support · the four intents
|
|
25
|
+
`info/success/warning/danger`, which carry MEANING only, never decoration).
|
|
26
|
+
The on-accent role uses the palette's OWN slug:
|
|
27
|
+
`--md-sys-color-danger-on-danger` sits on `--md-sys-color-danger`. The full
|
|
28
|
+
suffix roster with per-family meaning: [`references/role-roster.md`](references/role-roster.md)
|
|
29
|
+
(GENERATED from the installed export — trust it over memory).
|
|
30
|
+
|
|
31
|
+
## The laws (violating any is a defect)
|
|
32
|
+
|
|
33
|
+
1. **Pairing** — ink sits only on its own palette's legal ground:
|
|
34
|
+
`-on-{p}` on the accent fill; `-on-surface` on that palette's
|
|
35
|
+
surfaces/containers/background. Never cross palettes mid-pair.
|
|
36
|
+
2. **States ship as families** — where `-hover/-active/-disabled` siblings
|
|
37
|
+
exist, use them verbatim; never synthesize a state with opacity or
|
|
38
|
+
`color-mix()`. Not every role has siblings — the roster is the map.
|
|
39
|
+
3. **The scheme is baked in** — every role flips via `light-dark()`; write
|
|
40
|
+
each color once. Force a subtree with `color-scheme:`, never per-color
|
|
41
|
+
`@media` overrides.
|
|
42
|
+
4. **Elevation is the surface ladder** — raise/recess with
|
|
43
|
+
`-surface-{dim…bright}` / `-surface-{low…high}` tiers; shadows are
|
|
44
|
+
garnish, opacity is a defect.
|
|
45
|
+
5. **On-accent ink is fixed light in both schemes, by design** — it
|
|
46
|
+
deliberately overrides per-pair contrast math (operator ruling
|
|
47
|
+
2026-07-16, recorded in the framework's color-bridge contract: fill-pair
|
|
48
|
+
contrast is an upstream design decision — do not "fix" it locally with
|
|
49
|
+
dark text or auto-contrast).
|
|
50
|
+
6. **Roles by their named purpose, never by coincidental value** — no
|
|
51
|
+
`--a-bg` as a foreground, no chart identity tokens (`--a-data-0..9`)
|
|
52
|
+
for semantic state, and vice versa.
|
|
53
|
+
|
|
54
|
+
Depth and adia-specific notes per law: [`references/pairing-laws.md`](references/pairing-laws.md).
|
|
55
|
+
|
|
56
|
+
## Which layer — `--a-*` or `--md-sys-color-*`?
|
|
57
|
+
|
|
58
|
+
Both are public. `--a-*` is the compact alias layer most component CSS and
|
|
59
|
+
older app code consumes; the Material roles are the source of truth it
|
|
60
|
+
reads from. Match the file you're editing (don't mix mid-file); for NEW
|
|
61
|
+
code prefer the Material role — it's the finer-grained vocabulary. The
|
|
62
|
+
full alias→role mapping: [`references/a-alias-layer.md`](references/a-alias-layer.md)
|
|
63
|
+
(GENERATED — the authoritative bridge table).
|
|
64
|
+
|
|
65
|
+
## Consult table
|
|
66
|
+
|
|
67
|
+
| Ask | Answer from |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| "which role for this button/badge/toast/border/text" | the grammar + laws above, then [`role-roster.md`](references/role-roster.md) for the exact suffix |
|
|
70
|
+
| "what does `--a-<x>` actually resolve to" | [`a-alias-layer.md`](references/a-alias-layer.md) |
|
|
71
|
+
| "hover/disabled color for X" | law 2 — the role's own state family, from the roster |
|
|
72
|
+
| "make it work in dark mode" | law 3 — it already does; check the subtree's `color-scheme` before touching tokens |
|
|
73
|
+
| "this pair looks low-contrast" | law 5 first (on-accent is by design); genuine canvas-text pairs are gated by the framework's `verify:contrast` |
|
|
74
|
+
|
|
75
|
+
The generated references are produced in the framework monorepo at cut
|
|
76
|
+
time (producer-side, CI-gated) — in a consumer repo they describe the
|
|
77
|
+
version you installed; never edit them. Choosing and wiring the tokens into a
|
|
78
|
+
screen is `adia-compose`'s job; this pack only answers.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"name": "adia-tokens-routing-corpus",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"purpose": "Routing floor for the adia-tokens knowledge pack: 'which color token/role' asks reach it; composition, palette-design, and value-verification asks route past it.",
|
|
6
|
+
"scoring_notes": "Heuristic TF-IDF proxy (scripts/skills/run-skill-evals.mjs); the real harness routes on descriptions. Treat misroutes as description-tightening signals.",
|
|
7
|
+
"license": "internal",
|
|
8
|
+
"scope": "adia-ui-factory plugin, consumer-side. In the framework monorepo the operator's private design-systems plugin carries a broader Material-tokens skill — overlap there is inherent and acceptable; this pack exists for consumer installs without it.",
|
|
9
|
+
"minimums_per_spec": {
|
|
10
|
+
"trigger_phrases": 12,
|
|
11
|
+
"adversarial_phrases": 5,
|
|
12
|
+
"task_shapes_covered": "which-role, state-family, layer-choice, alias-resolution, dark-mode, contrast-complaint",
|
|
13
|
+
"adversarial_fraction": "29%"
|
|
14
|
+
},
|
|
15
|
+
"phrases": [
|
|
16
|
+
{ "id": "tokens-role-01", "phrase": "which token should this card background use", "should_route_to_tokens": true, "expected_shape": "which-role", "rationale": "The pack's flagship ask — role for a surface." },
|
|
17
|
+
{ "id": "tokens-role-02", "phrase": "what color role for the text on this danger badge", "should_route_to_tokens": true, "expected_shape": "which-role", "rationale": "Pairing-law territory: ink on an intent fill." },
|
|
18
|
+
{ "id": "tokens-role-03", "phrase": "which --md-sys-color role for a subtle divider", "should_route_to_tokens": true, "expected_shape": "which-role", "rationale": "Outline-family lookup by need." },
|
|
19
|
+
{ "id": "tokens-role-04", "phrase": "what token for a toast that must read as a warning", "should_route_to_tokens": true, "expected_shape": "which-role", "rationale": "Intent palette selection + container family." },
|
|
20
|
+
{ "id": "tokens-state-01", "phrase": "add hover and disabled colors to this button", "should_route_to_tokens": true, "expected_shape": "state-family", "rationale": "Law 2 — baked state families, never synthesized." },
|
|
21
|
+
{ "id": "tokens-state-02", "phrase": "how do I dim this control when it's disabled", "should_route_to_tokens": true, "expected_shape": "state-family", "rationale": "The opacity anti-pattern's replacement." },
|
|
22
|
+
{ "id": "tokens-layer-01", "phrase": "should I use --a-primary or --md-sys-color-primary here", "should_route_to_tokens": true, "expected_shape": "layer-choice", "rationale": "The two-layer question the pack owns." },
|
|
23
|
+
{ "id": "tokens-alias-01", "phrase": "what does --a-canvas-well actually resolve to", "should_route_to_tokens": true, "expected_shape": "alias-resolution", "rationale": "The generated alias table's row lookup." },
|
|
24
|
+
{ "id": "tokens-dark-01", "phrase": "make this panel's colors work in dark mode", "should_route_to_tokens": true, "expected_shape": "dark-mode", "rationale": "Law 3 — scheme baked in; check color-scheme, not tokens." },
|
|
25
|
+
{ "id": "tokens-elev-01", "phrase": "which surface tier makes this card read as raised", "should_route_to_tokens": true, "expected_shape": "which-role", "rationale": "Law 4 — the elevation ladder." },
|
|
26
|
+
{ "id": "tokens-contrast-01", "phrase": "the white text on our warning button looks low contrast — which token fixes it", "should_route_to_tokens": true, "expected_shape": "contrast-complaint", "rationale": "Law 5 — the answer is the ruling (by design, don't patch), which only this pack carries consumer-side." },
|
|
27
|
+
{ "id": "tokens-chart-01", "phrase": "which tokens color the chart series vs the error state", "should_route_to_tokens": true, "expected_shape": "which-role", "rationale": "Law 6 — identity vs state token classes." },
|
|
28
|
+
{ "id": "tokens-adv-01", "phrase": "build the settings screen with proper tokens", "should_route_to_tokens": false, "expected_alternative": "adia-compose (adia-ui-factory)", "rationale": "Adversarial — composition consumes the answer; the ask is a build." },
|
|
29
|
+
{ "id": "tokens-adv-02", "phrase": "design a new color ramp from our brand blue", "should_route_to_tokens": false, "expected_alternative": "framework-side palette design (not this plugin)", "rationale": "Adversarial — palette DESIGN is upstream; this pack answers consumption." },
|
|
30
|
+
{ "id": "tokens-adv-03", "phrase": "check the contrast ratio of this text on this background", "should_route_to_tokens": false, "expected_alternative": "framework verify:contrast / operator tooling", "rationale": "Adversarial — value verification, not role choice." },
|
|
31
|
+
{ "id": "tokens-adv-04", "phrase": "the page renders blank after my token change", "should_route_to_tokens": false, "expected_alternative": "adia-verify (adia-ui-factory)", "rationale": "Adversarial — a broken render is the browser gate's territory." },
|
|
32
|
+
{ "id": "tokens-adv-05", "phrase": "add a new token to the framework's core.css", "should_route_to_tokens": false, "expected_alternative": "adia-author (adia-ui-forge)", "rationale": "Adversarial — framework token AUTHORING is forge-side." }
|
|
33
|
+
],
|
|
34
|
+
"evaluator_notes": {
|
|
35
|
+
"known_limitations": "In the framework monorepo, the operator's private design-systems:material-design-color-tokens skill legitimately overlaps every positive here — the fence is install-context, not phrasing; do not tune descriptions to separate them.",
|
|
36
|
+
"promotion_criteria": "F1 >= 0.85 across 3+ runs",
|
|
37
|
+
"review_cadence": "on any description edit; on /eval-run findings"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
<!-- GENERATED — do not edit. Source: packages/web-components/styles/colors/semantics/core.css.
|
|
2
|
+
Provenance: produced in the framework monorepo at cut time by
|
|
3
|
+
scripts/release/check-token-semantics-sync.mjs (producer-side tooling,
|
|
4
|
+
not runnable from a consumer install — in a consumer repo this file
|
|
5
|
+
describes the version you installed). -->
|
|
6
|
+
|
|
7
|
+
# The `--a-*` alias layer — what each token reads
|
|
8
|
+
|
|
9
|
+
The `--a-*` semantic layer is a thin alias layer reading FROM the `--md-sys-color-*` static export (the color source of truth since v0.8.0). Both layers are public; components consume `--a-*` roles or Material roles directly — the mapping below is the bridge. 206 declarations.
|
|
10
|
+
|
|
11
|
+
| `--a-*` token | Reads |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `--a-canvas-strong` | `var(--md-sys-color-neutral-surface-high)` |
|
|
14
|
+
| `--a-canvas` | `var(--md-sys-color-neutral-surface)` |
|
|
15
|
+
| `--a-canvas-subtle` | `var(--md-sys-color-neutral-surface-dim)` |
|
|
16
|
+
| `--a-canvas-muted` | `var(--md-sys-color-neutral-surface-dimmer)` |
|
|
17
|
+
| `--a-canvas-hover` | `var(--md-sys-color-neutral-hover)` |
|
|
18
|
+
| `--a-canvas-active` | `var(--md-sys-color-neutral-active)` |
|
|
19
|
+
| `--a-canvas-selected` | `var(--md-sys-color-neutral-container-active)` |
|
|
20
|
+
| `--a-canvas-text-strong` | `var(--md-sys-color-neutral-on-surface)` |
|
|
21
|
+
| `--a-canvas-text` | `var(--md-sys-color-neutral-on-surface)` |
|
|
22
|
+
| `--a-canvas-text-subtle` | `var(--md-sys-color-neutral-on-surface-variant)` |
|
|
23
|
+
| `--a-canvas-text-muted` | `var(--md-sys-color-neutral-on-surface-variant)` |
|
|
24
|
+
| `--a-canvas-text-disabled` | `var(--md-sys-color-neutral-on-surface-disabled)` |
|
|
25
|
+
| `--a-canvas-text-inverse` | `var(--md-sys-color-neutral-inverse-on-surface)` |
|
|
26
|
+
| `--a-canvas-surface-inverse` | `var(--md-sys-color-neutral-inverse-surface)` |
|
|
27
|
+
| `--a-canvas-well` | `var(--md-sys-color-neutral-surface-low)` |
|
|
28
|
+
| `--a-canvas-inset` | `var(--md-sys-color-neutral-background)` |
|
|
29
|
+
| `--a-canvas-pressed` | `var(--md-sys-color-neutral-surface-high)` |
|
|
30
|
+
| `--a-canvas-well-strong` | `var(--md-sys-color-neutral-container)` |
|
|
31
|
+
| `--a-canvas-border-subtle` | `var(--md-sys-color-neutral-outline-variant)` |
|
|
32
|
+
| `--a-canvas-border` | `var(--md-sys-color-neutral-outline)` |
|
|
33
|
+
| `--a-canvas-border-strong` | `var(--md-sys-color-neutral-outline-active)` |
|
|
34
|
+
| `--a-bg` | `var(--md-sys-color-neutral-background)` |
|
|
35
|
+
| `--a-bg-scrim` | `var(--md-sys-color-neutral-scrim-weakest)` |
|
|
36
|
+
| `--a-bg-subtle` | `var(--md-sys-color-neutral-surface)` |
|
|
37
|
+
| `--a-bg-muted` | `var(--md-sys-color-neutral-container)` |
|
|
38
|
+
| `--a-bg-strong` | `var(--md-sys-color-neutral-surface-high)` |
|
|
39
|
+
| `--a-bg-hover` | `var(--md-sys-color-neutral-hover)` |
|
|
40
|
+
| `--a-bg-active` | `var(--md-sys-color-neutral-active)` |
|
|
41
|
+
| `--a-bg-selected` | `var(--md-sys-color-neutral-container-active)` |
|
|
42
|
+
| `--a-bg-disabled` | `var(--md-sys-color-neutral-container-disabled)` |
|
|
43
|
+
| `--a-bg-invalid` | `var(--a-danger-muted)` |
|
|
44
|
+
| `--a-fg` | `var(--md-sys-color-neutral-on-surface)` |
|
|
45
|
+
| `--a-fg-subtle` | `var(--md-sys-color-neutral-on-surface-variant)` |
|
|
46
|
+
| `--a-fg-muted` | `var(--md-sys-color-neutral-on-surface-variant)` |
|
|
47
|
+
| `--a-fg-strong` | `var(--md-sys-color-neutral-on-surface)` |
|
|
48
|
+
| `--a-fg-hover` | `var(--md-sys-color-neutral-on-surface-hover)` |
|
|
49
|
+
| `--a-fg-selected` | `var(--md-sys-color-neutral-on-surface-active)` |
|
|
50
|
+
| `--a-fg-disabled` | `var(--md-sys-color-neutral-on-surface-disabled)` |
|
|
51
|
+
| `--a-fg-inverse` | `var(--md-sys-color-neutral-inverse-on-surface)` |
|
|
52
|
+
| `--a-border` | `var(--md-sys-color-neutral-outline)` |
|
|
53
|
+
| `--a-border-subtle` | `var(--md-sys-color-neutral-outline-variant)` |
|
|
54
|
+
| `--a-border-strong` | `var(--md-sys-color-neutral-outline-active)` |
|
|
55
|
+
| `--a-border-hover` | `var(--md-sys-color-neutral-outline-hover)` |
|
|
56
|
+
| `--a-primary-strong` | `var(--md-sys-color-primary-active)` |
|
|
57
|
+
| `--a-primary` | `var(--md-sys-color-primary)` |
|
|
58
|
+
| `--a-primary-subtle` | `var(--md-sys-color-primary-container-high)` |
|
|
59
|
+
| `--a-primary-muted` | `var(--md-sys-color-primary-container)` |
|
|
60
|
+
| `--a-primary-hover` | `var(--md-sys-color-primary-hover)` |
|
|
61
|
+
| `--a-primary-active` | `var(--md-sys-color-primary-active)` |
|
|
62
|
+
| `--a-primary-selected` | `var(--md-sys-color-primary)` |
|
|
63
|
+
| `--a-link` | `var(--md-sys-color-primary-on-surface)` |
|
|
64
|
+
| `--a-link-hover` | `var(--md-sys-color-primary-on-surface-hover)` |
|
|
65
|
+
| `--a-link-visited` | `var(--md-sys-color-primary-on-surface-active)` |
|
|
66
|
+
| `--a-primary-text-strong` | `var(--md-sys-color-primary-on-primary)` |
|
|
67
|
+
| `--a-primary-text` | `var(--md-sys-color-primary-on-surface)` |
|
|
68
|
+
| `--a-primary-text-subtle` | `var(--md-sys-color-primary-on-surface-variant)` |
|
|
69
|
+
| `--a-primary-text-disabled` | `var(--md-sys-color-primary-on-surface-disabled)` |
|
|
70
|
+
| `--a-primary-border-subtle` | `var(--md-sys-color-primary-outline-variant)` |
|
|
71
|
+
| `--a-primary-border` | `var(--md-sys-color-primary-outline)` |
|
|
72
|
+
| `--a-primary-border-strong` | `var(--md-sys-color-primary-outline-active)` |
|
|
73
|
+
| `--a-primary-bg` | `var(--a-primary)` |
|
|
74
|
+
| `--a-primary-bg-hover` | `var(--a-primary-hover)` |
|
|
75
|
+
| `--a-primary-bg-active` | `var(--a-primary-active)` |
|
|
76
|
+
| `--a-primary-fg` | `var(--a-primary-text-strong)` |
|
|
77
|
+
| `--a-primary-fg-hover` | `var(--a-primary-text-strong)` |
|
|
78
|
+
| `--a-primary-border-hover` | `var(--a-primary-border-strong)` |
|
|
79
|
+
| `--a-primary-container-disabled` | `var(--md-sys-color-primary-container-disabled)` |
|
|
80
|
+
| `--a-brand-strong` | `var(--a-brand-60)` |
|
|
81
|
+
| `--a-brand` | `var(--a-brand-50)` |
|
|
82
|
+
| `--a-brand-subtle` | `var(--a-brand-40)` |
|
|
83
|
+
| `--a-brand-muted` | `var(--a-brand-30)` |
|
|
84
|
+
| `--a-brand-hover` | `var(--a-brand-60)` |
|
|
85
|
+
| `--a-brand-active` | `var(--a-brand-60)` |
|
|
86
|
+
| `--a-brand-selected` | `var(--a-brand-40)` |
|
|
87
|
+
| `--a-brand-text-strong` | `light-dark(var(--a-brand-05-tint), var(--a-brand-05-tint))` |
|
|
88
|
+
| `--a-brand-text` | `light-dark(var(--a-brand-10-tint), var(--a-brand-10-tint))` |
|
|
89
|
+
| `--a-brand-text-subtle` | `light-dark(var(--a-brand-30-tint), var(--a-brand-30-tint))` |
|
|
90
|
+
| `--a-brand-text-disabled` | `light-dark(var(--a-brand-60-shade), var(--a-brand-60-tint))` |
|
|
91
|
+
| `--a-brand-border-subtle` | `var(--a-brand-30)` |
|
|
92
|
+
| `--a-brand-border` | `var(--a-brand-45)` |
|
|
93
|
+
| `--a-brand-border-strong` | `var(--a-brand-60)` |
|
|
94
|
+
| `--a-brand-bg` | `var(--a-brand)` |
|
|
95
|
+
| `--a-brand-bg-hover` | `var(--a-brand-hover)` |
|
|
96
|
+
| `--a-brand-fg` | `var(--a-brand-text-strong)` |
|
|
97
|
+
| `--a-brand-fg-hover` | `var(--a-brand-text-strong)` |
|
|
98
|
+
| `--a-brand-border-hover` | `var(--a-brand-border-strong)` |
|
|
99
|
+
| `--a-info-strong` | `var(--md-sys-color-info-active)` |
|
|
100
|
+
| `--a-info` | `var(--md-sys-color-info)` |
|
|
101
|
+
| `--a-info-subtle` | `var(--md-sys-color-info-container-high)` |
|
|
102
|
+
| `--a-info-muted` | `var(--md-sys-color-info-container)` |
|
|
103
|
+
| `--a-info-hover` | `var(--md-sys-color-info-hover)` |
|
|
104
|
+
| `--a-info-active` | `var(--md-sys-color-info-active)` |
|
|
105
|
+
| `--a-info-selected` | `var(--md-sys-color-info)` |
|
|
106
|
+
| `--a-info-text-strong` | `var(--md-sys-color-info-on-info)` |
|
|
107
|
+
| `--a-info-text` | `var(--md-sys-color-info-on-surface)` |
|
|
108
|
+
| `--a-info-text-subtle` | `var(--md-sys-color-info-on-surface-variant)` |
|
|
109
|
+
| `--a-info-text-disabled` | `var(--md-sys-color-info-on-surface-disabled)` |
|
|
110
|
+
| `--a-info-border-subtle` | `var(--md-sys-color-info-outline-variant)` |
|
|
111
|
+
| `--a-info-border` | `var(--md-sys-color-info-outline)` |
|
|
112
|
+
| `--a-info-border-strong` | `var(--md-sys-color-info-outline-active)` |
|
|
113
|
+
| `--a-info-bg` | `var(--a-info)` |
|
|
114
|
+
| `--a-info-bg-hover` | `var(--a-info-hover)` |
|
|
115
|
+
| `--a-info-fg` | `var(--a-info-text-strong)` |
|
|
116
|
+
| `--a-info-fg-hover` | `var(--a-info-text-strong)` |
|
|
117
|
+
| `--a-info-border-hover` | `var(--a-info-border-strong)` |
|
|
118
|
+
| `--a-info-container-disabled` | `var(--md-sys-color-info-container-disabled)` |
|
|
119
|
+
| `--a-success-strong` | `var(--md-sys-color-success-active)` |
|
|
120
|
+
| `--a-success` | `var(--md-sys-color-success)` |
|
|
121
|
+
| `--a-success-subtle` | `var(--md-sys-color-success-container-high)` |
|
|
122
|
+
| `--a-success-muted` | `var(--md-sys-color-success-container)` |
|
|
123
|
+
| `--a-success-hover` | `var(--md-sys-color-success-hover)` |
|
|
124
|
+
| `--a-success-active` | `var(--md-sys-color-success-active)` |
|
|
125
|
+
| `--a-success-selected` | `var(--md-sys-color-success)` |
|
|
126
|
+
| `--a-success-text-strong` | `var(--md-sys-color-success-on-success)` |
|
|
127
|
+
| `--a-success-text` | `var(--md-sys-color-success-on-surface)` |
|
|
128
|
+
| `--a-success-text-subtle` | `var(--md-sys-color-success-on-surface-variant)` |
|
|
129
|
+
| `--a-success-text-disabled` | `var(--md-sys-color-success-on-surface-disabled)` |
|
|
130
|
+
| `--a-success-border-subtle` | `var(--md-sys-color-success-outline-variant)` |
|
|
131
|
+
| `--a-success-border` | `var(--md-sys-color-success-outline)` |
|
|
132
|
+
| `--a-success-border-strong` | `var(--md-sys-color-success-outline-active)` |
|
|
133
|
+
| `--a-success-bg` | `var(--a-success)` |
|
|
134
|
+
| `--a-success-bg-hover` | `var(--a-success-hover)` |
|
|
135
|
+
| `--a-success-fg` | `var(--a-success-text-strong)` |
|
|
136
|
+
| `--a-success-fg-hover` | `var(--a-success-text-strong)` |
|
|
137
|
+
| `--a-success-border-hover` | `var(--a-success-border-strong)` |
|
|
138
|
+
| `--a-success-container-disabled` | `var(--md-sys-color-success-container-disabled)` |
|
|
139
|
+
| `--a-warning-strong` | `var(--md-sys-color-warning-active)` |
|
|
140
|
+
| `--a-warning` | `var(--md-sys-color-warning)` |
|
|
141
|
+
| `--a-warning-subtle` | `var(--md-sys-color-warning-container-high)` |
|
|
142
|
+
| `--a-warning-muted` | `var(--md-sys-color-warning-container)` |
|
|
143
|
+
| `--a-warning-hover` | `var(--md-sys-color-warning-hover)` |
|
|
144
|
+
| `--a-warning-active` | `var(--md-sys-color-warning-active)` |
|
|
145
|
+
| `--a-warning-selected` | `var(--md-sys-color-warning)` |
|
|
146
|
+
| `--a-warning-text-strong` | `var(--md-sys-color-warning-on-warning)` |
|
|
147
|
+
| `--a-warning-text` | `var(--md-sys-color-warning-on-surface)` |
|
|
148
|
+
| `--a-warning-text-subtle` | `var(--md-sys-color-warning-on-surface-variant)` |
|
|
149
|
+
| `--a-warning-text-disabled` | `var(--md-sys-color-warning-on-surface-disabled)` |
|
|
150
|
+
| `--a-warning-border-subtle` | `var(--md-sys-color-warning-outline-variant)` |
|
|
151
|
+
| `--a-warning-border` | `var(--md-sys-color-warning-outline)` |
|
|
152
|
+
| `--a-warning-border-strong` | `var(--md-sys-color-warning-outline-active)` |
|
|
153
|
+
| `--a-warning-bg` | `var(--a-warning)` |
|
|
154
|
+
| `--a-warning-bg-hover` | `var(--a-warning-hover)` |
|
|
155
|
+
| `--a-warning-fg` | `var(--a-warning-text-strong)` |
|
|
156
|
+
| `--a-warning-fg-hover` | `var(--a-warning-text-strong)` |
|
|
157
|
+
| `--a-warning-border-hover` | `var(--a-warning-border-strong)` |
|
|
158
|
+
| `--a-warning-container-disabled` | `var(--md-sys-color-warning-container-disabled)` |
|
|
159
|
+
| `--a-danger-strong` | `var(--md-sys-color-danger-active)` |
|
|
160
|
+
| `--a-danger` | `var(--md-sys-color-danger)` |
|
|
161
|
+
| `--a-danger-subtle` | `var(--md-sys-color-danger-container-high)` |
|
|
162
|
+
| `--a-danger-muted` | `var(--md-sys-color-danger-container)` |
|
|
163
|
+
| `--a-danger-hover` | `var(--md-sys-color-danger-hover)` |
|
|
164
|
+
| `--a-danger-active` | `var(--md-sys-color-danger-active)` |
|
|
165
|
+
| `--a-danger-selected` | `var(--md-sys-color-danger)` |
|
|
166
|
+
| `--a-danger-text-strong` | `var(--md-sys-color-danger-on-danger)` |
|
|
167
|
+
| `--a-danger-text` | `var(--md-sys-color-danger-on-surface)` |
|
|
168
|
+
| `--a-danger-text-subtle` | `var(--md-sys-color-danger-on-surface-variant)` |
|
|
169
|
+
| `--a-danger-text-disabled` | `var(--md-sys-color-danger-on-surface-disabled)` |
|
|
170
|
+
| `--a-danger-border-subtle` | `var(--md-sys-color-danger-outline-variant)` |
|
|
171
|
+
| `--a-danger-border` | `var(--md-sys-color-danger-outline)` |
|
|
172
|
+
| `--a-danger-border-strong` | `var(--md-sys-color-danger-outline-active)` |
|
|
173
|
+
| `--a-danger-bg` | `var(--a-danger)` |
|
|
174
|
+
| `--a-danger-bg-hover` | `var(--a-danger-hover)` |
|
|
175
|
+
| `--a-danger-fg` | `var(--a-danger-text-strong)` |
|
|
176
|
+
| `--a-danger-fg-hover` | `var(--a-danger-text-strong)` |
|
|
177
|
+
| `--a-danger-border-hover` | `var(--a-danger-border-strong)` |
|
|
178
|
+
| `--a-danger-container-disabled` | `var(--md-sys-color-danger-container-disabled)` |
|
|
179
|
+
| `--a-secondary-strong` | `var(--md-sys-color-secondary-active)` |
|
|
180
|
+
| `--a-secondary` | `var(--md-sys-color-secondary)` |
|
|
181
|
+
| `--a-secondary-subtle` | `var(--md-sys-color-secondary-container-high)` |
|
|
182
|
+
| `--a-secondary-muted` | `var(--md-sys-color-secondary-container)` |
|
|
183
|
+
| `--a-secondary-hover` | `var(--md-sys-color-secondary-hover)` |
|
|
184
|
+
| `--a-secondary-active` | `var(--md-sys-color-secondary-active)` |
|
|
185
|
+
| `--a-secondary-selected` | `var(--md-sys-color-secondary)` |
|
|
186
|
+
| `--a-secondary-text-strong` | `var(--md-sys-color-secondary-on-secondary)` |
|
|
187
|
+
| `--a-secondary-text` | `var(--md-sys-color-secondary-on-surface)` |
|
|
188
|
+
| `--a-secondary-text-subtle` | `var(--md-sys-color-secondary-on-surface-variant)` |
|
|
189
|
+
| `--a-secondary-text-disabled` | `var(--md-sys-color-secondary-on-surface-disabled)` |
|
|
190
|
+
| `--a-secondary-border-subtle` | `var(--md-sys-color-secondary-outline-variant)` |
|
|
191
|
+
| `--a-secondary-border` | `var(--md-sys-color-secondary-outline)` |
|
|
192
|
+
| `--a-secondary-border-strong` | `var(--md-sys-color-secondary-outline-active)` |
|
|
193
|
+
| `--a-secondary-bg` | `var(--a-secondary)` |
|
|
194
|
+
| `--a-secondary-bg-hover` | `var(--a-secondary-hover)` |
|
|
195
|
+
| `--a-secondary-fg` | `var(--a-secondary-text-strong)` |
|
|
196
|
+
| `--a-secondary-fg-hover` | `var(--a-secondary-text-strong)` |
|
|
197
|
+
| `--a-secondary-border-hover` | `var(--a-secondary-border-strong)` |
|
|
198
|
+
| `--a-secondary-container-disabled` | `var(--md-sys-color-secondary-container-disabled)` |
|
|
199
|
+
| `--a-tertiary-strong` | `var(--md-sys-color-tertiary-active)` |
|
|
200
|
+
| `--a-tertiary` | `var(--md-sys-color-tertiary)` |
|
|
201
|
+
| `--a-tertiary-subtle` | `var(--md-sys-color-tertiary-container-high)` |
|
|
202
|
+
| `--a-tertiary-muted` | `var(--md-sys-color-tertiary-container)` |
|
|
203
|
+
| `--a-tertiary-hover` | `var(--md-sys-color-tertiary-hover)` |
|
|
204
|
+
| `--a-tertiary-active` | `var(--md-sys-color-tertiary-active)` |
|
|
205
|
+
| `--a-tertiary-selected` | `var(--md-sys-color-tertiary)` |
|
|
206
|
+
| `--a-tertiary-text-strong` | `var(--md-sys-color-tertiary-on-tertiary)` |
|
|
207
|
+
| `--a-tertiary-text` | `var(--md-sys-color-tertiary-on-surface)` |
|
|
208
|
+
| `--a-tertiary-text-subtle` | `var(--md-sys-color-tertiary-on-surface-variant)` |
|
|
209
|
+
| `--a-tertiary-text-disabled` | `var(--md-sys-color-tertiary-on-surface-disabled)` |
|
|
210
|
+
| `--a-tertiary-border-subtle` | `var(--md-sys-color-tertiary-outline-variant)` |
|
|
211
|
+
| `--a-tertiary-border` | `var(--md-sys-color-tertiary-outline)` |
|
|
212
|
+
| `--a-tertiary-border-strong` | `var(--md-sys-color-tertiary-outline-active)` |
|
|
213
|
+
| `--a-tertiary-bg` | `var(--a-tertiary)` |
|
|
214
|
+
| `--a-tertiary-bg-hover` | `var(--a-tertiary-hover)` |
|
|
215
|
+
| `--a-tertiary-fg` | `var(--a-tertiary-text-strong)` |
|
|
216
|
+
| `--a-tertiary-fg-hover` | `var(--a-tertiary-text-strong)` |
|
|
217
|
+
| `--a-tertiary-border-hover` | `var(--a-tertiary-border-strong)` |
|
|
218
|
+
| `--a-tertiary-container-disabled` | `var(--md-sys-color-tertiary-container-disabled)` |
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Pairing laws — depth and adia-specific notes
|
|
2
|
+
|
|
3
|
+
_Load when a "which token" answer needs the law's reasoning or its edge
|
|
4
|
+
cases, not just the rule. Stable doctrine, hand-maintained; the volatile
|
|
5
|
+
rosters live in the two GENERATED siblings. Sources: the framework's
|
|
6
|
+
`component-token-contract.md` + `material-color-bridge-contract.md`
|
|
7
|
+
(monorepo), mirrored here for consumer installs._
|
|
8
|
+
|
|
9
|
+
## 1 · Pairing — ink on its own palette's ground
|
|
10
|
+
|
|
11
|
+
The defect this prevents: `neutral` ink on a `danger-container` fill reads
|
|
12
|
+
fine in light, breaks in dark — the two palettes' schemes flip on different
|
|
13
|
+
curves. The ink for ANY palette's surface/container/background is that same
|
|
14
|
+
palette's `-on-surface` family; the ink for its solid accent fill is
|
|
15
|
+
`-on-{p}`. If you're writing a fill from palette A and ink from palette B,
|
|
16
|
+
stop — one of them is the wrong role.
|
|
17
|
+
|
|
18
|
+
## 2 · States as families
|
|
19
|
+
|
|
20
|
+
`-hover/-active/-disabled` siblings are real, tuned tokens — not derivable.
|
|
21
|
+
`opacity: .5` on a disabled control also fades its border and any icon
|
|
22
|
+
differently than the tuned pair does, and `color-mix()` breaks under scheme
|
|
23
|
+
flip. Where the roster shows no state sibling (e.g. `background`), the role
|
|
24
|
+
genuinely has no state — don't invent one.
|
|
25
|
+
|
|
26
|
+
## 3 · Scheme baked in
|
|
27
|
+
|
|
28
|
+
Every role is a `light-dark()` pair. Consequences: write colors once; a
|
|
29
|
+
subtree forced to one scheme (`color-scheme: dark` on a preview pane)
|
|
30
|
+
re-resolves every role inside it automatically; per-color
|
|
31
|
+
`@media (prefers-color-scheme)` overrides fork the source of truth and are
|
|
32
|
+
the first thing to rot. The embedded-app pattern's scheme owner is the
|
|
33
|
+
shell element's `data-scheme`, not `html` — test dark mode there.
|
|
34
|
+
|
|
35
|
+
## 4 · Elevation = the surface ladder
|
|
36
|
+
|
|
37
|
+
Two axes, deliberately distinct: `-dim…-bright` shifts perceived light;
|
|
38
|
+
`-lowest…-highest` shifts stacking prominence. A card that must read
|
|
39
|
+
"raised" takes a `-high` tier, not a shadow bump; a recessed well takes
|
|
40
|
+
`-dim`/`-low`. The `--a-canvas-*` aliases map onto this ladder (see the
|
|
41
|
+
alias table) — pick the tier, not a hand-tuned value.
|
|
42
|
+
|
|
43
|
+
## 5 · On-accent fixed light — the operator ruling
|
|
44
|
+
|
|
45
|
+
`-on-{p}` resolves to the palette's light end in BOTH schemes, for all
|
|
46
|
+
palettes — including `warning`, where white-on-amber measurably misses
|
|
47
|
+
WCAG AA. Ruled 2026-07-16 (framework color-bridge contract, steps 9–10):
|
|
48
|
+
the tokens are upstream-canonical; fill-pair contrast is an upstream
|
|
49
|
+
design decision, accepted at kit level. Do not patch locally (dark text,
|
|
50
|
+
auto-contrast, per-component overrides) — a change here arrives as a
|
|
51
|
+
regenerated upstream export, never an app-side fix. Canvas-TEXT contrast
|
|
52
|
+
(body text on page surfaces) is a different matter and IS gated (the
|
|
53
|
+
framework's `verify:contrast`, 4.5:1 AA).
|
|
54
|
+
|
|
55
|
+
## 6 · Named purpose over coincidental value
|
|
56
|
+
|
|
57
|
+
- `--a-data-0..9` color IDENTITY (chart series, groups, tracks); the
|
|
58
|
+
intent palettes color STATE. Mixing them makes a chart lie.
|
|
59
|
+
- Text/icons on a filled primary disc: `--a-chrome-light` (theme-stable
|
|
60
|
+
against any fill) — radio dots, step circles, badge counters.
|
|
61
|
+
- A token whose current value happens to look right is still the wrong
|
|
62
|
+
token if its name says otherwise — the next palette regeneration breaks
|
|
63
|
+
exactly these.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<!-- GENERATED — do not edit. Source: packages/web-components/styles/colors/material-static.css.
|
|
2
|
+
Provenance: produced in the framework monorepo at cut time by
|
|
3
|
+
scripts/release/check-token-semantics-sync.mjs (producer-side tooling,
|
|
4
|
+
not runnable from a consumer install — in a consumer repo this file
|
|
5
|
+
describes the version you installed). -->
|
|
6
|
+
|
|
7
|
+
# Role roster — the `--md-sys-color-*` semantic layer
|
|
8
|
+
|
|
9
|
+
**Palettes (8):** neutral (53) · primary (53) · secondary (53) · tertiary (53) · info (53) · success (53) · warning (53) · danger (53) — every palette carries the full roster.
|
|
10
|
+
|
|
11
|
+
Grammar: `--md-sys-color-{palette}{suffix}`. Chrome palette = `neutral`; brand accent = `primary`; `secondary`/`tertiary` support; `info/success/warning/danger` carry MEANING only. Consume via `var()` — never a raw `-050…-950` stop, never a hex.
|
|
12
|
+
|
|
13
|
+
| Family | Suffixes (`{p}` = the palette's own slug) | Meaning |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| accent | `(bare)` | The bare accent — the palette's main solid fill (CTAs for primary; the intent color for intents) |
|
|
16
|
+
| accent variants | `-dim` `-bright` `-low` `-high` | Tonal variants of the accent for de/emphasis without leaving the palette |
|
|
17
|
+
| accent states | `-hover` `-active` `-disabled` | The solid accent fill's baked states — never synthesize with opacity/color-mix |
|
|
18
|
+
| on-accent | `-on-{p}` `-on-{p}-variant` `-on-{p}-hover` `-on-{p}-active` `-on-{p}-disabled` | Ink on the palette's own solid fill (the accent). FIXED LIGHT in both schemes by design — never "fix" with dark text or auto-contrast |
|
|
19
|
+
| on-surface | `-on-surface` `-on-surface-variant` `-on-surface-hover` `-on-surface-active` `-on-surface-disabled` | Text/icon ink on the SAME palette's surfaces/containers/background — the pairing law's ink side, with baked states |
|
|
20
|
+
| placeholder | `-placeholder` | Form placeholder ink |
|
|
21
|
+
| outline | `-outline` `-outline-variant` `-outline-hover` `-outline-active` `-outline-disabled` | Borders/dividers/rings, with a softer -variant and baked states |
|
|
22
|
+
| container | `-container` `-container-low` `-container-high` `-container-hover` `-container-active` `-container-disabled` | Translucent tint fills for chips/badges/soft emphasis (distinct from the opaque surface ladder), with baked states |
|
|
23
|
+
| inverse | `-inverse-surface` `-inverse-on-surface` | The opposite-scheme pocket (tooltips, snackbars) |
|
|
24
|
+
| background | `-background` | The palette's page-level backdrop |
|
|
25
|
+
| surface ladder | `-surface` `-surface-dimmest` `-surface-dimmer` `-surface-dim` `-surface-bright` `-surface-brighter` `-surface-brightest` `-surface-lowest` `-surface-lower` `-surface-low` `-surface-high` `-surface-higher` `-surface-highest` | Elevation IS this ladder (dim↔bright, low↔high) — raise/recess with surfaces, never with opacity or ad-hoc shadows |
|
|
26
|
+
| scrim | `-scrim-weakest` `-scrim-weaker` `-scrim-weak` `-scrim` `-scrim-strong` `-scrim-stronger` `-scrim-strongest` | Scrim ladder — 7-step overlay dims for layering under sheets/dialogs/toasts |
|