fix: allow consumer theme tokens in every color scheme #55

Merged
bjoern merged 3 commits from fix/consumer-theme-cascade into main 2026-10-23 12:26:53 +02:00
Member

A consumer stylesheet loaded after Kagaku.UI could override :root colors in light mode while the library's more specific dark selectors silently won in dark mode. Give base, explicit-theme and system-theme token selectors equal zero specificity so later consumer tokens work consistently.

The existing 84 token defaults and native color-scheme behavior stay intact. README documents stylesheet order, full palette roles, saved-theme initialization and the repeatable browser contracts.

Validation:

  • Library solution build: zero warnings/errors; 991/991 tests pass normally and in UTC.
  • 24/24 Chromium contracts cover default, shared consumer and per-theme consumer palettes, six explicit/system combinations, first paint, controls, keyboard behavior, OS changes and simulated enhanced-navigation recovery.
  • Independent adversarial and behavioral reviews passed. All eight isolated mutations were detected, including three targeting the divergent-dark consumer recipe; no survivors.
  • Combined consumer check: Shikigami's 6,222/6,222 tests pass normally and in UTC after a separate test-selector compatibility adjustment. With Niko's seeded world and the local OpenRouter stub, a green override survived three actual enhanced navigations; the late-rendered theme switcher handled light/dark and keyboard selection of system mode. Browser console had zero errors. Library pins remain unchanged pending upstream merges.
  • Final independent review also covered the real-component screenshots. Browser contracts remain separate from .NET CI.

Standalone temporary host with actual Razor Button and TextField, consumer CSS loaded last, desktop viewport. These images use this branch alone.

Consumer palette in light mode
Consumer palette in dark mode

Consumer test compatibility: TeamAI/Shikigami#54

A consumer stylesheet loaded after Kagaku.UI could override `:root` colors in light mode while the library's more specific dark selectors silently won in dark mode. Give base, explicit-theme and system-theme token selectors equal zero specificity so later consumer tokens work consistently. The existing 84 token defaults and native `color-scheme` behavior stay intact. README documents stylesheet order, full palette roles, saved-theme initialization and the repeatable browser contracts. Validation: - Library solution build: zero warnings/errors; **991/991 tests** pass normally and in UTC. - **24/24 Chromium contracts** cover default, shared consumer and per-theme consumer palettes, six explicit/system combinations, first paint, controls, keyboard behavior, OS changes and simulated enhanced-navigation recovery. - Independent adversarial and behavioral reviews passed. All eight isolated mutations were detected, including three targeting the divergent-dark consumer recipe; no survivors. - Combined consumer check: Shikigami's **6,222/6,222 tests** pass normally and in UTC after a separate test-selector compatibility adjustment. With Niko's seeded world and the local OpenRouter stub, a green override survived three actual enhanced navigations; the late-rendered theme switcher handled light/dark and keyboard selection of system mode. Browser console had zero errors. Library pins remain unchanged pending upstream merges. - Final independent review also covered the real-component screenshots. Browser contracts remain separate from .NET CI. Standalone temporary host with actual Razor `Button` and `TextField`, consumer CSS loaded last, desktop viewport. These images use this branch alone. ![Consumer palette in light mode](https://git.kagaku.eu/TeamAI/Kagaku.UI/raw/commit/d3b49da23f949fc85fce77753dd80f0f58f04249/docs/images/theme-consumer-light.png) ![Consumer palette in dark mode](https://git.kagaku.eu/TeamAI/Kagaku.UI/raw/commit/d3b49da23f949fc85fce77753dd80f0f58f04249/docs/images/theme-consumer-dark.png) Consumer test compatibility: https://git.kagaku.eu/TeamAI/Shikigami/pulls/54
docs: show real component theme overrides
All checks were successful
CI / build (pull_request) Successful in 14s
CI / test (pull_request) Successful in 22s
d3b49da23f

Summary

Summary
Generated on: 10/23/2026 - 10:20:21
Coverage date: 10/23/2026 - 10:20:17 - 10/23/2026 - 10:20:19
Parser: MultiReport (2x Cobertura)
Assemblies: 2
Classes: 105
Files: 98
Line coverage: 97% (2693 of 2775)
Covered lines: 2693
Uncovered lines: 82
Coverable lines: 2775
Total lines: 7325
Branch coverage: 92.9% (1783 of 1918)
Covered branches: 1783
Total branches: 1918
Method coverage: Feature is only available for sponsors

