From 672f29fd98aa09e0de404b7b4928ac3b691c338f Mon Sep 17 00:00:00 2001 From: Hiroki Uemura Date: Fri, 30 Oct 2026 09:52:25 +0900 Subject: [PATCH 1/2] docs(theme): keep the hover step and record why Co-Authored-By: Claude Opus 5.5 --- .changeset/hover-step-stays.md | 5 +++++ decisions/semantic-color-roles.md | 7 +++++-- docs-manifest.json | 6 +++--- docs-src/concepts/styling-theming.docs.outline.md | 2 +- docs/concepts/styling-theming.md | 2 +- 5 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 .changeset/hover-step-stays.md diff --git a/.changeset/hover-step-stays.md b/.changeset/hover-step-stays.md new file mode 100644 index 000000000..a040aa8dc --- /dev/null +++ b/.changeset/hover-step-stays.md @@ -0,0 +1,5 @@ +--- +"@tailor-platform/app-shell": patch +--- + +Docs: the styling guide and the decision record now say why `text` on `surface-hover` stays below 4.5:1 for `danger` and `success` in light mode. A lighter step would make the tinted background hard to tell apart from the page, and the hover harder to see. No colour value changes. diff --git a/decisions/semantic-color-roles.md b/decisions/semantic-color-roles.md index d940d0784..fd0db0480 100644 --- a/decisions/semantic-color-roles.md +++ b/decisions/semantic-color-roles.md @@ -64,7 +64,7 @@ A unit test (`semantic-contrast.test.ts`) computes contrast from `default.css` f Not guaranteed: -- Hover surfaces. Light-mode text on `surface-hover` is 4.22:1 (danger, over both pages), 4.34:1 (success over `--background`) and 4.51:1 (success over `--card`). Subtle Badge hover can fall below 4.5:1 for danger and success. The test holds `text` on `surface-hover` at a floor of 4.2:1 so it cannot get worse unnoticed. This is a floor, not a pass. Changing the step is a design decision for a later change. +- Hover surfaces. Light-mode text on `surface-hover` is 4.22:1 (danger, over both pages), 4.34:1 (success over `--background`) and 4.51:1 (success over `--card`). Subtle Badge hover can fall below 4.5:1 for danger and success. The test holds `text` on `surface-hover` at a floor of 4.2:1 so it cannot get worse unnoticed. This is a floor, not a pass. The step is kept on purpose; see the update of 2026-10-30 below. - The `cream` and `bloom` palettes and their tinted shell backgrounds (for example `text` on `surface` over the bloom light shell `#efe8ff` is 4.16:1 for success and 4.15:1 for danger). - The neutral intent, which keeps the pre-existing system tokens. - Warning `solid` against the card as a fill: 2.15:1 in light mode. `--status-attention` is unchanged (`#f59e0b`), so `text-status-attention` is still low contrast on light surfaces. CsvImporter now uses the warning text role instead. @@ -152,7 +152,10 @@ Three open points from the remaining-work issue ([platform-planning#2208](https: AppShell's thresholds are 4.5:1 for text (WCAG 1.4.3) and 3:1 for non-text (WCAG 1.4.11). `tests/browser/semantic-contrast.test.ts` now runs the same checks for `default`, `cream` and `bloom`, in light and dark mode, on `--card` and `--background`. The pairs and the hover floor are unchanged, and all three palettes pass. The styling guide states the thresholds and the exceptions: -- `text` on `surface-hover` stays at the 4.2:1 floor. Choosing another step is a visible change for a later PR. +- `text` on `surface-hover` stays at the 4.2:1 floor. + +**Update 2026-10-30: the hover step stays.** We compared three ways to reach 4.5:1 for `text` on `surface-hover` in light mode: one lighter step for both surfaces (`surface` a2, `surface-hover` a3), a darker text step on hover only (step 12, which needs a new role), and the darker text step in every state (as `warning` already does). We keep a3 and a4. The hover state is short and the text is still above 4.2:1. A lighter step has two costs. The tinted background becomes hard to tell apart from the card: on `--card`, the danger `surface` differs from the card by 1.16:1 with a3, and by 1.06:1 with a2. The hover also becomes harder to see: the two backgrounds differ by 1.16:1 for danger with a3 and a4, and by 1.10:1 with a2 and a3. This does not meet WCAG 1.4.3 for the hover state, so the styling guide lists it as an exception, and the test keeps the 4.2:1 floor. + - In `cream` and `bloom`, the main content area is transparent over the shell gradient. At the top of the bloom light gradient (55% of `--shell-gradient-base`), `text` on `surface` is 4.49:1 for success and 4.48:1 for danger. cream light is 4.68:1 or more. The figure under "Not guaranteed" (4.16:1 over `#efe8ff`) used `--shell-gradient-base` itself, which the gradient covers. - `warning` `solid` and `indicator` are 2.15:1 against a light card. They are used with a label. - The neutral intent is not checked. diff --git a/docs-manifest.json b/docs-manifest.json index ac5a6abef..1bd70f528 100644 --- a/docs-manifest.json +++ b/docs-manifest.json @@ -1381,9 +1381,9 @@ "symbols": [], "hashes": { "typeSurface": null, - "outline": "4081996c98e029b0", + "outline": "c8d9f45e65d3b347", "snapshot": null, - "outputMd": "1ed3e6d92e582e26", + "outputMd": "41456a58c8ff7a4f", "examples": "4d19f4f688e0f0ac" } }, @@ -1770,7 +1770,7 @@ "packages/core/skills/app-shell-patterns/references/concepts/modules-and-resources.md": "bf15b5460f22d165", "packages/core/skills/app-shell-patterns/references/concepts/routing-navigation.md": "8034c7f885994b29", "packages/core/skills/app-shell-patterns/references/concepts/sidebar-navigation.md": "5a3c8bac248061f9", - "packages/core/skills/app-shell-patterns/references/concepts/styling-theming.md": "1ed3e6d92e582e26", + "packages/core/skills/app-shell-patterns/references/concepts/styling-theming.md": "41456a58c8ff7a4f", "packages/core/skills/app-shell-patterns/references/components/action-panel.md": "dc861082aa9610af", "packages/core/skills/app-shell-patterns/references/components/activity-card.md": "4f386e49380fb0b0", "packages/core/skills/app-shell-patterns/references/components/ai-chat.md": "824d1aa36bb7f194", diff --git a/docs-src/concepts/styling-theming.docs.outline.md b/docs-src/concepts/styling-theming.docs.outline.md index db5b22b6f..f3ca19ca4 100644 --- a/docs-src/concepts/styling-theming.docs.outline.md +++ b/docs-src/concepts/styling-theming.docs.outline.md @@ -204,7 +204,7 @@ The hue roles have the same values in every shipped palette. `cream` and `bloom` **Contrast.** AppShell's thresholds are 4.5:1 for text (WCAG 1.4.3) and 3:1 for non-text (WCAG 1.4.11). In every shipped palette (`default`, `cream`, `bloom`), in light and dark mode, on `--card` and `--background`, `text` on `surface` and `contrast` on `solid` and `solid-hover` are at least 4.5:1 for the four hue intents, and `danger` `solid` (the invalid-input border) is at least 3:1. A browser test checks this in Chromium against the built stylesheet. Known exceptions: -- `text` on `surface-hover` is below 4.5:1 for `danger` and `success` in light mode. The test holds it at 4.2:1 or more. +- `text` on `surface-hover` is below 4.5:1 for `danger` and `success` in light mode. This is on purpose: a lighter step would make the tinted background hard to tell apart from the page, and the hover harder to see. The test holds it at 4.2:1 or more. - In `cream` and `bloom`, the main content area is transparent over the shell gradient. At the top of the `bloom` light gradient, `text` on `surface` is 4.49:1 for `success` and 4.48:1 for `danger`. Put status content on a card when it needs to pass. - `warning` `solid` and `indicator` are 2.15:1 against a light card. Use them with a label, not as the only sign of a state. - The `neutral` intent reads the system tokens and is not checked. diff --git a/docs/concepts/styling-theming.md b/docs/concepts/styling-theming.md index cab965f88..651f79e16 100644 --- a/docs/concepts/styling-theming.md +++ b/docs/concepts/styling-theming.md @@ -221,7 +221,7 @@ The hue roles have the same values in every shipped palette. `cream` and `bloom` **Contrast.** AppShell's thresholds are 4.5:1 for text (WCAG 1.4.3) and 3:1 for non-text (WCAG 1.4.11). In every shipped palette (`default`, `cream`, `bloom`), in light and dark mode, on `--card` and `--background`, `text` on `surface` and `contrast` on `solid` and `solid-hover` are at least 4.5:1 for the four hue intents, and `danger` `solid` (the invalid-input border) is at least 3:1. A browser test checks this in Chromium against the built stylesheet. Known exceptions: -- `text` on `surface-hover` is below 4.5:1 for `danger` and `success` in light mode. The test holds it at 4.2:1 or more. +- `text` on `surface-hover` is below 4.5:1 for `danger` and `success` in light mode. This is on purpose: a lighter step would make the tinted background hard to tell apart from the page, and the hover harder to see. The test holds it at 4.2:1 or more. - In `cream` and `bloom`, the main content area is transparent over the shell gradient. At the top of the `bloom` light gradient, `text` on `surface` is 4.49:1 for `success` and 4.48:1 for `danger`. Put status content on a card when it needs to pass. - `warning` `solid` and `indicator` are 2.15:1 against a light card. Use them with a label, not as the only sign of a state. - The `neutral` intent reads the system tokens and is not checked. From 020e5fee419b48eed5a8abadd72b14e206147c74 Mon Sep 17 00:00:00 2001 From: Hiroki Uemura Date: Fri, 30 Oct 2026 10:00:17 +0900 Subject: [PATCH 2/2] chore: drop the changeset, the change does not affect consumers Co-Authored-By: Claude Opus 5.5 --- .changeset/hover-step-stays.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .changeset/hover-step-stays.md diff --git a/.changeset/hover-step-stays.md b/.changeset/hover-step-stays.md deleted file mode 100644 index a040aa8dc..000000000 --- a/.changeset/hover-step-stays.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@tailor-platform/app-shell": patch ---- - -Docs: the styling guide and the decision record now say why `text` on `surface-hover` stays below 4.5:1 for `danger` and `success` in light mode. A lighter step would make the tinted background hard to tell apart from the page, and the hover harder to see. No colour value changes.