Composer Dock
The workspace input module — mounts the existing Composer (.lb-composer — chips, attach, mic, send, model slot, all LB.Composer behavior) at the bottom of a canvas. Docked by default (sticky — a floating bar would overlap the last message instead of letting the thread scroll clear of it). --floating is the opt-in for media/canvas contexts where nothing scrolls underneath. Content caps at --lb-dock-max (48rem) so the composer lines up with the thread above it — the same measure as --lb-chat-thread-width. The parameter tray is a consumed Popover (--top --tray) with Segmented option rows — the disclosure semantics come from Popover, and the dock ships no JS of its own. Consumed here: Composer · Popover · Chip · Segmented · Banner. See it composed in the AI Chat template.
a11y (built in): suggestion chips are real buttons before the input in DOM order; tray toggle gets aria-haspopup/expanded/controls + Esc + outside-click from Popover; safe-area padding for home-indicator devices. Mobile: on-screen keyboards shrink the visual viewport and the sticky dock rides along natively.
A · Docked — chat canvas
Scroll the box — the dock stays pinned, content passes under the fade-free solid band. Suggestion chips above, hint line below, model button opens the tray. Actions are split by type: the input row holds only text + send; single-action buttons (attach, mic) live in the footer-left tools slot, and multi-option triggers (model — a menu, so it carries the chevron per the affordance policy) sit footer-right. An optional compact notice (.lb-dock__notice + .lb-banner--s) can sit above the composer.
B · --floating — media canvas
Nothing scrolls under the bar, so it may overlay the canvas. The host container sets position: relative. Tray here carries generation parameters (ratio · count) — segmented rows inside the same consumed Popover.
Usage
Pure CSS module — the composer brings its own LB.Composer behavior (load js/components/lb-chat.js), the tray is a standard data-lb-popover. Docked: place .lb-dock as the last child of the scroll container. Floating: add --floating and give the host position: relative.
<div class="lb-dock"> <!-- or .lb-dock.lb-dock--floating -->
<div class="lb-dock__inner">
<div class="lb-dock__suggestions"><button class="lb-chip">Example prompt</button></div> <!-- optional -->
<div class="lb-composer" data-lb-composer>
… chips row + input row (textarea only) + footer: tools left (attach/mic) · end cluster right (model + send) …
<div class="lb-composer__model">
<div class="lb-popover-host" data-lb-popover> <!-- parameter tray -->
<button class="lb-popover-trigger lb-btn lb-btn--ghost lb-btn--small">Model ▾</button>
<div class="lb-popover lb-popover--top lb-popover--tray" style="display:none;">
<div class="lb-dock__tray-row">
<span class="lb-dock__tray-label">Aspect ratio</span>
<div class="lb-segmented lb-segmented--full-width" data-lb-segmented>…</div>
</div>
</div>
</div>
</div>
</div>
<p class="lb-dock__hint">Enter to send · Shift+Enter = new line</p> <!-- optional -->
</div>
</div>