diff --git a/src/web-ui/src/flow_chat/_transcript-layout.scss b/src/web-ui/src/flow_chat/_transcript-layout.scss index 3ecb27f158..ae392e0752 100644 --- a/src/web-ui/src/flow_chat/_transcript-layout.scss +++ b/src/web-ui/src/flow_chat/_transcript-layout.scss @@ -11,14 +11,17 @@ $turn-rail-width: 30px; box-sizing: border-box; min-width: 0; width: 100%; - margin-inline: 0; + max-width: 900px; + margin-inline: auto; - // Reserve only the rail side plus a small opposite inset. Message rows use - // the remaining transcript width; neither the composer nor the welcome - // surface needs this lane. + // Reserve only the rail side plus a small opposite inset. Wide columns stay + // centered; neither the composer nor the welcome surface needs this lane. @container flow-chat-transcript (min-width: 0px) { width: calc(100% - #{$turn-rail-offset + $turn-rail-width} - var(--openbitfun-space-1) - var(--openbitfun-space-2)); - margin-inline-start: calc(#{$turn-rail-offset + $turn-rail-width} + var(--openbitfun-space-1)); + margin-inline-start: max( + calc(#{$turn-rail-offset + $turn-rail-width} + var(--openbitfun-space-1)), + calc((100% - 900px) / 2) + ); } } diff --git a/src/web-ui/src/flow_chat/components/modern/ExploreRegion.scss b/src/web-ui/src/flow_chat/components/modern/ExploreRegion.scss index f833f8922f..cdc3aa5d2b 100644 --- a/src/web-ui/src/flow_chat/components/modern/ExploreRegion.scss +++ b/src/web-ui/src/flow_chat/components/modern/ExploreRegion.scss @@ -7,10 +7,10 @@ @include transcriptLayout.content-column; position: relative; overflow: hidden; - /* Fill the shared transcript row so the collapse header (`>`) and the - * round's body text share both edges. */ - width: 100%; - margin: 0; + /* Same column box as .model-round-item so the collapse header (`>`) and the + * round's body text share one leading edge. */ + width: min(100%, 900px); + margin: 0 auto; padding-block: 0; } diff --git a/src/web-ui/src/flow_chat/components/modern/FLOWCHAT_VIRTUALIZATION.md b/src/web-ui/src/flow_chat/components/modern/FLOWCHAT_VIRTUALIZATION.md index bc9e498c74..1649a9ef81 100644 --- a/src/web-ui/src/flow_chat/components/modern/FLOWCHAT_VIRTUALIZATION.md +++ b/src/web-ui/src/flow_chat/components/modern/FLOWCHAT_VIRTUALIZATION.md @@ -181,8 +181,8 @@ actions remain visible at rest, without requiring hover or keyboard focus. shells, model rounds, Explore regions, and the runtime-status footer. The messages viewport enables a shared outer column rule for virtual rows and the runtime footer: reserve the turn rail's offset and hit area plus space-1 on -the leading side, and only space-2 on the trailing side. Rows use the remaining -transcript width without a fixed reading-width cap. This rule is local to the +the leading side, and only space-2 on the trailing side. Columns remain centered +when there is room for the full 900px reading width. This rule is local to the transcript; the composer and welcome surface keep their existing widths, and embedded transcripts without a rail keep their own layout. The scroller remains full width. diff --git a/src/web-ui/src/flow_chat/components/modern/UserMessageItem.scss b/src/web-ui/src/flow_chat/components/modern/UserMessageItem.scss index 51f88210e4..1064c96f2f 100644 --- a/src/web-ui/src/flow_chat/components/modern/UserMessageItem.scss +++ b/src/web-ui/src/flow_chat/components/modern/UserMessageItem.scss @@ -20,7 +20,6 @@ * its radius so the rounded surface and message text meet that column. */ width: fit-content; - min-width: min(8rem, 72%); max-width: min(72%, 48rem); padding: 0.46rem var(--_user-message-padding-inline); background: var(--openbitfun-color-action-quiet-hover); diff --git a/src/web-ui/src/flow_chat/components/modern/UserMessageItemActions.test.ts b/src/web-ui/src/flow_chat/components/modern/UserMessageItemActions.test.ts index d60aadae5e..370966764d 100644 --- a/src/web-ui/src/flow_chat/components/modern/UserMessageItemActions.test.ts +++ b/src/web-ui/src/flow_chat/components/modern/UserMessageItemActions.test.ts @@ -43,7 +43,7 @@ describe('UserMessageItem metadata visibility', () => { expect(textarea).toContain('min-height: var(--openbitfun-control-height-sm);'); expect(richInput).toContain('min-height: var(--openbitfun-control-height-sm);'); expect(bubble).toContain('width: fit-content;'); - expect(bubble).toContain('min-width: min(8rem, 72%);'); + expect(bubble).not.toContain('min-width:'); expect(bubble).toContain('max-width: min(72%, 48rem);'); expect(bubble).toContain('border: none;'); expect(main).toContain('justify-content: center;'); diff --git a/src/web-ui/src/flow_chat/components/modern/VirtualItemRenderer.scss b/src/web-ui/src/flow_chat/components/modern/VirtualItemRenderer.scss index 31bba24d44..3f7829863a 100644 --- a/src/web-ui/src/flow_chat/components/modern/VirtualItemRenderer.scss +++ b/src/web-ui/src/flow_chat/components/modern/VirtualItemRenderer.scss @@ -1,6 +1,6 @@ /** * Virtual item renderer wrapper styles. - * Shared transcript row geometry and content rhythm. + * A4-like reading width with centered content. */ @use '../../flat-markdown-surfaces' as flatMarkdownSurfaces; @use '../../markdown-typography' as markdownTypography; @@ -17,10 +17,11 @@ display: flow-root; /* - * One transcript row is shared by every item type (model rounds, explore - * groups, user messages, notices). transcript-layout reserves the turn-rail - * lane; leaf content owns its inset, and user-bubble decoration may extend - * into that gutter without shifting the text. + * Single reading column shared by every item type (model rounds, explore + * groups, user messages, notices). Matches ChatInput's 900px so headers, + * `>` collapse rows, and message text all sit on the same leading edge. + * transcript-layout owns the shared content inset; user-bubble decoration + * extends into that gutter without shifting the reading column. */ margin-block: 0; min-height: 1px; diff --git a/src/web-ui/src/flow_chat/components/modern/VirtualItemRenderer.tsx b/src/web-ui/src/flow_chat/components/modern/VirtualItemRenderer.tsx index 9a2684f48c..b0ffe807be 100644 --- a/src/web-ui/src/flow_chat/components/modern/VirtualItemRenderer.tsx +++ b/src/web-ui/src/flow_chat/components/modern/VirtualItemRenderer.tsx @@ -118,8 +118,8 @@ export const VirtualItemRenderer = React.memo( } })(); - // The wrapper owns shared transcript geometry and virtualization measurement. - // Render it even when content is empty to avoid zero-size issues. + // A4-like layout: wrap with a max-width container. + // Render the container even when content is empty to avoid zero-size issues. // data-turn-id is used for long-image export. return (