P0-4 fix: mobile header collapses to ONE line — logo + clock + sync dot

Phone audit: at 390px we still rendered the full desktop 3-row header (nav +
TOP MOVES ticker + SYNC line) eating ~20% of the viewport, and its height
clipped page titles under it (MY READS tabs, HEAD TO HEAD). Implemented Design's
mobile app bar <768px:
- New MobileSyncClock (extracted from HeartbeatBar) lives in the Nav's right
  cluster — wall clock rests, amber/STALE reacts off the shared freshness tier.
- <768px: the ticker row (.nav-ticker) AND the whole heartbeat bar are hidden;
  only the nav row shows (logo + clock + search). main padding-top → 62px and
  the Slate sticky tabs → top:60px, so nothing clips under the bar.
- Locked in vyndrParityQA (P0-4): ticker+heartbeat hidden, nav clock shown,
  paddings collapsed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kev
2026-07-17 01:15:24 -04:00
parent db61876b2f
commit ff53f31bfc
5 changed files with 96 additions and 4 deletions
+19
View File
@@ -246,3 +246,22 @@ describe('P0-1 — grade badges are token-derived; blue-B / amber-C banished', (
expect(css).toMatch(/\.grade-c-bg\s*\{[^}]*color-mix\(in srgb, var\(--grade-c\)/);
});
});
// ── P0-4 lock — mobile header collapses to ONE line ──────────────────────
describe('P0-4 — mobile app bar is one line (ticker + heartbeat hidden)', () => {
const css = read('app/globals.css');
it('<768px hides the ticker row + the whole heartbeat bar; nav clock shows', () => {
expect(css).toMatch(/@media\s*\(max-width:\s*767px\)\s*\{[^]*?\.nav-ticker\s*\{[^}]*display:\s*none/);
expect(css).toMatch(/@media\s*\(max-width:\s*767px\)\s*\{[^]*?\.heartbeat-bar\s*\{[^}]*display:\s*none/);
expect(css).toMatch(/\.nav-mobile-clock\s*\{\s*display:\s*none/); // desktop hides it
expect(css).toMatch(/@media[^]*?\.nav-mobile-clock\s*\{[^}]*display:\s*inline-flex/);
// the clock is wired into the nav, freshness-driven (never silently stale)
const nav = read('components/Nav.tsx');
expect(nav).toMatch(/MobileSyncClock/);
expect(nav).toMatch(/nav-mobile-clock/);
});
it('main top padding + slate sticky drop to the 60px bar on mobile (no clipping)', () => {
expect(css).toMatch(/@media[^]*?main\s*\{[^}]*padding-top:\s*62px/);
expect(css).toMatch(/\.slate-sticky-head\s*\{\s*top:\s*60px/);
});
});