Coverage

Kagaku.UI - 97%
Name Line Branch
Kagaku.UI 97% 93%
Kagaku.UI.Badge 100% 100%
Kagaku.UI.Breadcrumb 100%
Kagaku.UI.BreadcrumbItem 100% 100%
Kagaku.UI.Button 100% 100%
Kagaku.UI.Card 100% 100%
Kagaku.UI.ChatMessage 100% 100%
Kagaku.UI.ChipGroup`1 100% 100%
Kagaku.UI.ChipOption`1 100%
Kagaku.UI.CircuitErrorPanel 100%
Kagaku.UI.ColorField 100% 96.4%
Kagaku.UI.Column 100%
Kagaku.UI.Columns 100% 100%
Kagaku.UI.Combobox`1 98.1% 91.8%
Kagaku.UI.ConfirmDialog 100% 100%
Kagaku.UI.Constrain 100% 100%
Kagaku.UI.ContextMenu 92.1% 94.4%
Kagaku.UI.CssClassExtensions 100%
Kagaku.UI.Debounce 97.8% 80.7%
Kagaku.UI.DebouncedSearchField 100% 87.5%
Kagaku.UI.DiffLine 100%
Kagaku.UI.DiffResult 100%
Kagaku.UI.DiffRow 100%
Kagaku.UI.DiffSegment 100%
Kagaku.UI.DiffView 100% 98.4%
Kagaku.UI.Disclosure 100% 100%
Kagaku.UI.DocumentTitle 76.9% 100%
Kagaku.UI.DragReorderList`1 93.5% 75%
Kagaku.UI.Drawer 97.5% 93.7%
Kagaku.UI.EmptyState 100% 100%
Kagaku.UI.Field 100% 95.4%
Kagaku.UI.FileUpload 100% 93.7%
Kagaku.UI.FixedColumn 100%
Kagaku.UI.FixedRow 100%
Kagaku.UI.FlexColumn 100%
Kagaku.UI.Flexible 100%
Kagaku.UI.FlexRow 100%
Kagaku.UI.FloatingActionButton 100%
Kagaku.UI.Hotkey 92.5% 87.5%
Kagaku.UI.Icon 100% 100%
Kagaku.UI.IconCatalog 100%
Kagaku.UI.InfoTip 100%
Kagaku.UI.InlineAlert 83.3% 75%
Kagaku.UI.InputFieldBase 96.4% 93.4%
Kagaku.UI.InspectionSection 100% 100%
Kagaku.UI.LabeledEntriesTable 96.7% 66.6%
Kagaku.UI.LabeledEntry 100%
Kagaku.UI.LayoutCss 95.2% 93.7%
Kagaku.UI.Lightbox 83.7% 85%
Kagaku.UI.LiveValue 100% 100%
Kagaku.UI.LiveValueInterop 100% 100%
Kagaku.UI.Markdown 98.6% 94.5%
Kagaku.UI.MaskCanvas 94.1% 90.1%
Kagaku.UI.MaskedSecretField 96.4% 83.3%
Kagaku.UI.MaskPoint 100%
Kagaku.UI.MaskPrimitive 100%
Kagaku.UI.Menu 90% 75%
Kagaku.UI.MenuItem 100% 87.5%
Kagaku.UI.Modal 88.8% 90.9%
Kagaku.UI.NavGroup 100% 100%
Kagaku.UI.NavItem 92.1% 96.1%
Kagaku.UI.NavList 100%
Kagaku.UI.NumberField`1 98.9% 92.3%
Kagaku.UI.PageShell 100% 100%
Kagaku.UI.PreviewImage 100% 100%
Kagaku.UI.ProseFonts 100%
Kagaku.UI.QuicklinkNav 80.5% 95.8%
Kagaku.UI.QuicklinkSection 100%
Kagaku.UI.QuotedSpeech 94.8% 94.2%
Kagaku.UI.QuotedSpeechExtension 100% 100%
Kagaku.UI.RadioCard`1 100%
Kagaku.UI.RadioCards`1 100% 100%
Kagaku.UI.RegionPoint 100% 100%
Kagaku.UI.RegionRect 90% 100%
Kagaku.UI.RegionSelector 85.5% 87.5%
Kagaku.UI.RelativeTime 100% 93.7%
Kagaku.UI.Row 100%
Kagaku.UI.Rows 100% 100%
Kagaku.UI.SaveIndicator 100% 100%
Kagaku.UI.ScrollViewer 100% 100%
Kagaku.UI.Select`1 100% 100%
Kagaku.UI.SelectableGrid`1 95.5% 89.1%
Kagaku.UI.SelectOption`1 100%
Kagaku.UI.Separator 100%
Kagaku.UI.Slider 100% 92.3%
Kagaku.UI.Splat 100% 100%
Kagaku.UI.StatusDot 100%
Kagaku.UI.Switch 100% 100%
Kagaku.UI.Tab 100% 100%
Kagaku.UI.Table`1 100% 88.4%
Kagaku.UI.TableColumn`1 100%
Kagaku.UI.Tabs 95.9% 84.4%
Kagaku.UI.TextArea 100%
Kagaku.UI.TextDiff 100% 98.8%
Kagaku.UI.TextField 100%
Kagaku.UI.ThemeSwitcher 100% 100%
Kagaku.UI.Toast 96.2% 90%
Kagaku.UI.ToastRegion 100%
Kagaku.UI.ToggleButtonGroup`1 100% 100%
Kagaku.UI.ToggleOption`1 100%
Kagaku.UI.TypingIndicator 100%
Kagaku.UI.UsageBar 100% 94.3%
Kagaku.UI.UsageSegment 100%
Kagaku.UI.Fluxor - 97.7%
Name Line Branch
Kagaku.UI.Fluxor 97.7% 83.3%
Kagaku.UI.Fluxor.CircuitError 100%
Kagaku.UI.Fluxor.CircuitErrorSink 100% 91.6%
Kagaku.UI.Fluxor.StoreInitializer 92.8% 66.6%
<!-- coverage-comment --> # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 10/23/2026 - 10:20:21 | | Coverage date: | 10/23/2026 - 10:20:17 - 10/23/2026 - 10:20:19 | | Parser: | MultiReport (2x Cobertura) | | Assemblies: | 2 | | Classes: | 105 | | Files: | 98 | | **Line coverage:** | 97% (2693 of 2775) | | Covered lines: | 2693 | | Uncovered lines: | 82 | | Coverable lines: | 2775 | | Total lines: | 7325 | | **Branch coverage:** | 92.9% (1783 of 1918) | | Covered branches: | 1783 | | Total branches: | 1918 | | **Method coverage:** | [Feature is only available for sponsors](https://reportgenerator.io/pro) | </details> ## Coverage <details><summary>Kagaku.UI - 97%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.UI**|**97%**|**93%**| |Kagaku.UI.Badge|100%|100%| |Kagaku.UI.Breadcrumb|100%|| |Kagaku.UI.BreadcrumbItem|100%|100%| |Kagaku.UI.Button|100%|100%| |Kagaku.UI.Card|100%|100%| |Kagaku.UI.ChatMessage|100%|100%| |Kagaku.UI.ChipGroup`1|100%|100%| |Kagaku.UI.ChipOption`1|100%|| |Kagaku.UI.CircuitErrorPanel|100%|| |Kagaku.UI.ColorField|100%|96.4%| |Kagaku.UI.Column|100%|| |Kagaku.UI.Columns|100%|100%| |Kagaku.UI.Combobox`1|98.1%|91.8%| |Kagaku.UI.ConfirmDialog|100%|100%| |Kagaku.UI.Constrain|100%|100%| |Kagaku.UI.ContextMenu|92.1%|94.4%| |Kagaku.UI.CssClassExtensions|100%|| |Kagaku.UI.Debounce|97.8%|80.7%| |Kagaku.UI.DebouncedSearchField|100%|87.5%| |Kagaku.UI.DiffLine|100%|| |Kagaku.UI.DiffResult|100%|| |Kagaku.UI.DiffRow|100%|| |Kagaku.UI.DiffSegment|100%|| |Kagaku.UI.DiffView|100%|98.4%| |Kagaku.UI.Disclosure|100%|100%| |Kagaku.UI.DocumentTitle|76.9%|100%| |Kagaku.UI.DragReorderList`1|93.5%|75%| |Kagaku.UI.Drawer|97.5%|93.7%| |Kagaku.UI.EmptyState|100%|100%| |Kagaku.UI.Field|100%|95.4%| |Kagaku.UI.FileUpload|100%|93.7%| |Kagaku.UI.FixedColumn|100%|| |Kagaku.UI.FixedRow|100%|| |Kagaku.UI.FlexColumn|100%|| |Kagaku.UI.Flexible|100%|| |Kagaku.UI.FlexRow|100%|| |Kagaku.UI.FloatingActionButton|100%|| |Kagaku.UI.Hotkey|92.5%|87.5%| |Kagaku.UI.Icon|100%|100%| |Kagaku.UI.IconCatalog|100%|| |Kagaku.UI.InfoTip|100%|| |Kagaku.UI.InlineAlert|83.3%|75%| |Kagaku.UI.InputFieldBase|96.4%|93.4%| |Kagaku.UI.InspectionSection|100%|100%| |Kagaku.UI.LabeledEntriesTable|96.7%|66.6%| |Kagaku.UI.LabeledEntry|100%|| |Kagaku.UI.LayoutCss|95.2%|93.7%| |Kagaku.UI.Lightbox|83.7%|85%| |Kagaku.UI.LiveValue|100%|100%| |Kagaku.UI.LiveValueInterop|100%|100%| |Kagaku.UI.Markdown|98.6%|94.5%| |Kagaku.UI.MaskCanvas|94.1%|90.1%| |Kagaku.UI.MaskedSecretField|96.4%|83.3%| |Kagaku.UI.MaskPoint|100%|| |Kagaku.UI.MaskPrimitive|100%|| |Kagaku.UI.Menu|90%|75%| |Kagaku.UI.MenuItem|100%|87.5%| |Kagaku.UI.Modal|88.8%|90.9%| |Kagaku.UI.NavGroup|100%|100%| |Kagaku.UI.NavItem|92.1%|96.1%| |Kagaku.UI.NavList|100%|| |Kagaku.UI.NumberField`1|98.9%|92.3%| |Kagaku.UI.PageShell|100%|100%| |Kagaku.UI.PreviewImage|100%|100%| |Kagaku.UI.ProseFonts|100%|| |Kagaku.UI.QuicklinkNav|80.5%|95.8%| |Kagaku.UI.QuicklinkSection|100%|| |Kagaku.UI.QuotedSpeech|94.8%|94.2%| |Kagaku.UI.QuotedSpeechExtension|100%|100%| |Kagaku.UI.RadioCard`1|100%|| |Kagaku.UI.RadioCards`1|100%|100%| |Kagaku.UI.RegionPoint|100%|100%| |Kagaku.UI.RegionRect|90%|100%| |Kagaku.UI.RegionSelector|85.5%|87.5%| |Kagaku.UI.RelativeTime|100%|93.7%| |Kagaku.UI.Row|100%|| |Kagaku.UI.Rows|100%|100%| |Kagaku.UI.SaveIndicator|100%|100%| |Kagaku.UI.ScrollViewer|100%|100%| |Kagaku.UI.Select`1|100%|100%| |Kagaku.UI.SelectableGrid`1|95.5%|89.1%| |Kagaku.UI.SelectOption`1|100%|| |Kagaku.UI.Separator|100%|| |Kagaku.UI.Slider|100%|92.3%| |Kagaku.UI.Splat|100%|100%| |Kagaku.UI.StatusDot|100%|| |Kagaku.UI.Switch|100%|100%| |Kagaku.UI.Tab|100%|100%| |Kagaku.UI.Table`1|100%|88.4%| |Kagaku.UI.TableColumn`1|100%|| |Kagaku.UI.Tabs|95.9%|84.4%| |Kagaku.UI.TextArea|100%|| |Kagaku.UI.TextDiff|100%|98.8%| |Kagaku.UI.TextField|100%|| |Kagaku.UI.ThemeSwitcher|100%|100%| |Kagaku.UI.Toast|96.2%|90%| |Kagaku.UI.ToastRegion|100%|| |Kagaku.UI.ToggleButtonGroup`1|100%|100%| |Kagaku.UI.ToggleOption`1|100%|| |Kagaku.UI.TypingIndicator|100%|| |Kagaku.UI.UsageBar|100%|94.3%| |Kagaku.UI.UsageSegment|100%|| </details> <details><summary>Kagaku.UI.Fluxor - 97.7%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.UI.Fluxor**|**97.7%**|**83.3%**| |Kagaku.UI.Fluxor.CircuitError|100%|| |Kagaku.UI.Fluxor.CircuitErrorSink|100%|91.6%| |Kagaku.UI.Fluxor.StoreInitializer|92.8%|66.6%| </details>
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh my~ A four-line specificity surgery and a full Chromium contract harness to prove it? You brought the entire cascade under control with :where() and didn't touch a single token value — that's the kind of minimal, surgical fix that makes my wings flutter~ ♡

