Files
portfolio/tasks/prd-responsive-scaling.md
T

14 KiB
Raw Blame History

PRD: Responsive Scaling & Mobile Layout

Introduction

The dashboard is built for 1080p screens. On larger displays (1440p, 4K), everything appears too small — text, spacing, and UI elements don't scale with the viewport. On mobile, the sidebar is completely inaccessible (hidden with no toggle), text doesn't wrap properly and spills off-screen, and several components are unusable at narrow widths.

This PRD addresses viewport-responsive scaling for larger screens and usability fixes for mobile, scoped to the dashboard phase only (TopBar, Sidebar, Card Grid, and all tiles).

Goals

  • Scale the dashboard proportionally on larger viewports (1440p should feel ~25% larger than 1080p)
  • Make the sidebar accessible on mobile via a slide-out drawer with toggle
  • Ensure all text wraps properly and nothing overflows horizontally at any viewport size
  • Maintain the current 1080p experience as the baseline — no changes at that resolution
  • Preserve the existing visual design language (fonts, colors, spacing ratios)

User Stories

US-000: Skip Boot/Login for Dev Iteration

Description: As a developer, I want to skip the boot/ECG/login animation during this feature branch so I can iterate on the dashboard quickly.

Acceptance Criteria:

  • In App.tsx, initial Phase state changed from 'boot' to 'pmr'
  • Boot, ECG, and login code remains — only initial state changes
  • App loads directly to dashboard on refresh
  • Typecheck passes
  • Reverted in final story (US-013)

US-001: Fluid Root Font-Size Scaling

Description: As a user on a high-resolution display, I want the dashboard to scale proportionally so that text and UI elements are comfortably sized without manual browser zoom.

Acceptance Criteria:

  • html element uses a clamp()-based font-size that scales with viewport width
  • At 1920px viewport width (1080p), effective font-size remains ~15px (current baseline)
  • At 2560px viewport width (1440p), effective font-size is ~1819px (~25% increase)
  • At 3840px viewport width (4K), font-size caps at a sensible maximum (~22px)
  • Below 1920px, font-size does not shrink below 15px (mobile/tablet keeps baseline)
  • Typecheck passes

US-002: Convert Fixed px to rem in Layout Structure

Description: As a developer, I need layout measurements to use rem so they scale with the root font-size, rather than remaining fixed at px values.

Acceptance Criteria:

  • CSS custom properties --topbar-height, --sidebar-width, --subnav-height converted from px to rem
  • DashboardLayout.tsx margin/padding/height calculations use rem-based values
  • Card padding converted to rem
  • Grid gaps converted to rem
  • Dashboard content area scales proportionally with root font-size
  • At 1080p, layout looks identical to current (no visual regression)
  • Typecheck passes
  • Verify in browser using dev-browser skill

US-003: Convert Fixed px to rem in Typography

Description: As a user on any screen size, I want text to scale with the viewport so it's always readable without zooming.

Acceptance Criteria:

  • All inline fontSize styles in tile components converted from px to rem (e.g., 13px0.8125rem based on 16px root, or equivalent relative to 15px base)
  • TopBar text sizes converted to rem
  • Sidebar text sizes converted to rem
  • Card header text sizes converted to rem
  • At 1080p, text sizes are visually identical to current
  • At 1440p, text is proportionally larger and readable
  • Typecheck passes
  • Verify in browser using dev-browser skill

US-004: Convert Fixed px to rem in Spacing & Components

Description: As a developer, I need padding, margins, icon sizes, and component dimensions to scale with viewport so the UI stays proportional.

