diff --git a/apps/web/src/pages/workspace/index.tsx b/apps/web/src/pages/workspace/index.tsx index bad69f36..0bab9f5e 100644 --- a/apps/web/src/pages/workspace/index.tsx +++ b/apps/web/src/pages/workspace/index.tsx @@ -1323,56 +1323,60 @@ export function StageWorkspace({ className="composer" data-working={working || sending ? "" : undefined} > - {attachFault === null ? null : ( -

- {attachFault} -

- )} - {sendFailed && sendFault ? ( -

- {sendFault} -

- ) : null} - {caution === null ? null : ( -
-

{wording.earlierDocument.warning(participantLabel(caution))}

-
- - {wording.earlierDocument.sendAnyway} - - { - setCaution(null); - composerRef.current?.focus(); - }} - > - {wording.action.cancel} - +
+ {attachFault === null ? null : ( +

+ {attachFault} +

+ )} + {sendFailed && sendFault ? ( +

+ {sendFault} +

+ ) : null} + {caution === null ? null : ( +
+

+ {wording.earlierDocument.warning(participantLabel(caution))} +

+
+ + {wording.earlierDocument.sendAnyway} + + { + setCaution(null); + composerRef.current?.focus(); + }} + > + {wording.action.cancel} + +
-
- )} - {replies.length > 0 && !providerMissing ? ( -
- {replies.map((reply) => ( - void deliver(reply)} - > - {reply} - - ))} -
- ) : null} + )} + {replies.length > 0 && !providerMissing ? ( +
+ {replies.map((reply) => ( + void deliver(reply)} + > + {reply} + + ))} +
+ ) : null} +
.workspace-fault { +.composer-notes > .workspace-fault { padding: 0; } diff --git a/apps/web/src/styles.css b/apps/web/src/styles.css index 13f66762..656d4051 100644 --- a/apps/web/src/styles.css +++ b/apps/web/src/styles.css @@ -1049,15 +1049,28 @@ h3 { gap: var(--space-2); flex: none; position: relative; - /* However long the text gets, the box stops at a share of the window and - the text scrolls inside it (#160): a `flex: none` row that outgrew the - column pushed the send, stop, attach and mic controls below the pane's - edge, where nothing could reach them. */ + /* Capped so the send, stop, attach and mic controls never leave the pane. + The composer itself must not scroll: the attachment tray and the model + list float above the box, and a scrolling composer clips them. The + textarea scrolls its own text, and the notes above the box give way. */ max-height: 70vh; min-height: 0; +} + +/* Errors, the earlier-document caution and suggested replies share one + region that scrolls once the composer reaches its cap, so the box below + keeps its full height. */ +.composer > .composer-notes { + display: grid; + gap: var(--space-2); + min-height: 0; overflow-y: auto; } +.composer > .composer-notes:empty { + display: none; +} + /* The box itself is a flex column: textarea body above, action row beneath. Capping the box and letting the body scroll keeps the action row pinned at every text length. The textarea's own cap is the library's 200px; a @@ -1090,18 +1103,6 @@ h3 { overflow-y: auto; } -/* The send-back picker a hold on send raises, the reviewer's notes and the - model profile list float above the composer, anchored to it rather than the - viewport. The composer scrolls its own overflow (#160), which would clip them - above it, so it stops while one is open (#210). */ -.composer:has(> .sbpick), -.composer:has([data-slot="prompt-input-model-select"][data-state="open"]), -.composer:has(.reviewer-stance[data-open]), -.composer:has(.reviewer-stance:hover), -.composer:has(.reviewer-stance:focus-within) { - overflow: visible; -} - .document { border: 1px solid var(--wb-border); background: var(--wb-card);