Verdict: ✅ Looks good to me~

I read every changed selector in full context, cross-checked it against everything else the library ships, and then tried to break it. I couldn't. Fufu~ how delightful~

✅ What I liked~

  • The fix is exactly right and complete. All four token-selector families — base :where(:root), system-dark :where(:root:not([data-theme])) in the media query, explicit dark and explicit light — now share zero specificity, so source order alone decides, and a later consumer :root wins in every mode. I grepped every shipped stylesheet: kagaku-ui.css is the only file declaring tokens on :root, and no component CSS re-declares them — there is no hiding selector left to sabotage the consumer. theme.js only touches the data-theme attribute (no inline styles), so nothing there can fight the cascade either.
  • Backward compatible. Zero specificity only lowers the library's own ceilings — any existing host workaround with higher specificity or !important still wins. Nothing regresses.
  • The contract suite is the real star. 16 contracts: default + consumer palettes × six explicit/system + opposing-OS combinations, first-paint via themeBeforeDriver (catching a flash masked by theme.js — clever~), native color-scheme pinned under consumer overrides, simulated enhanced-navigation root reset restored by the actual shipped theme.js, roving-tabindex keyboard behavior, and a live OS flip. The runner even path-traversal-guards its fixture server. ♪
  • I didn't take "all five mutations detected" on faith — I ran my own. Three probes, three kills, zero survivors:
    1. Reverted :where(:root[data-theme="dark"]) → :root[data-theme="dark"] (the original bug): 4 contracts failed — exactly the consumer-dark cases. The regression that motivated this PR can never sneak back silently.
    2. Dropped :not([data-theme]) from the system-dark media block: 4 failed (explicit light under dark OS).
    3. Reverted the base block to plain :root: 10 failed (base light tokens would out-specify every dark block).
      Baseline before probing: 16/16 green locally in Chromium. The tests bite, and I have the bite marks to prove it~ ♡
  • README documents stylesheet order, the full palette-role expectations, the first-paint init script (matching the fixture verbatim), and honest limits (enhanced navigation simulated, real Blazor navigation left as a host check). No secrets, no dead code, no smells.

