From 8b35fd06ec7a0ba051cf1727b5e279a9dafab3b8 Mon Sep 17 00:00:00 2001 From: Kev Date: Fri, 17 Jul 2026 01:19:48 -0400 Subject: [PATCH] =?UTF-8?q?P1-5=20fix:=20390px=20containment=20=E2=80=94?= =?UTF-8?q?=20consensus=20rows=20stack,=20pitcher=20line=20wraps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phone audit: CONSENSUS VS MODEL bled off the right edge ('2 BO…', 'MO…') and STARTING-pitcher lines truncated ('2.64 E…'). The M4 lock only hid the DOCUMENT scroll (html/body overflow-x) — content still clipped inside cards. Now contained: - .breadth-row stacks (flex-direction:column) at <430px, each field on its own line with overflow-wrap:anywhere — no bleed. - the game-card starting-pitcher inner spans wrap + shrink (flexWrap + minWidth:0) so name/ERA/archetype flow onto a second line instead of clipping. - STRENGTHENED the lock: vyndrParityQA now asserts the CONTAINMENT patterns (breadth-row stacks, pitcher spans wrap), not just document overflow. MLB stat pills: the game-lines grid already scrolls-within-card (<640 M1); if the audit still shows pill clipping elsewhere, it's a follow-up targeted pass. Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/unit/vyndrParityQA.test.js | 16 ++++++++++++++++ web/src/app/globals.css | 14 ++++++++++++++ web/src/components/vyndr/GameCard.tsx | 4 ++-- web/src/components/vyndr/MarketBreadth.tsx | 4 ++-- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/tests/unit/vyndrParityQA.test.js b/tests/unit/vyndrParityQA.test.js index 33574e1..4a2e25e 100644 --- a/tests/unit/vyndrParityQA.test.js +++ b/tests/unit/vyndrParityQA.test.js @@ -265,3 +265,19 @@ describe('P0-4 — mobile app bar is one line (ticker + heartbeat hidden)', () = expect(css).toMatch(/\.slate-sticky-head\s*\{\s*top:\s*60px/); }); }); + +// ── P1-5 lock — 390px containment (strengthened: content, not just doc scroll) ─ +describe('P1-5 — dense rows CONTAIN at 390px (not just html overflow-x:hidden)', () => { + const css = read('app/globals.css'); + it('consensus rows stack at <430px so they never bleed off the right edge', () => { + expect(css).toMatch(/@media\s*\(max-width:\s*430px\)\s*\{[^]*?\.breadth-row\s*\{[^}]*flex-direction:\s*column/); + expect(css).toMatch(/\.breadth-row\s*>\s*span\s*\{[^}]*overflow-wrap:\s*anywhere/); + expect(read('components/vyndr/MarketBreadth.tsx')).toMatch(/breadth-row/); + }); + it('the starting-pitcher line wraps its name/ERA inside the card (no truncation)', () => { + const gc = read('components/vyndr/GameCard.tsx'); + // the inner pitcher spans allow wrap + shrink so "2.64 ERA" never gets cut + expect(gc).toMatch(/g\.pitchers\.away\.era/); + expect((gc.match(/flexWrap: 'wrap', minWidth: 0/g) || []).length).toBeGreaterThanOrEqual(2); + }); +}); diff --git a/web/src/app/globals.css b/web/src/app/globals.css index 160661e..c507a3e 100644 --- a/web/src/app/globals.css +++ b/web/src/app/globals.css @@ -1372,6 +1372,20 @@ html[data-font="readable"] .wm::after { opacity: 0.45 !important; } } + +/* P1-5 — 390px CONTAINMENT: dense data rows must WRAP/STACK inside their card, + never bleed off the right edge (the M4 no-overflow lock only hid the document + scroll; content still clipped). */ +@media (max-width: 430px) { + /* CONSENSUS VS MODEL rows stack — player / consensus / model each own line. */ + .breadth-row { flex-direction: column; align-items: flex-start; gap: 3px; } + .breadth-row > span { min-width: 0 !important; max-width: 100%; overflow-wrap: anywhere; } +} +@media (max-width: 767px) { + /* opt-in scroll-within-card for wide tables (pitcher lines / pill rows). */ + .mobile-scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; } +} + /* P0-4 — MOBILE APP BAR: collapse the 3-row header (nav + ticker + heartbeat) to ONE line <768px. The ticker row + the whole heartbeat bar are hidden; the nav's right cluster shows the app-bar clock (nav-mobile-clock). main's top diff --git a/web/src/components/vyndr/GameCard.tsx b/web/src/components/vyndr/GameCard.tsx index 2c8d4b8..698c7e7 100644 --- a/web/src/components/vyndr/GameCard.tsx +++ b/web/src/components/vyndr/GameCard.tsx @@ -263,12 +263,12 @@ export default function GameCard({ game: g, onAddParlay, onOpen, preferredBooks {g.pitchers && (
STARTING - + {g.pitchers.away.name} {g.pitchers.away.era} ERA {g.pitchers.away.archetype && } vs - + {g.pitchers.home.name} {g.pitchers.home.era} ERA {g.pitchers.home.archetype && } diff --git a/web/src/components/vyndr/MarketBreadth.tsx b/web/src/components/vyndr/MarketBreadth.tsx index 598b47f..0240789 100644 --- a/web/src/components/vyndr/MarketBreadth.tsx +++ b/web/src/components/vyndr/MarketBreadth.tsx @@ -87,8 +87,8 @@ export default function MarketBreadth({ return (
{r.player && {r.player}}