Skip to content

Zoom: one number for both ways of reading a session - #61

Merged
thomwolf merged 1 commit into
mainfrom
reader/zoom-follows-render-mode
Aug 13, 2026
Merged

Zoom: one number for both ways of reading a session#61
thomwolf merged 1 commit into
mainfrom
reader/zoom-follows-render-mode

Conversation

@thomwolf

Copy link
Copy Markdown
Member

The zoom in the bottom bar sits next to the terminal/reader switch because they are the same kind of setting — how you are looking at everything. But it only moved the terminal: conversation.css is written in absolute px, so a reader pane ignored it, and flipping modes quietly changed how big your session was.

What this does

The conversation grammar gets one base size--cx-base, 13px by default — and every type size in it becomes an em of that. The terminal spends the zoom on its xterm font size, the reader spends the same number on --cx-base (set on .pane-reader), so 13px at 100% either way and switching modes no longer resizes anything.

The reader scales as one surface — bar, turns, tool output, reply line, footer. A 10.5px toolbar left behind at 150% is the part you could not read in the first place; the remote pane already treats its log, composer and status line as one size for the same reason.

Things the px→em pass had to be careful about

  • The Overview card shares this grammar and must not move. Hence a var(--cx-base, 13px) default rather than an inherited size: the card resolves to exactly the sizes it had.
  • The answer's markdown needed its own heading sizes — the shared .markdown rules are absolute px, so an h1 would have stayed 22px while the prose around it grew.
  • Spacing does not scale, but glyph columns must: the prompt's gutter, the step rail's ▸/✓ column and the body inset under it, the tool-field label column (was 4.5rem). At 200% the chevron ran into the first word of the prompt.
  • .cs-pre's scroll cap is really "about twenty lines" — in rem it showed ten at 200%; in em it stays nineteen at every zoom.