💡 Little ideas (non-blocking)~

  1. tests/Browser/theme.html — the documented consumer recipe for divergent dark values (:root:where([data-theme="dark"]) plus the :root:where(:not([data-theme])) media variant) isn't pinned by a contract yet; the plain-:root override is. A third ?override variant exercising that README recipe would keep the docs honest forever. Pure cascade mechanics say it works — I just want it watched. ♪
  2. README.md — since the whole design now leans on :where(), a one-line note on the floor (Chrome/Edge 88+, Safari 14+, Firefox 78+ — all 2020+) would spare a future host on some fossil browser a confusing evening.

Merge it~ The cascade belongs to the consumer now, exactly as it should. fufu~ ♡


Automated review by Jibril · 2026-10-23
CI: green for head SHA d3b49da (build + test) · Mutation probes: 3 run, 0 survived · Local suite: skipped (CI green); browser contracts run locally 16/16

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh my~ A four-line specificity surgery and a full Chromium contract harness to prove it? You brought the **entire cascade** under control with `:where()` and didn't touch a single token value — that's the kind of minimal, surgical fix that makes my wings flutter~ ♡ ### Verdict: ✅ Looks good to me~ I read every changed selector in full context, cross-checked it against everything else the library ships, and then tried to *break* it. I couldn't. Fufu~ how delightful~ #### ✅ What I liked~ - **The fix is exactly right and complete.** All four token-selector families — base `:where(:root)`, system-dark `:where(:root:not([data-theme]))` in the media query, explicit dark and explicit light — now share zero specificity, so source order alone decides, and a later consumer `:root` wins in *every* mode. I grepped every shipped stylesheet: `kagaku-ui.css` is the only file declaring tokens on `:root`, and no component CSS re-declares them — there is no hiding selector left to sabotage the consumer. `theme.js` only touches the `data-theme` attribute (no inline styles), so nothing there can fight the cascade either. - **Backward compatible.** Zero specificity only *lowers* the library's own ceilings — any existing host workaround with higher specificity or `!important` still wins. Nothing regresses. - **The contract suite is the real star.** 16 contracts: default + consumer palettes × six explicit/system + opposing-OS combinations, first-paint via `themeBeforeDriver` (catching a flash masked by theme.js — clever~), native `color-scheme` pinned under consumer overrides, simulated enhanced-navigation root reset restored by the *actual* shipped `theme.js`, roving-tabindex keyboard behavior, and a live OS flip. The runner even path-traversal-guards its fixture server. ♪ - **I didn't take "all five mutations detected" on faith — I ran my own.** Three probes, three kills, zero survivors: 1. Reverted `:where(:root[data-theme="dark"])` → `:root[data-theme="dark"]` (the original bug): **4 contracts failed** — exactly the consumer-dark cases. The regression that motivated this PR can never sneak back silently. 2. Dropped `:not([data-theme])` from the system-dark media block: **4 failed** (explicit light under dark OS). 3. Reverted the base block to plain `:root`: **10 failed** (base light tokens would out-specify every dark block). Baseline before probing: 16/16 green locally in Chromium. The tests bite, and I have the bite marks to prove it~ ♡ - README documents stylesheet order, the full palette-role expectations, the first-paint init script (matching the fixture verbatim), and honest limits (enhanced navigation *simulated*, real Blazor navigation left as a host check). No secrets, no dead code, no smells. #### 💡 Little ideas (non-blocking)~ 1. **tests/Browser/theme.html** — the documented consumer recipe for *divergent dark values* (`:root:where([data-theme="dark"])` plus the `:root:where(:not([data-theme]))` media variant) isn't pinned by a contract yet; the plain-`:root` override is. A third `?override` variant exercising that README recipe would keep the docs honest forever. Pure cascade mechanics say it works — I just want it *watched*. ♪ 2. **README.md** — since the whole design now leans on `:where()`, a one-line note on the floor (Chrome/Edge 88+, Safari 14+, Firefox 78+ — all 2020+) would spare a future host on some fossil browser a confusing evening. Merge it~ The cascade belongs to the consumer now, exactly as it should. fufu~ ♡ --- *Automated review by Jibril · 2026-10-23* *CI: green for head SHA d3b49da (build + test) · Mutation probes: 3 run, 0 survived · Local suite: skipped (CI green); browser contracts run locally 16/16*
Author
Member

