Skip to content

Session-first phone layout · #3981

A selected terminal at ≤768px gets one 48px chrome row: drawer toggle, truncating session title, static Keyboard state and one … disclosure. The disclosure keeps project choices, Sessions · Tasks · Config, Light · Dark · System, Disconnect, install, pane actions, new-tab choices and the tab switcher reachable. Escape closes it and returns focus. Drawer, Tasks, Config and desktop layouts remain available. Opening the drawer preserves the session-first composition and the terminal rectangle. Split sessions show the focused pane, with Hide pane in the menu, and restore both panes on desktop. The six-button primary keybar is one 44px row; Arrows replaces it with More keys and four arrow keys, preserving 44px targets and terminal focus.

Measured height budget

Measurements use Chromium's visual viewport with the OS soft keyboard closed, while the terminal owns keyboard input and the keybar is visible. Both themes produce the same geometry. The terminal element is .af-pane-host .xterm.

Width Theme Visual viewport Top chrome Keybar Terminal Terminal share
360px Light 812px 48px 44px 718px 88.4%
360px Dark 812px 48px 44px 718px 88.4%
390px Light 812px 48px 44px 718px 88.4%
390px Dark 812px 48px 44px 718px 88.4%
430px Light 812px 48px 44px 718px 88.4%
430px Dark 812px 48px 44px 718px 88.4%

The regression assertion requires at least 85% at all three widths in both themes. The unchanged bundle failed at 360px with a 476px terminal (58.6%). The pane retains its 2px padding so its inset focus border clears column one. Browser emulation does not show an actual OS keyboard; the stream suite also simulates visual viewport resize and pan to verify terminal fit above it.

Before and after

Before stills are the committed recorder captures from starting master df215cfe (after #3980 merged). After stills use the real client and isolated daemon with the same scripted stand-in transcript, at 812px viewport height. These are browser captures, not mockups.

Width Theme Before After
360px Light Before 360 Light After 360 Light
360px Dark Before 360 Dark After 360 Dark
390px Light Before 390 Light After 390 Light
390px Dark Before 390 Dark After 390 Dark
430px Light Before 430 Light After 430 Light
430px Dark Before 430 Dark After 430 Dark

Verification

The new composition and one-row keybar tests were watched fail against the original sources: unit red evidence. The browser budget failed against the original tracked bundle: browser red evidence.

The browser recorder checks one-row chrome, title truncation and full accessible text, 44px targets, disclosure activation and Escape focus return, and the height budget in both themes. Screen bounds must remain inside the pane-host content box and clear the painted focus border; the host must have zero horizontal scroll. Opening and closing the drawer must preserve the host rectangle. The existing outgoing binary PTY Input assertions cover interrupt, one-shot Ctrl, composed input, locked Ctrl, focus retention and viewport changes; arrow selection additionally checks the outgoing arrow bytes.

Sources: composition, keybar, browser assertions.

The review regressions were watched fail on head 9edbad57 before the fixes: unit output and browser output. Corrected browser output records all six measurements. The requested host bounds and scrollLeft checks already passed on that head; the additional painted-border assertion exposed the clipping (0px < 2px). Restoring token-based padding puts the screen at 2px, clear of the border. The drawer formerly moved the host from y=48px to y=228px; it now leaves both its position and size unchanged.

Width (both themes) Screen left / painted edge Screen right / host right Host scrollLeft Closed = open host (x, y, width, height)
360px 2px / 2px 340px / 358px 0 (2, 50, 356, 760)
390px 2px / 2px 373px / 388px 0 (2, 50, 386, 760)
430px 2px / 2px 412px / 428px 0 (2, 50, 426, 760)

The browser helpers resolve the visible disclosure trigger and wait for phone or desktop composition after viewport changes. The #2219 phone test explicitly documents that desktop caret anchoring is outside its coverage.

All 740 web unit tests passed, with source and recorder typechecking and the tracked bundle rebuilt. The full containerized web-driver.spec.ts passed all 146 tests with zero retries, including tab reordering, drawer navigation and split-terminal restoration.

AF_UPDATE_GOLDENS=1 make perf-container regenerated both themes; comparison without the flag passed all five visual scenarios and every unchanged performance budget. Capture readiness is checked before and after screenshots so transient operator-state changes cannot become goldens. The pixel oracle and performance thresholds are unchanged. scripts/gen-docs.sh, design-token tests, generated-design checking, file-length lint and the Docs job's exact mkdocs build --strict passed. No Go source changed.