fix: let the session list scroll instead of cutting off the footer
Summary
- Make the panel body between the header and footer the one scroll container in the app, so a long session list scrolls instead of pushing the footer out of a fixed-size panel.
- Keep the header and footer out of that scroll region, so microphone state and the controls that act on it stay on screen at any session count.
- Give session rows their natural height instead of sharing the panel between them.
The bug
The expanded panel is a fixed 620x520 box with overflow: hidden. The session list grows with however many sessions a developer is running, and past four it pushed the footer out of the panel. Nothing could scroll it back: the root is deliberately overflow: clip, because hidden would leave a scroll container that a focus or scrollIntoView can use to drag the notch capsule out of view while compact.
Five observed sessions was enough to put the microphone permission readout, "Start microphone", and "Quit" out of reach — well within what Luke is for.
Why the body and not the root
overflow: clip on the root is load-bearing and stays. The new scroll container is scoped to the panel body and carries overscroll-behavior: contain, so it cannot chain a scroll up to the root and reintroduce the problem that comment is guarding against. min-height: 0 is what actually lets it scroll — a flex child defaults to its content size and would otherwise keep pushing the footer down.
Evidence
- Platform-independent checks:
./scripts/check.shpassed — lint, 3 typecheck projects, 62 tests (5 harness, 31 core, 26 desktop), all builds - macOS Electron verification (
./scripts/verify.sh): not run — this Linux workspace cannot package the macOS app; CI's macOS app/evidence job covers it - Layout measured against the real
styles.cssat 620x520 in headless Chrome, before and after, across session counts.footerCutOffByis how far the footer sits below the panel's bottom edge in pixels;lastRowReachablescrolls the body to its end first and then asks whether the final row is in view.
Before:
sessions= 3: footerCutOffBy=0 startReachable=true
sessions= 4: footerCutOffBy=0 startReachable=true
sessions= 5: footerCutOffBy=60 startReachable=false
sessions= 6: footerCutOffBy=130 startReachable=false
sessions= 8: footerCutOffBy=270 startReachable=false
sessions=12: footerCutOffBy=550 startReachable=false
After:
sessions= 3: footerCutOffBy=0 startReachable=true scrollable=false lastRowReachable=true
sessions= 4: footerCutOffBy=0 startReachable=true scrollable=true lastRowReachable=true
sessions= 5: footerCutOffBy=0 startReachable=true scrollable=true lastRowReachable=true
sessions= 6: footerCutOffBy=0 startReachable=true scrollable=true lastRowReachable=true
sessions= 8: footerCutOffBy=0 startReachable=true scrollable=true lastRowReachable=true
sessions=12: footerCutOffBy=0 startReachable=true scrollable=true lastRowReachable=true
That measurement is Chrome rendering the real stylesheet, not the packaged Electron app. It establishes the CSS math and the regression threshold; it does not replace looking at the app.
Automated visual evidence
Download the deterministic macOS evidence · workflow run
- Commit:
20bb11e448cb6adcabeed569349e74546c693d6a - Scenario:
smoke - Physical-notch check: not performed by CI
Physical-device evidence
- Screenshot or screen recording:
not attached - Physical-notch check:
not performed - Device/display configuration:
not recorded
Notes
- The fixture scenario has three sessions, so the deterministic evidence screenshots are unchanged by this fix. The CI PNGs are worth an eye anyway, since the flex changes touch how rows are sized at counts the fixture does not cover.
- This is a precursor to #12, which adds a voice panel below the session list and hits the same ceiling much sooner.
🤖 Generated with Claude Code