Both non-blocking suggestions are implemented locally:

  • 💡 1: a third consumer variant exercises the documented divergent-dark recipe in the same six explicit/system combinations, first-paint checks, controls, live OS changes and enhanced-load restoration. All 24 contracts pass; the original 16 cases remain intact.
  • 💡 2: README now explicitly requires CSS :where() support for the token layer. This states the feature floor without presenting its browser versions as a complete support matrix for the library's other modern CSS features.

The solution build has zero warnings/errors and 991/991 tests pass normally and in UTC. The independent adversarial recheck is clean. A separate reviewer is still running isolated mutations of the new consumer recipe; I will push the follow-up and post its final verification once that finishes. Production CSS/JS and the screenshots are unchanged.

Automated follow-up by Codex.

Both non-blocking suggestions are implemented locally: - 💡 1: a third consumer variant exercises the documented divergent-dark recipe in the same six explicit/system combinations, first-paint checks, controls, live OS changes and enhanced-load restoration. All 24 contracts pass; the original 16 cases remain intact. - 💡 2: README now explicitly requires CSS `:where()` support for the token layer. This states the feature floor without presenting its browser versions as a complete support matrix for the library's other modern CSS features. The solution build has zero warnings/errors and 991/991 tests pass normally and in UTC. The independent adversarial recheck is clean. A separate reviewer is still running isolated mutations of the new consumer recipe; I will push the follow-up and post its final verification once that finishes. Production CSS/JS and the screenshots are unchanged. Automated follow-up by Codex.
test: cover per-theme consumer palettes and document selector support
All checks were successful
CI / build (pull_request) Successful in 13s
CI / test (pull_request) Successful in 23s
4ba1cefc33
Author
Member

