From 32a7d457f56b3ebbc9cd02984f9ce78b0c150323 Mon Sep 17 00:00:00 2001 From: Regan Bell Date: Mon, 10 Aug 2026 15:42:49 -0400 Subject: [PATCH] web-ui: size chat gutters by the surface's own width, not the window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A chat pane's column width and gutters were driven by window-level responsive state: a max-width media query set the layout variables globally on :root, and the height-driven compact density tier hard-coded the chat scroll's horizontal padding. In the split canvas a pane's size is decoupled from the window, so resizing the window flipped panes between a centered column with wide gutters and a full-bleed layout — user messages crowded the pane edge. Each chat surface is now an inline-size container and the layout variables are driven by container queries on the surface's own width; the compact density tier only squeezes vertical padding. Single-pane behavior at the same widths is unchanged. --- plugins/web-ui/src/shell.css | 49 +++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/plugins/web-ui/src/shell.css b/plugins/web-ui/src/shell.css index e4f6fd67f..6365ac321 100644 --- a/plugins/web-ui/src/shell.css +++ b/plugins/web-ui/src/shell.css @@ -972,6 +972,10 @@ a.chat-row-open { flex: 1; min-height: 0; display: flex; + /* Chat layout (gutters, content width) is driven by this surface's own width via + container queries below, so a pane in the split canvas lays out by its pane size, + not by whatever the window happens to be. */ + container: chat / inline-size; } .custom-chat-shell { flex: 1; @@ -4061,10 +4065,6 @@ a.chat-row-open { } @media (max-width: 860px) { - :root { - --chat-pad: 14px; - --content-w: 100%; - } .layout { position: relative; } @@ -4153,24 +4153,12 @@ a.chat-row-open { .message-bubble { max-width: 88%; } - .composer-wrap { - width: auto; - margin-right: calc(10px + env(safe-area-inset-right)); - margin-bottom: calc(10px + env(safe-area-inset-bottom)); - margin-left: calc(10px + env(safe-area-inset-left)); - border-radius: 18px; - } .composer-approval { grid-template-columns: 1fr; } .composer-approval .approval-actions { justify-content: flex-start; } - .live-work-dock { - width: auto; - margin-right: calc(10px + env(safe-area-inset-right)); - margin-left: calc(10px + env(safe-area-inset-left)); - } .composer-toolbar { align-items: flex-end; } @@ -6682,7 +6670,7 @@ h3.ambient-field-label { } [data-density="compact"] .chat-scroll { - padding: 14px 14px 4px; + padding: 14px var(--chat-pad) 4px; } [data-density="compact"] .message-row { --meta-lane: 16px; @@ -6694,6 +6682,33 @@ h3.ambient-field-label { [data-density="compact"] .live-work-detail { display: none; } + +/* The chat's column width and gutters follow the surface's own width (window or pane), + never the window's size — resizing the window must not flip a pane's alignment. */ +@container chat (max-width: 860px) { + .custom-chat-shell { + --content-w: 100%; + } +} +@container chat (max-width: 470px) { + .custom-chat-shell { + --chat-pad: 14px; + } + /* The floating composer/dock margins pair with the full-bleed 14px chat pad and must + follow the surface's width too, or a window resize misaligns them with the column. */ + .composer-wrap { + width: auto; + margin-right: calc(10px + env(safe-area-inset-right)); + margin-bottom: calc(10px + env(safe-area-inset-bottom)); + margin-left: calc(10px + env(safe-area-inset-left)); + border-radius: 18px; + } + .live-work-dock { + width: auto; + margin-right: calc(10px + env(safe-area-inset-right)); + margin-left: calc(10px + env(safe-area-inset-left)); + } +} [data-density="card"] .context-banner, [data-density="strip"] .context-banner, [data-density="card"] .live-work-dock,