Root cause: scale-to-fit formula had a 0.88 floor that defeated the fit
on viewports narrower than ~1350px, so the 1536px-wide artboard always
rendered wider than the screen. Removed the floor + height-ratio term:
scale is now purely innerWidth/1536 clamped to 1, so the artboard never
exceeds viewport width.
Added an honest fluid mobile block (HeroBar compact + ObjectSummary)
rendered above the (still-scaled) artboard on viewports <768px, instead
of illegible tiny text inside the transform. HeroBar gained a `compact`
prop for the column layout; default (desktop) path unchanged.
Review fixup: the outer return was a bare Fragment, so on mobile its two
root children (quick-view block + artboard) became siblings of
layout.tsx's row-direction flex container and laid out side-by-side
instead of stacked. Wrapped in a single flex-column div to restore the
"one flex child, centered" contract layout.tsx expects.
Verified live: injected an iframe (window.innerWidth genuinely 390-ish,
since the shared browser session's own viewport can't be resized) —
scrollWidth === clientWidth === innerWidth, zero horizontal overflow.
Console errors are pre-existing /api/v1/me 500s (no backend in this
dev instance), not layout-related.
Follow-up (not in scope): ParamsPanel/ResultPanel/TopNav/overlays have
no dedicated mobile layout yet — still inside the scaled artboard,
smaller on phones but no longer overflowing.