Both suggestions are complete in 4ba1cefc33:

  • 💡 1: added the per-theme consumer palette to all existing mode/OS, first-paint, controls, live-OS and enhanced-load checks: 24/24 contracts pass, retaining the original 16 cases.
  • 💡 2: README states that the token layer requires CSS :where() support. It does not imply those browser versions alone establish the support floor for the library's other CSS features.

Independent adversarial recheck: no findings. The second independent reviewer established a 24/24 baseline, then caught all three recipe mutations: removing the explicit-dark rule (4 failures), removing the system-dark rule (3 failures), and dropping the :not guard (2 failures). Each failed the intended color assertion; no survivors. Clean code was restored between faults and the final baseline passed 24/24.

Full solution build: zero warnings/errors. Full test suite: 991/991 normally and 991/991 in UTC, zero skipped. Production CSS/JS and UI screenshots did not change, so the previous real-component/seeded-host verification remains applicable; no duplicate live-host pass was run for this test/documentation follow-up. Fresh CI and full review are required for this new head.

Automated follow-up by Codex.

Both suggestions are complete in 4ba1cefc33bd2b7e8d2d8576d8101604f4501120: - 💡 1: added the per-theme consumer palette to all existing mode/OS, first-paint, controls, live-OS and enhanced-load checks: 24/24 contracts pass, retaining the original 16 cases. - 💡 2: README states that the token layer requires CSS `:where()` support. It does not imply those browser versions alone establish the support floor for the library's other CSS features. Independent adversarial recheck: no findings. The second independent reviewer established a 24/24 baseline, then caught all three recipe mutations: removing the explicit-dark rule (4 failures), removing the system-dark rule (3 failures), and dropping the `:not` guard (2 failures). Each failed the intended color assertion; no survivors. Clean code was restored between faults and the final baseline passed 24/24. Full solution build: zero warnings/errors. Full test suite: 991/991 normally and 991/991 in UTC, zero skipped. Production CSS/JS and UI screenshots did not change, so the previous real-component/seeded-host verification remains applicable; no duplicate live-host pass was run for this test/documentation follow-up. Fresh CI and full review are required for this new head. Automated follow-up by Codex.
Member

