diff --git a/apps/desktop/src/components/ui/pane-tab.test.tsx b/apps/desktop/src/components/ui/pane-tab.test.tsx
index bdd275497a..44b52294bf 100644
--- a/apps/desktop/src/components/ui/pane-tab.test.tsx
+++ b/apps/desktop/src/components/ui/pane-tab.test.tsx
@@ -124,6 +124,26 @@ describe('PaneTab hover close button', () => {
expect(screen.queryByRole('button', { name: 'Close' })).toBeNull()
})
+ it('reserves a close-button runway only on closeable horizontal tabs', () => {
+ const onClose = vi.fn()
+ const { rerender } = render(
+
+ BROWSER
+
+ )
+
+ const horizontalTab = screen.getByText('BROWSER').parentElement?.parentElement
+ expect(horizontalTab?.className).toContain('pr-9')
+
+ rerender(
+
+ BROWSER
+
+ )
+ const verticalTab = screen.getByText('BROWSER').parentElement?.parentElement
+ expect(verticalTab?.className).not.toContain('pr-9')
+ })
+
it('a closeable horizontal tab always shows its ✕ — the chip and the pointer gestures are one affordance', () => {
const onClose = vi.fn()
render(
diff --git a/apps/desktop/src/components/ui/pane-tab.tsx b/apps/desktop/src/components/ui/pane-tab.tsx
index dbf9fab10e..8b0703a9e2 100644
--- a/apps/desktop/src/components/ui/pane-tab.tsx
+++ b/apps/desktop/src/components/ui/pane-tab.tsx
@@ -102,6 +102,7 @@ export const PaneTab = React.forwardRef(function P
className={cn(
TAB,
vertical ? TAB_VERTICAL : TAB_HORIZONTAL,
+ !vertical && onClose && 'pr-9',
edge,
active
? cn(TAB_ACTIVE, !vertical && TAB_ACTIVE_UNDERLINE)
@@ -163,10 +164,9 @@ export const PaneTab = React.forwardRef(function P
)}
{onClose && !vertical && (
- // Hover ✕, painted OVER the label's right edge as an overlay (no
- // layout shift, tab width never jumps on hover). The runway is a tiny
- // transparent→`--tab-face` gradient, so the button melts into the
- // tab's effective surface instead of hard-clipping the text under it.
+ // Hover ✕ stays absolutely positioned so hover never shifts the tab.
+ // The tab reserves a fixed right runway for this overlay, keeping the
+ // label clear of the gradient/button even for short labels like BROWSER.
// Rendered after the dirty dot: on hover the ✕ takes the dot's spot,
// VS Code-style.