v1.0.263
✨ New: a theme layer that works in both modes
Light mode had been styled in dark mode. Enough of it was written and reviewed against a near-black page that the light theme was carrying a long tail of invisible borders, dead fills and text below AA — this release rebuilds the token layer underneath it rather than patching the symptoms.
Surfaces and fills are now two separate scales. Surfaces are solid and are the only things with elevation: the app ground, a panel, a floating overlay. Fills are alpha and carry none: a chip, a toolbar strip, a selected row, composited onto whichever surface they land on. Previously six roles — background, card, popover, muted, secondary, accent — all drew from four slate steps, and they collided: in dark, a toolbar was exactly the colour of the card beneath it, and a dropdown was byte-identical to the panel it opened over.
Light mode gets depth the only way a white base can carry it — borders and shadows. That meant tokens the system didn't have: a 4-step alpha line ramp, a 3-step elevation scale much lighter than Tailwind's stock shadows (built on 0.1 alpha black, they read as a dirty halo on white), interactive tints that compose inside cards instead of overwriting them, and a per-theme scrim, since a backdrop needs far less black over a white page than over a dark one.
Values are solved so each fill composites onto the exact step it used to be — pixel-for-pixel in most cases. Existing screens keep their weight and gain the compositing fix.
🐛 Fix: the surfaces that never asked the theme
Several surfaces painted themselves from a single hardcoded dark-tuned value that no theme switch ever reached.
The terminal was the worst of them: its xterm palette was one dark set, and background: 'transparent' resolved to solid #000 — invisible against a dark bubble, a black brick over a light one. It now carries a palette per theme. The Neo4j graph canvas assumed a dark ground outright, with edge labels at ~2.8:1 on white and node rings that vanished. Chart grids, the console drag ghost and the hour heatmap's empty bars were all handing a bare HSL triple to canvas or to a style prop, which is a silent no-op rather than an error.
The ANSI palette's four "light overrides" had never applied at all — the selector matched in both themes — and the other 28 colours had no light handling. Light is now the base. The JSON preview no longer renders github-dark keys at ~1.8:1 on a white pane, and tooltips are no longer a white box on a white page held together by a border.
🐛 Fix: chat messages stop stacking surfaces
An assistant turn carries markdown, code blocks and a tool-call list, and each wanted a surface of its own. Nested, and now compositing, they compounded — a code block inside an expanded tool row bottomed out at 2.06:1 against the page it was meant to sit quietly on. The nesting is gone: tool-call rows are divider-separated list items rather than a stack of rounded boxes, and only code blocks keep a fill. Both sides of the conversation now wear one skin; the user bubble is marked by alignment and its flipped corner, not by a brand-coloured border that read as "selected".
Twenty-four cards, toolbars and sub-headers also drop a fill that was doing nothing — the border beside it had been doing all the separating.
🐛 Fix: session badges and Windows tool-call attribution
Recent-session rows said the same thing three times: a status dot, the word 运行中/完成, and an untinted number badge. The word is gone and the badge carries running/unread state, since that is where the eye lands when scanning the right edge.
On Windows, snapshot toolFiles paths were stored with backslashes and compared against git's /-separated diff paths. The sets never intersected, so every file in an Edit/Write snapshot was marked an external change and tool-call attribution broke entirely.