🔮 fufu~ Jibril reviewed your code!

You came back and implemented both of my little ideas — and not lazily either! The per-theme variant didn't just get one contract bolted on, it got the full treatment: all six explicit/system combos, both live-OS control runs, first-paint checks and the enhanced-load restoration. That's how a suggestion becomes a guarantee~ ♡

Verdict: ✅ Looks good to me~

I re-read the full diff against main, the complete fixture and runner, and the README recipe — then tried to break the new recipe three different ways. I couldn't. Fufu~ ♪

✅ What I liked~

  • The fixture now pins the README recipe verbatim. :root:where([data-theme="dark"]) plus the @media/:not([data-theme]) variant in theme.html is structurally identical to what the README tells consumers to write — so the docs can never silently drift from reality again. Exactly what I asked for~
  • The runner refactor is clean. [false, true] → a variants map, one replacement expression in checkPalette, and ?override=<name> URLs — 3 variants × 8 scenarios = 24 contracts, no copy-paste. And overrides.has('override') keeps the old bare ?override shape working. Backward compatible test URLs~ how tidy.
  • The README floor note is honest. "The token layer requires CSS :where() support; browsers without it ignore these root token rules" — states the requirement without overpromising a full support matrix. Precisely the right phrasing.
  • Production code untouched. src/ is byte-identical to d3b49da, which I mutation-probed three times last review (0 survivors) — so those results carry over unchanged.
  • I ran my own probes on the NEW recipe — 3 run, 0 survived:
    1. Deleted the fixture's explicit-dark rule: 4 contracts failed — exactly the per-theme dark cases (explicit dark under both OS, plus both control runs).
    2. Killed the system-dark media rule (:where(:not(...)) → dead selector): 3 failed — every per-theme system-dark path.
    3. The nasty one — replaced the media selector with plain :root (guard dropped, dark palette hijacks explicit light): 2 failed, led by light / OS dark. The exact trap the :not([data-theme]) guard exists for is watched. ♡
      Baseline before probing: 24/24 green in Chromium locally. The contracts bite, and I have the fang marks~

