Summary
packages/ui/src/theme/themes/oc-2.json line 28 declares the light variant's icon-weak-base without a leading #:
"icon-base": "#8F8F8F",
"icon-weak-base": "C7C7C7",
The dark variant (line 264) is correct: "icon-weak-base": "#343434".
oc-2 is the only theme of the 37 in that directory that declares this token literally — every other theme takes the derived neutral[6] from resolve.ts — and it is the only malformed value among them. Since oc-2 is the default, this is the default light-mode experience.
Why it fails silently
resolveThemeVariant passes the string through verbatim, and the resolved tokens are injected into a <style> element (theme/context.tsx), which overrides the static --icon-weak-base: #dbdbdb in styles/theme.css. So the malformed value wins the cascade.
Custom properties accept almost any token sequence, so nothing errors at parse time. The failure lands at substitution: var(--icon-weak-base) resolves to C7C7C7, which is invalid at computed-value time, so the property falls back to the inherited value if it is an inherited property and the initial value otherwise. That means the same token fails differently depending on where it is used.
Measured in a running app on the default light theme:
--icon-weak-base → "C7C7C7"
color: var(--icon-weak-base) → rgb(1, 2, 3) // the parent's color, not grey
background: var(--icon-weak-base) → rgba(0, 0, 0, 0) // transparent
--icon-base (control) → rgb(143, 143, 143) // fine
What it affects
Light mode only; dark is unaffected.
| Site |
Property |
Result |
app/src/components/dialog-release-notes.tsx |
bg-icon-weak-base |
inactive carousel indicators render transparent |
ui/src/components/diff-changes.tsx |
fill on <rect> inside <svg fill="none"> |
neutral diff blocks inherit fill: none and don't render |
app/src/components/file-tree.tsx |
color |
icon inherits the parent text color, so it renders at full strength instead of weak |
app/src/components/settings-keybinds.tsx |
color |
same |
app/src/components/settings-models.tsx |
color |
same |
Fix
Add the #. The intended value looks unambiguous — #C7C7C7 matches text-weaker declared a few lines above in the same block.
- "icon-weak-base": "C7C7C7",
+ "icon-weak-base": "#C7C7C7",
Possibly worth a guard too, so this can't recur silently: the theme schema could require ^# on literal color values, or resolveThemeVariant could warn on a value that is neither a #-prefixed hex nor a var(...) reference.
Happy to open a PR if useful.
Summary
packages/ui/src/theme/themes/oc-2.jsonline 28 declares the light variant'sicon-weak-basewithout a leading#:The dark variant (line 264) is correct:
"icon-weak-base": "#343434".oc-2is the only theme of the 37 in that directory that declares this token literally — every other theme takes the derivedneutral[6]fromresolve.ts— and it is the only malformed value among them. Sinceoc-2is the default, this is the default light-mode experience.Why it fails silently
resolveThemeVariantpasses the string through verbatim, and the resolved tokens are injected into a<style>element (theme/context.tsx), which overrides the static--icon-weak-base: #dbdbdbinstyles/theme.css. So the malformed value wins the cascade.Custom properties accept almost any token sequence, so nothing errors at parse time. The failure lands at substitution:
var(--icon-weak-base)resolves toC7C7C7, which is invalid at computed-value time, so the property falls back to the inherited value if it is an inherited property and the initial value otherwise. That means the same token fails differently depending on where it is used.Measured in a running app on the default light theme:
What it affects
Light mode only; dark is unaffected.
app/src/components/dialog-release-notes.tsxbg-icon-weak-baseui/src/components/diff-changes.tsxfillon<rect>inside<svg fill="none">fill: noneand don't renderapp/src/components/file-tree.tsxcolorapp/src/components/settings-keybinds.tsxcolorapp/src/components/settings-models.tsxcolorFix
Add the
#. The intended value looks unambiguous —#C7C7C7matchestext-weakerdeclared a few lines above in the same block.Possibly worth a guard too, so this can't recur silently: the theme schema could require
^#on literal color values, orresolveThemeVariantcould warn on a value that is neither a#-prefixed hex nor avar(...)reference.Happy to open a PR if useful.