fix(desktop): fixed title-bar buttons are opaque over sliding panes

Merged
DA
10d ago
+38-4

Dean could see the right panel's tabs through the panel toggle while the panel opened or closed. Since #1892 the toggle stays fixed at the window's top right and the panel slides underneath it. The toggle's hover fill (--selected, 20% white) is translucent, and at rest it has no fill at all, so the tab row showed through in both states.

What changed

Title-bar clusters (desktop.css). Each .title-bar-controls cluster now sets --title-bar-ground to the colour of the bar it sits on:

  • Left cluster: the sidebar colour while the sidebar is open. The window ground while it is folded. The panel's well while it is folded and the panel is full screen.
  • Right cluster: the window ground while the panel is shut. The well for as long as a .side-panel is drawn, including during its close animation.

Hover fill is opaque. A hovered title-bar button (sidebar toggle, title-bar New plan, panel toggle) draws linear-gradient(var(--selected), var(--selected)) var(--title-bar-ground). That is the same translucent token, layered over an opaque copy of the ground under it, so no rgba value is written out again and it looks the same at rest. Disabled buttons are excluded.

Rest state ("no fill"): a backing on the right, nothing on the left. I chose these two approaches over clipping the sliding content, which is harder: the panel moves by transform, so cutting a hole around the toggle would mean moving the clip against the slide every frame.

  • Right cluster: the panel's tab row really does pass under the toggle, so the cluster sits on an opaque, rounded backing in --title-bar-ground. The backing belongs to the cluster rather than the button, so the disabled toggle's opacity: 0.45 dims only the glyph and never makes the backing see-through.
  • Left cluster: the only thing that passes under it is the sidebar's own empty edge. I tried a backing there too. Mid-fold, the edge splits the cluster in two, and one solid colour can only match one side, so a faint square showed behind "+" (2–3 levels off). I dropped it: only the hover fill is opaque on the left.

Audit of other controls that overlap moving or scrolled content:

  • Transcript scroll-to-newest button: its hover was bg-secondary (9% white) in place of its opaque bg-background, so the button turned about 91% see-through over the scrolling lines. Its hover now layers the fill over its ground (hover:bg-[linear-gradient(…)]).
  • Floating voice caption over the document: it was rgba(22,22,27,0.97) and is now solid #16161b, the same colour over the ground.
  • Already opaque, unchanged: plan / action menus (--desktop-sidebar), the confirm dialog, tooltips (#0b0b0c), the compose folder menu, the sticky transcript call headers and settings header, and Excalidraw's islands (#232329).
  • Not affected: the panel's expand button sits inside the panel's bar and moves with it, so nothing passes beneath it.

The app is dark-only (color-scheme: dark), so there is no light variant. Reduced motion is unaffected: the rules only change colours, not motion.

Evidence

Headless Chrome on Linux, using the built styles.css from main and from this branch, on a page that copies the shell's markup (sidebar, toolbar, side panel with tabs, both title-bar clusters). Each frame is frozen partway through the real pane motion (Web Animations / CSS transitions paused at the given time), with real CDP hover.

before/after

  • Mid-open and mid-close: "Tran…" shows through the hovered toggle on main and does not on this branch. With the toggle not hovered, the tab text runs under the bare glyph on main and is hidden by the backing here.
  • Pixel diff of the at-rest frames, before vs after: at most 1 level, from anti-aliasing at the rounded corners. Nothing changes when nothing is moving.

Verification

  • ./scripts/check.sh exits 0.
  • CI could not verify the Mac UI, because CI builds nothing for the Mac. ./scripts/verify.sh was not run, since this is a Linux VM; LUKE-159 is the manual Mac pass.
  • No test was added: the change is CSS-only, and a test asserting these rules would be a change detector. The frames above are the evidence.

🤖 Generated with Claude Code


Open workspace in Conductor


Devin Review