Picture-in-picture
Picture-in-picture panel
<lab-pip-panel> · js/components/pip-panel/
Universal PiP shell. Cream + ink + offset-shadow chrome via --widget-bar-* tokens, a default <slot> for the content element, and a single bottom bar carrying the device label (left) and, when the device declares magnification states, a generated toggle group (right). The label attribute is the instrument kind ("Microscope", "Magnifier"), from the step's widget_label; the bar hides only when there is neither a label nor any buttons. Below a ~300 px width the bar reflows — buttons stack above the label, both centred, with a smaller-button variant. The shell sizes adaptively (width clamps between a 240 px floor and a 380 px ceiling, tracking the right-edge bracket) and can render the shared Error state itself (the error attribute) when there is no content element to mount. Clicking a button sets objective and emits objective-change, which PipHandler relays to the content's HUD. Production positioning is owned by #pip-anchor; these previews pin --pip-panel-width and stack inline.
Microscope view
<lab-microscope-view> · js/components/microscope-view/
Pure PiP content element. 1:1 sample viewport over the shared --pip-base desk gray, with a light-mono HUD (magnification + sample identity bottom-left, scale bar bottom-right). It carries no device label and no controls — the shell owns the label and the magnification toggle group. The objective attribute (set by PipHandler, updated when the shell's buttons change it) drives the HUD readout only. Viewport states: Placeholder (target declared, real imagery pending — faint hatch + HUD), Empty (no target), Error (unresolved target). Real microscopy imagery is Phase D. Mounts inside <lab-pip-panel> via PIP_CONTENT_REGISTRY.
Magnifier view
<lab-magnifier-view> · js/components/magnifier-view/
Chrome-free PiP content element — a single square viewport over the shared --pip-base base. The image is not authored on the step; it is pushed at runtime via the pip-image event onto the src property. State follows the image: Empty (bare base) until the first push, Loaded once it arrives, Error if it fails to load (the <img> error event). No HUD, no controls; the device label is the shell's.