Restyle the app in the UI language v2 foundations #238

Merged
Grandiras merged 5 commits from ui-v2-foundations into main 2026-10-02 23:26:12 +00:00
Owner

Ports the UI language v2 foundations from the canvas onto the app's current structure. Nothing about how the app behaves changes; the sidebar, inspector, Done deck, save-on-leave and Undo wait for sign-off and come as separate PRs.

What changes

  • Type: Inter (variable, with an optical-size axis, vendored like the old fonts; 72 KB) replaces Figtree and Bricolage Grotesque, which are deleted. UI notes lose their italics; markdown emphasis keeps them.
  • Tokens: warm neutrals, translucent --fill-* for fields, tracks and hovers, --bg-panel/--bg-group/--bg-thumb, concentric radii (panel 26 / tray 22 / card 14 / field 12 / row 10), and two-way depth. Trays are recessed (--shadow-recessed); tiles and panels are raised (--shadow-sm…xl), with shadow colours as tokens.
  • The board's colour is the accent. BoardTint puts the open board's BoardPalette colour on :root for the board, its settings and its calendar; a Home tile wears its own inline. One block re-lights it in OKLCH:
    • --brand fills; white text on it passes AA in both themes. Six of the eight palette hues fail AA at their own lightness.
    • --brand-ink carries accent text, icons, rings and focus.
    • The ground and trays take a 5–7 % tint.
  • Components:
    • Chosen tabs, segments and theme pills are a raised white thumb on a fill track, not an accent block.
    • Fields are a fill with an accent ring and halo on focus.
    • The card dialog is a panel of white groups.
    • Tag chips are a re-lit tint with a dot; an unpicked choice is an outline.
    • Columns are recessed trays, and "+ Add card" is a quiet row.
    • The header is translucent material.
    • Buttons press (scale .97) instead of floating, and danger buttons are tinted.
  • Dark theme-color follows the new --bg-1 (#292725, spec updated), the manifest splash follows the new ground, offline.html matches, there is a changelog line in both locales, and docs/frontend.md (Theming) explains the accent, chosen states and depth.

Found by the e2e suite and fixed:

  • A real regression. A backdrop-filter on the header made it the containing block of its fixed children, so the nav menu's click-catcher shrank to the header and clicking outside no longer closed the menu. The blur now sits on a ::before layer.
  • Two outdated shadow checks. The "no shadow cast onto the bar" checks read the new inset top-edge highlight as a downward shadow; they now skip inset shadows.
  • The changelog's unreleased dot keeps the brand fill its spec reads.

Checked

  • tools/verify.sh passes (584 tests).
  • Before/after screenshots compared, in light and dark: board, card dialog, Home, calendar, timeline, every settings tab, Members, Profile, sign-in, the menu, search and the phone board.
  • Full e2e suite on an isolated stack: 151/156 passed before the fixes above. A re-run on the head is in progress.

Follow-up: the traced canvas frames now predate this look (noted in the docs). The tracer's seed no longer runs against the current schema, and a separate task fixes it and retraces.

🤖 Generated with Claude Code

Ports the UI language v2 **foundations** from the canvas onto the app's current structure. Nothing about how the app behaves changes; the sidebar, inspector, Done deck, save-on-leave and Undo wait for sign-off and come as separate PRs. **What changes** - **Type:** Inter (variable, with an optical-size axis, vendored like the old fonts; 72 KB) replaces Figtree and Bricolage Grotesque, which are deleted. UI notes lose their italics; markdown emphasis keeps them. - **Tokens:** warm neutrals, translucent `--fill-*` for fields, tracks and hovers, `--bg-panel`/`--bg-group`/`--bg-thumb`, concentric radii (panel 26 / tray 22 / card 14 / field 12 / row 10), and two-way depth. Trays are recessed (`--shadow-recessed`); tiles and panels are raised (`--shadow-sm`…`xl`), with shadow colours as tokens. - **The board's colour is the accent.** `BoardTint` puts the open board's `BoardPalette` colour on `:root` for the board, its settings and its calendar; a Home tile wears its own inline. One block re-lights it in OKLCH: - `--brand` fills; white text on it passes AA in both themes. Six of the eight palette hues fail AA at their own lightness. - `--brand-ink` carries accent text, icons, rings and focus. - The ground and trays take a 5–7 % tint. - **Components:** - Chosen tabs, segments and theme pills are a raised white thumb on a fill track, not an accent block. - Fields are a fill with an accent ring and halo on focus. - The card dialog is a panel of white groups. - Tag chips are a re-lit tint with a dot; an unpicked choice is an outline. - Columns are recessed trays, and "+ Add card" is a quiet row. - The header is translucent material. - Buttons press (`scale .97`) instead of floating, and danger buttons are tinted. - Dark `theme-color` follows the new `--bg-1` (`#292725`, spec updated), the manifest splash follows the new ground, `offline.html` matches, there is a changelog line in both locales, and `docs/frontend.md` (Theming) explains the accent, chosen states and depth. **Found by the e2e suite and fixed:** - **A real regression.** A `backdrop-filter` on the header made it the containing block of its fixed children, so the nav menu's click-catcher shrank to the header and clicking outside no longer closed the menu. The blur now sits on a `::before` layer. - **Two outdated shadow checks.** The "no shadow cast onto the bar" checks read the new inset top-edge highlight as a downward shadow; they now skip inset shadows. - **The changelog's unreleased dot** keeps the brand fill its spec reads. **Checked** - `tools/verify.sh` passes (584 tests). - Before/after screenshots compared, in light and dark: board, card dialog, Home, calendar, timeline, every settings tab, Members, Profile, sign-in, the menu, search and the phone board. - Full e2e suite on an isolated stack: 151/156 passed before the fixes above. A re-run on the head is in progress. **Follow-up:** the traced canvas frames now predate this look (noted in the docs). The tracer's seed no longer runs against the current schema, and a separate task fixes it and retraces. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
app.css takes the v2 canvas's foundations onto today's structure: Inter in
place of Figtree and Bricolage, warm neutrals, concentric radii, two-way
depth (recessed trays, raised tiles and panels), and the open board's colour
as the accent. BoardTint sets --board-color on :root for a board, its
settings and its calendar; one block re-lights it in OKLCH into --brand for
fills and --brand-ink for text, icons and focus, and tints the ground and
trays. Chosen states become a raised thumb on a fill track, fields and
hovers translucent fills, the dialog a panel of white groups, tag chips a
re-lit tint with a dot.

Structure and behaviour (sidebar, inspector, Done deck, save on leave,
Undo) stay as they are until signed off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Inter is vendored upright only, and the language marks a quiet note with
its colour, not a slant. Markdown emphasis keeps its italics.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep fixed children of the header fixed, and let shadow checks skip insets
All checks were successful
CI / build (pull_request) Successful in 41s
e6a0de2748
A backdrop-filter on .board-header made it the containing block of its fixed
descendants, so the nav menu's click-catcher shrank to the header and a click
outside no longer closed the menu. The material moves to a ::before layer.

The unreleased changelog dot keeps the brand fill its spec reads, and the
"no shadow cast onto the bar" checks skip inset shadows: the top-edge
highlight of a raised surface casts nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator

🤖 Reviewing this PR — the review will link the full session transcript.

📜 Live transcript — updating every ~5 minutes while the review runs.

🤖 Reviewing this PR — the review will link the full session transcript. <!-- opencode-run:review --> 📜 [Live transcript](https://git.grandiras.net/Grandiras/opencode-bot/src/branch/opencode-logs/transcripts/Grandiras/Ponente/pr-238/run-2026-10-02T23-15-18-654Z.md) — updating every ~5 minutes while the review runs.
Collaborator

🤖 Reviewing this PR — follow along in the action run; the reply will link the full session transcript.

📜 Live transcript — updating every ~5 minutes while the task runs.

🤖 Reviewing this PR — follow along in [the action run](https://git.grandiras.net/Grandiras/claude-bot/actions/runs/667); the reply will link the full session transcript. <!-- claude-run:pr_review --> 📜 [Live transcript](https://git.grandiras.net/Grandiras/claude-bot/src/branch/claude-logs/transcripts/Grandiras/Ponente/pr-238/run-667.md) — updating every ~5 minutes while the task runs.
claude-reviewer approved these changes 2026-10-02 23:15:48 +00:00
Dismissed
claude-reviewer left a comment

✅ Verdict: approve — no blocking issues found.

This is a coherent restyle. It is token-driven, with the OKLCH accent block and --brand-ink split cleanly out, and the docs/frontend.md and changelog updates are in place. I read the diff only and did not run the app or the e2e suite.

  • Header fix: moving the backdrop-filter onto .board-header::before is the right fix for the fixed-children containing-block regression.
  • Shadow checks: the updated e2e checks split on commas outside parentheses and skip inset shadows, which is correct.
  • BoardTint: it is wired into the board, settings and calendar pages. The calendar only tints in single-board scope.
  • Leftover: .request-email-none { } is now an empty rule after its font-style was removed. It could be deleted.
  • Browser support: the CSS relies on relative color syntax (oklch(from …)) and light-dark(). That is fine for current evergreen browsers, but older browsers get no accent colours at all. This is worth confirming as an accepted floor.
  • Unverified: the PR notes a full e2e re-run on the head was still in progress. I'd confirm it is green before merging.

🧠 claude-sonnet-5-5 · ⏱ 0m 12s · 2 turns · tokens: 43.3k in / 1.5k out (+12.2k cache-read)
📜 Full session transcript

✅ **Verdict: approve** — no blocking issues found. This is a coherent restyle. It is token-driven, with the OKLCH accent block and `--brand-ink` split cleanly out, and the `docs/frontend.md` and changelog updates are in place. I read the diff only and did not run the app or the e2e suite. - **Header fix:** moving the `backdrop-filter` onto `.board-header::before` is the right fix for the fixed-children containing-block regression. - **Shadow checks:** the updated e2e checks split on commas outside parentheses and skip inset shadows, which is correct. - **`BoardTint`:** it is wired into the board, settings and calendar pages. The calendar only tints in single-board scope. - **Leftover:** `.request-email-none { }` is now an empty rule after its `font-style` was removed. It could be deleted. - **Browser support:** the CSS relies on relative color syntax (`oklch(from …)`) and `light-dark()`. That is fine for current evergreen browsers, but older browsers get no accent colours at all. This is worth confirming as an accepted floor. - **Unverified:** the PR notes a full e2e re-run on the head was still in progress. I'd confirm it is green before merging. --- 🧠 claude-sonnet-5-5 · ⏱ 0m 12s · 2 turns · tokens: 43.3k in / 1.5k out (+12.2k cache-read) 📜 [Full session transcript](https://git.grandiras.net/Grandiras/claude-bot/src/branch/claude-logs/transcripts/Grandiras/Ponente/pr-238/run-667.md) <!-- claude-verdict:approve --> <!-- claude-reviewed-head:e6a0de27480a230a6f0d092487cb069fbe6b97b5 -->
opencode-reviewer approved these changes 2026-10-02 23:21:18 +00:00
Dismissed
opencode-reviewer left a comment

✅ Verdict: approve — no blocking issues found.

Good to merge. This is a large, careful restyle and the parts that could silently break check out:

  • The AA claim is real. I computed WCAG contrast for all eight BoardPalette hues re-lit at the declared lightnesses: white on --brand is ≥ ~4.75:1 in both themes (worst: teal/green in dark), and --brand-ink is ≥ ~6:1 on its surfaces. The "six of eight fail at their own lightness" premise holds too.
  • The header regression fix is correct. Moving backdrop-filter to a z-index: -1 ::before inside the sticky header keeps the header out of the containing-block business for fixed children while the sticky stacking context still paints the pseudo above the scrolled content.
  • Values are consistent. #292725 matches across App.razor (both the meta tag and the head script), --bg-1 dark, and prefs.spec.js; the manifest splash and offline.html follow the new ground; the two shadow e2e checks now correctly split shadows on commas outside parens and skip inset layers, and every non-inset segment still yields offsets.
  • BoardTint wiring is clean: html:root in HeadContent outranks the :root default and is withdrawn on unmount, the calendar only tints when a board is scoped, and the [style*="--board-color"] re-light block covers the inline cases (Home tiles, BoardPhoneBar).

Minor notes, none blocking:

  • --warning / --warning-bg and --toast-accent are defined but not used anywhere yet (var(--warning) appears only in --warning-bg's own definition). Fine as groundwork; just confirming it's intentional.
  • The logo SVGs (BrandMark.razor, icons) still use #7c3aed while the default accent is now the re-lit #7048e8 — presumably the brand mark keeps its own violet, but worth a glance that the header mark doesn't visibly clash with the new default accent next to it.
  • design/trace/build.py still maps Figtree/Bricolage families; consistent with the docs note that traced frames predate the restyle and the tracer fix is a separate task.

The one thing I'd like an answer on (see the inline finding) is the browser-support band between light-dark() and relative color syntax — either a @supports fallback or a documented floor.


⏱ 5m 59s · 10 steps · $0.0295 · tokens: 82.0k in / 3.7k out (+323.5k cache-read) · Go: 5h 0% · wk 7% · mo 86%
📜 Full session transcript

✅ **Verdict: approve** — no blocking issues found. Good to merge. This is a large, careful restyle and the parts that could silently break check out: - **The AA claim is real.** I computed WCAG contrast for all eight `BoardPalette` hues re-lit at the declared lightnesses: white on `--brand` is ≥ ~4.75:1 in both themes (worst: teal/green in dark), and `--brand-ink` is ≥ ~6:1 on its surfaces. The "six of eight fail at their own lightness" premise holds too. - **The header regression fix is correct.** Moving `backdrop-filter` to a `z-index: -1` `::before` inside the sticky header keeps the header out of the containing-block business for fixed children while the sticky stacking context still paints the pseudo above the scrolled content. - **Values are consistent.** `#292725` matches across `App.razor` (both the meta tag and the head script), `--bg-1` dark, and `prefs.spec.js`; the manifest splash and `offline.html` follow the new ground; the two shadow e2e checks now correctly split shadows on commas outside parens and skip inset layers, and every non-inset segment still yields offsets. - `BoardTint` wiring is clean: `html:root` in `HeadContent` outranks the `:root` default and is withdrawn on unmount, the calendar only tints when a board is scoped, and the `[style*="--board-color"]` re-light block covers the inline cases (Home tiles, `BoardPhoneBar`). Minor notes, none blocking: - `--warning` / `--warning-bg` and `--toast-accent` are defined but not used anywhere yet (`var(--warning)` appears only in `--warning-bg`'s own definition). Fine as groundwork; just confirming it's intentional. - The logo SVGs (`BrandMark.razor`, icons) still use `#7c3aed` while the default accent is now the re-lit `#7048e8` — presumably the brand mark keeps its own violet, but worth a glance that the header mark doesn't visibly clash with the new default accent next to it. - `design/trace/build.py` still maps Figtree/Bricolage families; consistent with the docs note that traced frames predate the restyle and the tracer fix is a separate task. The one thing I'd like an answer on (see the inline finding) is the browser-support band between `light-dark()` and relative color syntax — either a `@supports` fallback or a documented floor. --- ⏱ 5m 59s · 10 steps · $0.0295 · tokens: 82.0k in / 3.7k out (+323.5k cache-read) · Go: 5h 0% · wk 7% · mo 86% 📜 [Full session transcript](https://git.grandiras.net/Grandiras/opencode-bot/src/branch/opencode-logs/transcripts/Grandiras/Ponente/pr-238/run-2026-10-02T23-15-18-654Z.md) <!-- opencode-reviewed-head:e6a0de27480a230a6f0d092487cb069fbe6b97b5 --> <!-- opencode-verdict:approve -->
@ -123,0 +133,4 @@
icons and focus rings, which need more contrast than a fill. */
:root,
[style*="--board-color"] {
--brand: light-dark(oklch(from var(--board-color) 0.52 min(c, 0.17) h), oklch(from var(--board-color) 0.54 min(c, 0.17) h));
Collaborator

Compatibility question, non-blocking: light-dark() needs Chrome 123+/Safari 17.5+/Firefox 130+, but full relative-color support starts at Chrome 131 / Safari 18.0 / Firefox 133 (caniuse marks 119–130 Chrome, 16.4–17.6 Safari, 128–132 Firefox as partial — and the older partials are exactly the gaps around math functions on channels like min(c, 0.17)). On a browser in that band this declaration can fail at computed-value time, and since custom-property fallbacks don't help here (a broken value on --brand makes every var(--brand) consumer unset, e.g. a transparent primary button with white text), the only real guard is an @supports not (color: oklch(from red 0 0 h)) block with static token values. If the team has decided the floor is Chrome 131+/Safari 18+/FF 133+, this can be closed with a sentence in docs/frontend.md's Theming section; otherwise worth a fallback.

Compatibility question, non-blocking: `light-dark()` needs Chrome 123+/Safari 17.5+/Firefox 130+, but full relative-color support starts at Chrome 131 / Safari 18.0 / Firefox 133 (caniuse marks 119–130 Chrome, 16.4–17.6 Safari, 128–132 Firefox as *partial* — and the older partials are exactly the gaps around math functions on channels like `min(c, 0.17)`). On a browser in that band this declaration can fail at computed-value time, and since custom-property fallbacks don't help here (a broken value on `--brand` makes every `var(--brand)` consumer unset, e.g. a transparent primary button with white text), the only real guard is an `@supports not (color: oklch(from red 0 0 h))` block with static token values. If the team has decided the floor is Chrome 131+/Safari 18+/FF 133+, this can be closed with a sentence in docs/frontend.md's Theming section; otherwise worth a fallback.
Author
Owner

Thanks to both reviewers. Addressed in the latest push: an @supports not (color: oklch(from red 0.5 min(c, 0.17) h)) block now gives browsers in the light-dark()-but-no-relative-colours band static, already re-lit brand values (no board tint), and the floor is documented in docs/frontend.md (Theming); the empty .request-email-none rule and the unused --warning/--warning-bg/--toast-accent are gone. The brand mark keeps its own gradient on purpose: BrandMark is the logo's source of truth (docs/brand.md), separate from the UI accent. The tracer's Figtree/Bricolage mapping is being fixed in the retrace PR stacked on this one. Full e2e at e6a0de2 on an isolated stack: 156/156 passed.

Thanks to both reviewers. Addressed in the latest push: an `@supports not (color: oklch(from red 0.5 min(c, 0.17) h))` block now gives browsers in the light-dark()-but-no-relative-colours band static, already re-lit brand values (no board tint), and the floor is documented in docs/frontend.md (Theming); the empty `.request-email-none` rule and the unused `--warning`/`--warning-bg`/`--toast-accent` are gone. The brand mark keeps its own gradient on purpose: `BrandMark` is the logo's source of truth (docs/brand.md), separate from the UI accent. The tracer's Figtree/Bricolage mapping is being fixed in the retrace PR stacked on this one. Full e2e at e6a0de2 on an isolated stack: 156/156 passed.
Fall back to brand violet where relative colours are missing
All checks were successful
CI / build (pull_request) Successful in 42s
db9fa085bc
Both reviews asked about the band of browsers with light-dark() but without
relative colours: there the re-light block is invalid and every var(--brand)
unset, so a primary button loses its fill. An @supports not block gives them
the brand violet already re-lit, with no board tint, and the floor is in
docs/frontend.md.

Also drops what nothing used: the rule .request-email-none was left with,
--warning, --warning-bg and --toast-accent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator

🤖 Reviewing this PR — the review will link the full session transcript.

📜 Live transcript — updating every ~5 minutes while the review runs.

🤖 Reviewing this PR — the review will link the full session transcript. <!-- opencode-run:review --> 📜 [Live transcript](https://git.grandiras.net/Grandiras/opencode-bot/src/branch/opencode-logs/transcripts/Grandiras/Ponente/pr-238/run-2026-10-02T23-24-00-566Z.md) — updating every ~5 minutes while the review runs.
Collaborator

🤖 Reviewing this PR — follow along in the action run; the reply will link the full session transcript.

📜 Live transcript — updating every ~5 minutes while the task runs.

🤖 Reviewing this PR — follow along in [the action run](https://git.grandiras.net/Grandiras/claude-bot/actions/runs/668); the reply will link the full session transcript. <!-- claude-run:pr_review --> 📜 [Live transcript](https://git.grandiras.net/Grandiras/claude-bot/src/branch/claude-logs/transcripts/Grandiras/Ponente/pr-238/run-668.md) — updating every ~5 minutes while the task runs.
claude-reviewer left a comment

✅ Verdict: approve — no blocking issues found.

The only leftover from my last pass is resolved: the diff now deletes .request-email-none entirely instead of leaving an empty rule. I read the diff only. I did not run the app or the e2e suite.

The earlier notes still hold:

  • Header fix: moving the backdrop-filter onto .board-header::before is the right fix for the fixed-children containing-block regression.
  • Shadow checks: the e2e checks now skip inset shadows and split on commas outside parentheses, which is correct.
  • BoardTint: it is wired into the board, settings and calendar pages. The calendar tints only in single-board scope.
  • Browser floor: the @supports not fallback gives older browsers brand violet, so var(--brand) is never left unset there. Chrome before 131, Safari before 18 and Firefox before 133 get no board tint. The docs state this floor, so it reads as accepted.

Before merge, confirm the e2e re-run on the head is green. The PR description said it was still in progress.


🧠 claude-sonnet-5-5 · ⏱ 0m 6s · 2 turns · tokens: 44.2k in / 901 out (+12.2k cache-read)
📜 Full session transcript

✅ **Verdict: approve** — no blocking issues found. The only leftover from my last pass is resolved: the diff now deletes `.request-email-none` entirely instead of leaving an empty rule. I read the diff only. I did not run the app or the e2e suite. The earlier notes still hold: - **Header fix:** moving the `backdrop-filter` onto `.board-header::before` is the right fix for the fixed-children containing-block regression. - **Shadow checks:** the e2e checks now skip inset shadows and split on commas outside parentheses, which is correct. - **`BoardTint`:** it is wired into the board, settings and calendar pages. The calendar tints only in single-board scope. - **Browser floor:** the `@supports not` fallback gives older browsers brand violet, so `var(--brand)` is never left unset there. Chrome before 131, Safari before 18 and Firefox before 133 get no board tint. The docs state this floor, so it reads as accepted. Before merge, confirm the e2e re-run on the head is green. The PR description said it was still in progress. --- 🧠 claude-sonnet-5-5 · ⏱ 0m 6s · 2 turns · tokens: 44.2k in / 901 out (+12.2k cache-read) 📜 [Full session transcript](https://git.grandiras.net/Grandiras/claude-bot/src/branch/claude-logs/transcripts/Grandiras/Ponente/pr-238/run-668.md) <!-- claude-verdict:approve --> <!-- claude-reviewed-head:db9fa085bce8f1d6284f7725fe1baad2486938fe -->
opencode-reviewer left a comment

✅ Verdict: approve — no blocking issues found.

Re-review: both open items from the previous pass are resolved on the head.

  • Browser-support fallback landed. The new @supports not (color: oklch(from red 0.5 min(c, 0.17) h)) block gives browsers with light-dark() but without relative colors (Chrome 119–130, Safari 16.4–17.6, FF 128–132) static brand violet for --brand/--brand-bright/--brand-dim/--brand-ink and matching --bg-0/--bg-2/--material, so a broken computed value on --brand can no longer blank out the accent. The test condition is well chosen (it exercises relative color and channel math, and browsers that can't parse it evaluate not true), the fallback set matches offline.html, and docs/frontend.md's Theming section documents the floor. --brand-glow/--brand-surface use color-mix, which the whole affected band supports, and they correctly derive from the fallback --brand.
  • The leftover empty .request-email-none rule is deleted.

The rest stands as reviewed: AA contrast for white on --brand holds across the palette, the header containing-block fix is correct, the #292725 theme-color value is consistent across App.razor, --bg-1, the spec and prefs.spec.js, and the updated shadow e2e checks parse the new multi-layer/inset shadows correctly. The remaining minor notes from last time still hold as non-issues: unused --warning tokens are groundwork, the brand mark keeps its own violet, and the traced frames predate the restyle by design (documented).


⏱ 0m 54s · 4 steps · $0.0104 · tokens: 44.4k in / 871 out (+80.3k cache-read) · Go: 5h 0% · wk 7% · mo 86%
📜 Full session transcript

✅ **Verdict: approve** — no blocking issues found. Re-review: both open items from the previous pass are resolved on the head. - **Browser-support fallback landed.** The new `@supports not (color: oklch(from red 0.5 min(c, 0.17) h))` block gives browsers with `light-dark()` but without relative colors (Chrome 119–130, Safari 16.4–17.6, FF 128–132) static brand violet for `--brand`/`--brand-bright`/`--brand-dim`/`--brand-ink` and matching `--bg-0`/`--bg-2`/`--material`, so a broken computed value on `--brand` can no longer blank out the accent. The test condition is well chosen (it exercises relative color *and* channel math, and browsers that can't parse it evaluate `not` true), the fallback set matches `offline.html`, and `docs/frontend.md`'s Theming section documents the floor. `--brand-glow`/`--brand-surface` use `color-mix`, which the whole affected band supports, and they correctly derive from the fallback `--brand`. - **The leftover empty `.request-email-none` rule is deleted.** The rest stands as reviewed: AA contrast for white on `--brand` holds across the palette, the header containing-block fix is correct, the `#292725` theme-color value is consistent across `App.razor`, `--bg-1`, the spec and `prefs.spec.js`, and the updated shadow e2e checks parse the new multi-layer/inset shadows correctly. The remaining minor notes from last time still hold as non-issues: unused `--warning` tokens are groundwork, the brand mark keeps its own violet, and the traced frames predate the restyle by design (documented). --- ⏱ 0m 54s · 4 steps · $0.0104 · tokens: 44.4k in / 871 out (+80.3k cache-read) · Go: 5h 0% · wk 7% · mo 86% 📜 [Full session transcript](https://git.grandiras.net/Grandiras/opencode-bot/src/branch/opencode-logs/transcripts/Grandiras/Ponente/pr-238/run-2026-10-02T23-24-00-566Z.md) <!-- opencode-reviewed-head:db9fa085bce8f1d6284f7725fe1baad2486938fe --> <!-- opencode-verdict:approve -->
Grandiras deleted branch ui-v2-foundations 2026-10-02 23:26:12 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
5 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Grandiras/Ponente!238
No description provided.