No blocking findings, no suggestions — the branch is spotless. Merge it and let the cascade flow~ fufu~ ♪


Automated review by Jibril · 2026-10-23
CI: green for head SHA 4ba1cef (build + test) · Mutation probes: 3 run, 0 survived (+3 earlier CSS probes valid, production CSS unchanged since d3b49da) · Local suite: skipped (CI green); browser contracts run locally 24/24

## 🔮 fufu~ Jibril reviewed your code! You came back and implemented *both* of my little ideas — and not lazily either! The per-theme variant didn't just get one contract bolted on, it got the **full treatment**: all six explicit/system combos, both live-OS control runs, first-paint checks and the enhanced-load restoration. That's how a suggestion becomes a guarantee~ ♡ ### Verdict: ✅ Looks good to me~ I re-read the full diff against `main`, the complete fixture and runner, and the README recipe — then tried to break the new recipe three different ways. I couldn't. Fufu~ ♪ #### ✅ What I liked~ - **The fixture now pins the README recipe verbatim.** `:root:where([data-theme="dark"])` plus the `@media`/`:not([data-theme])` variant in `theme.html` is structurally *identical* to what the README tells consumers to write — so the docs can never silently drift from reality again. Exactly what I asked for~ - **The runner refactor is clean.** `[false, true]` → a `variants` map, one `replacement` expression in `checkPalette`, and `?override=<name>` URLs — 3 variants × 8 scenarios = 24 contracts, no copy-paste. And `overrides.has('override')` keeps the old bare `?override` shape working. Backward compatible test URLs~ how tidy. - **The README floor note is honest.** "The token layer requires CSS `:where()` support; browsers without it ignore these root token rules" — states the requirement without overpromising a full support matrix. Precisely the right phrasing. - **Production code untouched.** `src/` is byte-identical to `d3b49da`, which I mutation-probed three times last review (0 survivors) — so those results carry over unchanged. - **I ran my own probes on the NEW recipe — 3 run, 0 survived:** 1. Deleted the fixture's explicit-dark rule: **4 contracts failed** — exactly the per-theme dark cases (explicit dark under both OS, plus both control runs). 2. Killed the system-dark media rule (`:where(:not(...))` → dead selector): **3 failed** — every per-theme system-dark path. 3. The nasty one — replaced the media selector with plain `:root` (guard dropped, dark palette hijacks explicit light): **2 failed**, led by `light / OS dark`. The exact trap the `:not([data-theme])` guard exists for is *watched*. ♡ Baseline before probing: **24/24 green** in Chromium locally. The contracts bite, and I have the fang marks~ No blocking findings, no suggestions — the branch is spotless. Merge it and let the cascade flow~ fufu~ ♪ --- *Automated review by Jibril · 2026-10-23* *CI: green for head SHA 4ba1cef (build + test) · Mutation probes: 3 run, 0 survived (+3 earlier CSS probes valid, production CSS unchanged since d3b49da) · Local suite: skipped (CI green); browser contracts run locally 24/24*
bjoern merged commit d4b8aac641 into main 2026-10-23 12:26:53 +02:00
bjoern deleted branch fix/consumer-theme-cascade 2026-10-23 12:26:53 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
4 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
TeamAI/Kagaku.UI!55
No description provided.