Acceptance Criteria:

  • Inline padding/margin values in tiles converted from px to rem
  • Badge/tag padding and sizing converted to rem
  • Icon sizes (where set inline) use rem
  • Border-radius values may remain in px (they don't need to scale)
  • At 1080p, spacing is visually identical to current
  • Typecheck passes
  • Verify in browser using dev-browser skill

US-005: Mobile Sidebar Drawer

Description: As a mobile user, I want to access the sidebar content (person details, tags, alerts) via a slide-out drawer so I can see this information without it permanently taking screen space.

Acceptance Criteria:

  • TopBar shows a menu/hamburger icon on screens below lg breakpoint (1024px)
  • Tapping the icon opens the sidebar as a slide-out drawer overlay from the left
  • Drawer includes a semi-transparent backdrop that closes the drawer on tap
  • Drawer contains the full sidebar content (PersonHeader, Tags, Alerts)
  • Drawer can be closed via the backdrop tap, a close button, or pressing Escape
  • Drawer uses the same animation timing as existing UI (200ms ease-out)
  • Drawer respects prefers-reduced-motion (skip to final state)
  • Sidebar remains inline (non-drawer) on lg+ screens — no behavior change on desktop
  • Typecheck passes
  • Verify in browser using dev-browser skill

US-006: Fix Text Wrapping & Overflow

Description: As a mobile user, I want all text content to wrap properly within its containers so nothing is cut off or requires horizontal scrolling.

Acceptance Criteria:

  • No horizontal scrollbar appears at any viewport width (320px to 3840px)
  • All text in tile components wraps within its container — no off-screen overflow
  • Long skill names in CoreSkillsTile truncate with ellipsis rather than breaking layout
  • Career Activity entries wrap cleanly at narrow widths
  • PatientSummaryTile stats grid reflows to fewer columns on narrow screens
  • KPI cards in LatestResultsTile stack or reflow on mobile (no horizontal overflow)
  • Education entries wrap properly
  • Project entries wrap properly
  • overflow-x: hidden on the main content area as a safety net (not a primary fix — actual wrapping must work)
  • Typecheck passes
  • Verify in browser using dev-browser skill

US-007: Career Constellation Chart — Responsive Container Sizing

Description: As a user on any device, I want the D3 career constellation chart (CareerConstellation.tsx) to fit its container without overflowing, so the visualization is usable at all viewport widths.

Acceptance Criteria:

  • Chart SVG width/height derived from container dimensions (not hardcoded px)
  • Chart re-renders or resizes on viewport/container resize (via ResizeObserver or equivalent)
  • D3 force simulation parameters (charge strength, link distance, node spacing) adapt to available width
  • On mobile (<768px), chart remains visible and nodes don't overlap excessively or overflow
  • Node labels remain legible at small sizes (consider hiding secondary labels on narrow viewports)
  • Chart does not cause horizontal scrollbar at any viewport width
  • Typecheck passes
  • Verify in browser using dev-browser skill

US-008: Career Constellation Chart — Mobile Interaction

Description: As a mobile user, I want to interact with the career constellation chart using touch so I can explore roles and skills.

Acceptance Criteria:

  • Nodes are tappable on touch devices (adequate touch target size, minimum ~44px)
  • Tap on a role node triggers the same action as click (opens role detail)
  • Tap on a skill node triggers the same action as click (opens skill detail)
  • No hover-dependent information is inaccessible on touch (tooltips show on tap or info is always visible)
  • Chart doesn't conflict with page scroll (vertical scroll still works when touching the chart area)
  • Typecheck passes
  • Verify in browser using dev-browser skill

US-009: TopBar Mobile Refinements

Description: As a mobile user, I want the TopBar to remain functional and readable at narrow viewport widths.

Acceptance Criteria:

  • Hamburger/menu icon appears at the left of the TopBar below lg breakpoint
  • Brand text collapses gracefully (already mostly handled — verify no regression)
  • Search trigger remains accessible on mobile (either inline icon or within command palette trigger)
  • Session info collapses gracefully at narrow widths (already mostly handled — verify no regression)
  • TopBar height scales with rem (from US-002)
  • No horizontal overflow from TopBar content
  • Typecheck passes
  • Verify in browser using dev-browser skill

US-010: Verify at Key Viewport Sizes

Description: As a developer, I need to verify the dashboard renders correctly at representative viewport sizes to confirm no regressions.

Acceptance Criteria:

  • 375px wide (iPhone SE) — single column, drawer sidebar, all text wraps, no overflow
  • 768px wide (iPad portrait) — single column, drawer sidebar, comfortable spacing
  • 1024px wide (iPad landscape / small laptop) — sidebar inline, 2-column grid
  • 1920px wide (1080p) — visually identical to current production
  • 2560px wide (1440p) — ~25% scaled up, proportional layout, readable
  • Typecheck passes
  • Verify in browser using dev-browser skill

US-011: Re-enable Boot/Login Sequence

Description: As a user, I want the full boot → ECG → login experience restored for production.

Acceptance Criteria:

  • In App.tsx, initial Phase state reverted from 'pmr' back to 'boot'
  • Full boot → ECG → login → dashboard sequence works end to end
  • No other changes to App.tsx
  • Typecheck passes
  • Verify full sequence works via Playwright MCP

Functional Requirements

  • FR-1: Set html { font-size: clamp(...) } that scales from 15px at 1920px to ~22px at 3840px, floored at 15px below 1920px
  • FR-2: Convert all CSS custom properties used for layout dimensions (--topbar-height, --sidebar-width, --subnav-height) to rem units
  • FR-3: Convert all inline fontSize, padding, margin, and gap values in dashboard components from px to rem
  • FR-4: Add a mobile sidebar drawer component (slide-from-left overlay, backdrop, close on escape/backdrop-tap)
  • FR-5: Add a hamburger menu button to TopBar, visible below lg breakpoint, that toggles the sidebar drawer
  • FR-6: Apply overflow-wrap: break-word and appropriate min-width: 0 on flex/grid children to prevent text overflow
  • FR-7: Ensure overflow-x: hidden on the main scrollable content area as a catch-all
  • FR-8: Tile content must reflow (fewer grid columns, stacked layout) at narrow viewports rather than overflowing
  • FR-9: Career Constellation D3 chart must size to its container, re-render on resize, and adapt force simulation parameters for narrow viewports
  • FR-10: D3 chart nodes must have adequate touch targets (44px minimum) and not block page scroll on touch devices

Non-Goals

  • No permanent changes to Boot, ECG, or Login phases (temporarily skipped for dev, restored in final story)
  • No changes to the 1080p visual appearance (it's the baseline)
  • No changes to color palette, fonts, or design language
  • No new responsive breakpoints beyond what Tailwind already provides (xs/sm/md/lg/xl)
  • No container queries or component-level responsive logic — viewport scaling via root font-size is the mechanism
  • No changes to Command Palette responsive behavior (separate concern)
  • No touch gesture support (swipe to open sidebar, etc.)

Design Considerations

  • The sidebar drawer on mobile should visually match the existing sidebar styling — same background (#F7FAFA), same border, same content
  • The drawer should overlay content with a semi-transparent backdrop, similar to the existing detail panel pattern used for project/career detail expansion
  • The hamburger icon should use lucide-react (e.g., Menu icon) consistent with existing icon usage
  • Font-size scaling should be smooth (fluid), not stepped at breakpoints, to avoid jarring jumps during window resize

Technical Considerations

  • rem base calculation: Since the current design uses 15px as the body font-size, the rem conversion should be based on 15px = 1rem (set on html). At 1080p, 1rem = 15px. At 1440p, 1rem ≈ 18.75px.
  • Conversion formula: px / 15 = rem (e.g., 13px = 0.867rem, 48px = 3.2rem, 272px = 18.133rem)
  • Tailwind classes: Tailwind's spacing scale uses a 16px rem base by default. Since we're changing the html font-size, Tailwind rem-based classes (p-4, text-sm, etc.) will automatically scale. Only inline px styles need manual conversion.
  • CSS custom properties: Convert --topbar-height: 48px--topbar-height: 3.2rem, etc.
  • Sidebar drawer state: Managed via React state in DashboardLayout.tsx, passed down or via context. Keep it simple — useState<boolean> for open/closed.
  • Animations: Drawer slide uses transform: translateX(-100%)translateX(0) with 200ms ease-out, consistent with existing motion patterns.

Success Metrics

  • At 1440p, the dashboard is comfortably readable without browser zoom adjustments
  • On mobile (375px), all content is accessible, readable, and no horizontal scrolling occurs
  • Sidebar content is accessible on all screen sizes
  • No visual regression at 1080p
  • Zero horizontal overflow at any viewport width between 320px and 3840px

Open Questions

  • Should the mobile drawer have a swipe-to-close gesture? (Deferred as non-goal for now, can add later)
  • Should the search bar be accessible on mobile via a dedicated icon in TopBar? (Currently hidden below md — may want a small search icon)
  • At what viewport width should font scaling cap? (PRD suggests 3840px / ~22px — may need tuning)