# Progress Log — Login Screen Rework # Branch: ralph/login-screen-rework # Started: 2026-02-15 ## Codebase Patterns ### Project Structure - Components in `src/components/`, tiles in `src/components/tiles/` - Data files in `src/data/` - Types in `src/types/pmr.ts` and `src/types/index.ts` - Hooks in `src/hooks/`, Contexts in `src/contexts/`, Lib in `src/lib/` - Path alias: `@/` maps to `./src/` ### Phase Management - App.tsx controls phase: 'boot' -> 'ecg' -> 'login' -> 'pmr' - BootSequence.tsx, ECGAnimation.tsx — LOCKED, do not modify - LoginScreen.tsx bridges to dashboard ### Typography - Elvaro Grotesque (`font-ui`, `var(--font-ui)`) — primary UI font - Blumir (`font-ui-alt`) — alternative variable font - Geist Mono (`font-geist`, `var(--font-geist-mono)`) — timestamps, data values - Fira Code (`font-mono`) — boot/ECG terminal only - Do NOT use Inter, Roboto, DM Sans, or system defaults ### Design Tokens (index.css CSS variables) - --surface: #FFFFFF (card/topbar background) - --bg-dashboard: #F0F5F4 (warm sage content background) - --accent: #0D6E6E (teal primary) - --accent-hover: #0A8080 - --accent-light: rgba(10,128,128,0.08) - --border: #D4E0DE (structural borders) - --border-card: #E4EDEB (card/inner borders) - --text-primary: #1A2B2A - --text-secondary: #5B7A78 - --text-tertiary: #8DA8A5 - --sidebar-width: 304px - --topbar-height: 56px ### Known Dependencies - React 18.3.1, TypeScript, Vite, Tailwind CSS - Framer Motion 11.15.0, Lucide React 0.468.0, fuse.js 7.0.0 ### Phase Rendering (post US-006) - Login phase now renders BOTH DashboardLayout and LoginScreen overlay simultaneously - DashboardLayout is wrapped in DetailPanelProvider for both 'login' and 'pmr' phases - LoginScreen overlay: `fixed inset-0 z-50` with `rgba(240, 245, 244, 0.7)` + `backdrop-filter: blur(20px)` ### Key Files for This Feature - src/App.tsx — phase management, will need restructuring for blur overlay - src/components/LoginScreen.tsx — main login screen (416 lines) - src/components/TopBar.tsx — Home icon replacement target (line 57) - src/components/DashboardLayout.tsx — rendered behind login blur - src/contexts/DetailPanelContext.tsx — wraps DashboardLayout - cvmis-logo.svg — source SVG with 3 capsule groups - LogoReveal/frame 1-5.jpg — animation reference frames ### CvmisLogo Component - `size` prop: numeric, sets SVG height attribute directly - `cssHeight` prop: string, sets height via CSS style (use for clamp/responsive values) - `animated` prop: boolean, enables framer-motion reveal animation (1000ms total) - Logo animation: 500ms rise (green capsule) + 500ms fan-out (all three) = 1000ms total ### LoginScreen.tsx Key Lines (post US-004) - Line 20: connectionState useState - Line 43: canLogin derived state - Line 60-101: startLoginSequence (typing animation) - Line 110-139: useEffect with connectionTimeout (2000ms) and startLoginSequence delay (1500ms / 400ms reduced motion) - Line 145-409: JSX render (card, form, button, status indicator) - Line 208-211: CvmisLogo with cssHeight="clamp(48px, 4vw, 64px)" animated=true - Line 221: "CVMIS" title - Line 232: "CV Management Information System" subtitle - Line 350-382: Connection status indicator (6px dot, 10px text) --- ## 2026-02-15 - US-006 - Rendered DashboardLayout (wrapped in DetailPanelProvider) behind LoginScreen during login phase in App.tsx - Changed LoginScreen overlay from solid #1A2B2A background to semi-transparent rgba(240, 245, 244, 0.7) with backdrop-filter: blur(20px) - Dashboard is non-interactive during login (overlay captures pointer events via fixed inset-0 z-50) - After login click, phase transitions to 'pmr' and overlay is removed from DOM, dashboard becomes interactive - Files changed: src/App.tsx, src/components/LoginScreen.tsx - Verified in browser: blur overlay shows dashboard content behind login card, login click transitions to interactive dashboard - **Learnings for future iterations:** - App.tsx phase rendering changed from exclusive (one phase at a time) to overlapping (login + pmr render DashboardLayout) - DetailPanelProvider now wraps DashboardLayout for both 'login' and 'pmr' phases — condition is `(phase === 'login' || phase === 'pmr')` - LoginScreen already had `fixed inset-0 z-50` which makes it a full-viewport overlay — just needed background/blur changes - WebkitBackdropFilter needed for Safari compatibility alongside backdropFilter --- ## 2026-02-15 - US-005 - Replaced Home icon with CvmisLogo (size={24}, static/no animation) in TopBar.tsx - Removed Home from lucide-react import (Search still used) - Imported CvmisLogo component - Files changed: src/components/TopBar.tsx - Verified in browser: logo renders correctly with teal/amber/green capsule colors, fits TopBar height - **Learnings for future iterations:** - TopBar uses inline styles throughout, consistent with LoginScreen pattern - Search is the only remaining lucide-react icon in TopBar.tsx - CvmisLogo default `animated=false` means no animation prop needed for static usage --- ## 2026-02-15 - US-004 - Rebranded login from "CareerRecord PMR" to "CVMIS" with subtitle "CV Management Information System" - Replaced Shield icon with CvmisLogo component (animated=true, responsive cssHeight) - Added `cssHeight` prop to CvmisLogo for CSS clamp-based responsive sizing: clamp(48px, 4vw, 64px) - Increased startLoginSequence delay from 400ms to 1500ms to let logo animation complete before typing begins - prefers-reduced-motion: keeps original 400ms delay since logo renders instantly - Fixed lint warning: added prefersReducedMotion to useEffect dependency array - Files changed: src/components/LoginScreen.tsx, src/components/CvmisLogo.tsx - **Learnings for future iterations:** - CvmisLogo `size` prop is numeric (SVG height attribute) — use `cssHeight` string prop for CSS clamp values - Logo animation is 1000ms total (500ms rise + 500ms fan-out) — typing delay must account for this - The committed LoginScreen from US-003 still had Shield icon — US-003 only committed responsive sizing, not branding changes --- ## 2026-02-15 - US-003 - Responsive card: width clamp(320px,28vw,480px), maxWidth calc(100vw-32px), padding clamp(24px,2.5vw,40px) - Replaced hardcoded colors with CSS variables: --surface, --bg-dashboard, --accent, --text-secondary, --text-tertiary - Input fields: #E4EDEB default border, var(--accent) focus border, var(--bg-dashboard) inactive bg - Font sizes: labels clamp(12px,1vw,14px), inputs clamp(13px,1.1vw,15px), button clamp(14px,1.1vw,16px) - Card shadow: 0 1px 2px rgba(26,43,42,0.05) matching project shadow tokens - Files changed: src/components/LoginScreen.tsx - **Learnings for future iterations:** - No --border-card CSS variable exists in index.css — use #E4EDEB directly - LoginScreen uses inline styles throughout, not Tailwind classes (except for focus-visible ring on button) - The card used className="bg-white" which needed to be replaced with inline style for consistency --- ## 2026-02-15 - US-002 - Created CvmisLogo.tsx component with inlined SVG paths from cvmis-logo.svg - Three capsule groups: capsule-rx (teal #0b7979), capsule-terminal (amber #d97706), capsule-data (green #059669) - Props: size (height px), animated (boolean, default false), className (optional) - Framer Motion animation: Phase 1 (rise 500ms) — green data capsule scales from 0, Phase 2 (fan-out 500ms) — all three appear - prefers-reduced-motion: skips animation, renders final state immediately - Files changed: src/components/CvmisLogo.tsx (new) - **Learnings for future iterations:** - The SVG uses viewBox="0 0 600 506" with internal g transform scale(0.05,-0.05) — keep this coordinate system intact - framer-motion's useReducedMotion() hook is the simplest way to handle reduced motion - transform-origin in SVG needs px units when using framer-motion on g elements --- ## 2026-02-15 - US-001 - Changed initial Phase state from 'boot' to 'login' in App.tsx line 47 - Files changed: src/App.tsx - **Learnings for future iterations:** - Phase state is a simple string union type on line 47 of App.tsx - US-010 will revert this exact change back to 'boot' ---