Two deliberate visible changes

  • The phone keyboard field keeps a fixed 16px: that guard is what stops iOS zoom-on-focus, and the new rule is later in the cascade, so styles.css's version is restated in this file. It is the one place the zoom does not reach.
  • .cxv-top (Reader: come back to where you were reading #59's "earlier messages" line) now says the size it means. font: inherit sheds the button's UA font but also resets the size the element gets from its own .cxv-msg class, so it had been landing on the app's inherited 16px in a column of 11px messages. It is 0.85em now, like its siblings.

Verification

tsc --noEmit clean; web/test/exchanges|overviewSort|sessionTitle pass.

Measured in Chromium against a fixture built from the real ConversationView / Exchange / ToolCall DOM, comparing computed sizes with the pre-change stylesheet:

  • nothing moves at 100% except .cxv-top (16 → 11.05px, above), and the two container elements that now carry the base and hold no direct text;
  • every element in the reader scales exactly 0.5×/2× at 50%/200% — bar, prompt, meta, rail, tool fields, markdown headings, reply line, footer, and the "reading the trace…" state;
  • the Overview card is untouched at all three;
  • nothing overflows the pane sideways at 200%.

Deployed to the thomwolf/agent-manager test Space for a look in the real app.

🤖 Generated with Claude Code

The bottom bar puts the terminal/reader switch next to the zoom because they are
the same kind of setting — how you are looking at everything. But the zoom only
moved the terminal: `conversation.css` was written in absolute px, so a reader
pane ignored it entirely, and the mode switch quietly changed how big your
session was.

So the grammar gets ONE base size — `--cx-base`, 13px by default — and every
type size in it becomes an em of that. The terminal spends the zoom on its font
size, the reader on `--cx-base` (set on `.pane-reader`), and 13px at 100% either
way means switching modes no longer resizes the conversation.

The reader scales as one surface: bar, turns, tool output, reply line, footer.
A 10.5px toolbar left behind at 150% would be the part you could not read in the
first place — the remote pane already treats its log, composer and status line as
one size for the same reason.

Four things the px-to-em pass had to be careful about:

- **The Overview card shares this grammar and must not move.** That is why the
  base is a `var(--cx-base, 13px)` default rather than something inherited: the
  card resolves to exactly the sizes it had.
- **The answer's markdown needed its own heading sizes.** The shared `.markdown`
  rules are absolute px, so an answer's `h1` would have stayed 22px while the
  prose around it grew. Same proportions, in em, and this file loads after
  styles.css.
- **Spacing does not scale, but glyph columns must.** The prompt's `❯` gutter,
  the step rail's ▸/✓ column and the body inset under it, and the tool-field
  label column (was `4.5rem`) are all em now. At 200% the chevron was running
  into the first word of the prompt.
- **`.cs-pre`'s scroll cap is really "about twenty lines".** In rem it showed ten
  at 200%; in em it stays nineteen at every zoom.

Two deliberate visible changes beyond that. The phone keyboard field keeps its
fixed 16px — that guard is what stops iOS zoom-on-focus, and the new rule is
later in the cascade, so styles.css's version is restated here. And `.cxv-top`
(#59's "earlier messages" line) says the size it means: `font: inherit` sheds the
button's UA font but also resets the size the element gets from `.cxv-msg`, so it
had been landing on the app's inherited 16px in a column of 11px messages.

Verified in Chromium against a fixture built from the real ConversationView /
Exchange / ToolCall DOM, comparing computed sizes with the pre-change stylesheet:
nothing moves at 100% except `.cxv-top`, every element in the reader scales
exactly 0.5x/2x at 50%/200%, the Overview card is untouched at all three, and
nothing overflows the pane sideways at 200%.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@thomwolf
thomwolf force-pushed the reader/zoom-follows-render-mode branch from d8dcf48 to 0637538 Compare August 13, 2026 00:23
@thomwolf
thomwolf merged commit 03b5cf0 into main Aug 13, 2026
@thomwolf
thomwolf deleted the reader/zoom-follows-render-mode branch August 13, 2026 00:40
lvwerra pushed a commit that referenced this pull request Aug 13, 2026
Rebased onto main after #59 and #61, which cover ground this branch also
touched. Theirs wins in both places: #61 made zoom ONE number for both ways of
reading a session (`--cx-base` on `.pane-reader`), so the branch's second path
— a `zoom` prop and `zoom: var(--cx-zoom)` on `.cxv-body` — is gone rather than
reintroduced; and #59 comes back to where you had got to, over a tail window
that already opens on the end, so the branch's own open-on-the-newest-turn
landing (reader and trace viewer both) is gone too. TracePane keeps main's
version entirely.

What is left is what main does not have:

- **The prompt band spans the pane.** Reaching into the left gutter but stopping
  at the text column on the right made it read as a card floating over the
  answer rather than as the head of it. Full bleed both sides; the meta row sits
  tight under the band it belongs to, and one exchange ends well before the next
  begins.
- **Nothing of the terminal's may paint over the reader.** Its covers —
  `restoring last view…`, `starting claude…`, `stopped · output preserved` — sit
  at `z-index: 4` and were drawn straight over the conversation, so a reconnect
  turned the reader into a terminal screen with a reader toolbar on top. They
  are gated off while reading, and the overlay now outranks anything the
  terminal can raise.
- **One `Composer` for the card and the reader.** A composer accretes features —
  paste-to-attach, history recall, a slash-command menu — and duplicated markup
  is how one surface quietly gets them and the other does not. `onPasteFiles`
  and `above` are the seam an attachment strip plugs into. The echo is now
  optimistic in both: the prompt appears before the POST returns, and a failed
  send withdraws it and puts the text back in the box.
- **The reader switch is the same height as the zoom keys** (22px, like the
  layout picker beside it).

Verified against a running instance with a fixture transcript: the reader
renders, the band bleeds to the right edge, an injected `.term-boot` cover
paints behind the overlay, the bottom bar is one height, a sent prompt echoes
before the POST returns, and main's zoom still scales the reader through
`--cx-base` with no second path in play. Server, web and UI suites green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lvwerra added a commit that referenced this pull request Aug 13, 2026
Rebased onto main after #59 and #61, which cover ground this branch also
touched. Theirs wins in both places: #61 made zoom ONE number for both ways of
reading a session (`--cx-base` on `.pane-reader`), so the branch's second path
— a `zoom` prop and `zoom: var(--cx-zoom)` on `.cxv-body` — is gone rather than
reintroduced; and #59 comes back to where you had got to, over a tail window
that already opens on the end, so the branch's own open-on-the-newest-turn
landing (reader and trace viewer both) is gone too. TracePane keeps main's
version entirely.

What is left is what main does not have:

- **The prompt band spans the pane.** Reaching into the left gutter but stopping
  at the text column on the right made it read as a card floating over the
  answer rather than as the head of it. Full bleed both sides; the meta row sits
  tight under the band it belongs to, and one exchange ends well before the next
  begins.
- **Nothing of the terminal's may paint over the reader.** Its covers —
  `restoring last view…`, `starting claude…`, `stopped · output preserved` — sit
  at `z-index: 4` and were drawn straight over the conversation, so a reconnect
  turned the reader into a terminal screen with a reader toolbar on top. They
  are gated off while reading, and the overlay now outranks anything the
  terminal can raise.
- **One `Composer` for the card and the reader.** A composer accretes features —
  paste-to-attach, history recall, a slash-command menu — and duplicated markup
  is how one surface quietly gets them and the other does not. `onPasteFiles`
  and `above` are the seam an attachment strip plugs into. The echo is now
  optimistic in both: the prompt appears before the POST returns, and a failed
  send withdraws it and puts the text back in the box.
- **The reader switch is the same height as the zoom keys** (22px, like the
  layout picker beside it).

Verified against a running instance with a fixture transcript: the reader
renders, the band bleeds to the right edge, an injected `.term-boot` cover
paints behind the overlay, the bottom bar is one height, a sent prompt echoes
before the POST returns, and main's zoom still scales the reader through
`--cx-base` with no second path in play. Server, web and UI suites green.

Co-authored-by: Agent Manager <agents@agent-manager.local>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant