diff --git a/tradein-mvp/frontend/src/app/v2/page.tsx b/tradein-mvp/frontend/src/app/v2/page.tsx index 4d5ca0df..c6c8659b 100644 --- a/tradein-mvp/frontend/src/app/v2/page.tsx +++ b/tradein-mvp/frontend/src/app/v2/page.tsx @@ -411,16 +411,25 @@ export default function TradeInV2Page() { useEffect(() => setMounted(true), []); // Scale-fit: shrink the fixed 1536×1024 artboard to fit smaller viewports - // instead of clipping. Never upscale (capped at 1); recomputed on resize. + // instead of clipping. Never upscale (capped at 1). #2275: this used to floor + // at 0.88, which on a 390px phone still rendered the artboard ~1350px wide — + // page-wide horizontal scroll + a hero clipped at the left edge + the summary + // rail pushed off-screen. Width is now the only constraint (a scaled artboard + // taller than the viewport just scrolls the page vertically, which is normal + // and not the bug being fixed here). const [artboardScale, setArtboardScale] = useState(1); + // #2275: below this viewport width the fixed-width artboard can no longer + // read at a usable size even scaled-to-fit, so HeroBar + ObjectSummary (the + // "at a glance" content — report meta, PDF CTA, per-section totals) get a real + // fluid mobile block above the artboard instead of a tiny scaled-down copy. + // The rest of the dashboard (ParamsPanel / ResultPanel / overlays) stays + // inside the scaled artboard — smaller on phones, but no longer overflowing. + const [isMobile, setIsMobile] = useState(false); useEffect(() => { - const compute = () => - setArtboardScale( - Math.max( - 0.88, - Math.min(1, window.innerWidth / 1536, window.innerHeight / 1024), - ), - ); + const compute = () => { + setArtboardScale(Math.min(1, window.innerWidth / 1536)); + setIsMobile(window.innerWidth < 768); + }; compute(); window.addEventListener("resize", compute); return () => window.removeEventListener("resize", compute); @@ -573,7 +582,8 @@ export default function TradeInV2Page() { const topNavUser = useMemo(() => { const scope = me.data; if (!scope) return undefined; - const nameParts = scope.display_name?.trim().split(/\s+/).filter(Boolean) ?? []; + const nameParts = + scope.display_name?.trim().split(/\s+/).filter(Boolean) ?? []; const initials = nameParts.length >= 2 ? (nameParts[0][0] + nameParts[1][0]).toUpperCase() @@ -693,172 +703,221 @@ export default function TradeInV2Page() { } return ( -