# Project Research Summary **Project:** Ready2Blob v1.2 -- UI Polish & MD3 Overhaul **Domain:** Material Design 3 theming layer on existing React + Tailwind v4 wizard app **Researched:** 2026-03-31 **Confidence:** HIGH ## Executive Summary Ready2Blob v1.2 is a pure styling and UX content overhaul of an already-functional 4-step rclone configuration wizard. The existing stack (Vite 6, React 18, TypeScript 5, Tailwind v4, react-hook-form 7, Zod 4, 159 passing tests) is solid and does not need architectural changes. The research unanimously recommends a **zero new runtime dependencies** approach: define Material Design 3 color tokens as CSS custom properties, wire them into Tailwind v4's native `@theme` directive, and build a small set of reusable UI primitives (Button, Input, Card, Select) that replace the current scattered inline markup. The only new dependency is `@material/material-color-utilities` as a dev-only tool for generating MD3 color palettes from a seed color -- it never ships to the browser. The recommended approach is a bottom-up, layer-by-layer migration. First establish the CSS token foundation and dark mode infrastructure (zero component changes, zero test impact). Then extract UI primitives as new additive components. Then swap existing hardcoded colors for semantic tokens one component at a time, running all 159 tests after each change. This ordering is critical because the token system is the foundation for everything else -- dark mode, accent colors, MD3 components, and responsive improvements all depend on it. Content improvements (app intro, step descriptions, remote name clarity) are independent and can be parallelized. The primary risks are: breaking the 131 test selectors across 5 UI test files during component restyling, dark mode contrast failures (WCAG AA), and flash of unstyled content on dark mode load. All three are preventable with the disciplined layer-by-layer approach. The most dangerous anti-pattern is a big-bang restyle where all components are changed at once -- this makes test failures impossible to isolate and virtually guarantees regressions. ## Key Findings ### Recommended Stack Zero new runtime dependencies. The existing Tailwind v4 handles all styling needs through its CSS-first `@theme` directive and `@custom-variant` for dark mode. One dev dependency added: `@material/material-color-utilities` (v0.4.0) to generate MD3 palettes at build time via a Node script. The output is static CSS custom properties -- zero bundle impact. **Core technologies (all existing, no changes):** - **Tailwind v4 `@theme`**: Maps MD3 tokens to utility classes (`bg-surface`, `text-on-primary`) -- native, no plugins - **Tailwind v4 `@custom-variant dark`**: Class-based dark mode toggle replacing the removed `darkMode: 'class'` config - **CSS custom properties**: ~20 semantic MD3 color roles, elevation shadows, shape radii, motion tokens **New dev dependency only:** - **`@material/material-color-utilities` 0.4.0**: Official Google library, generates full MD3 palette from a single seed hex color. Used by a build script (`scripts/generate-theme.ts`) that outputs `src/theme-tokens.css`. NOT bundled. **Explicitly rejected:** MUI, Material Tailwind, shadcn/ui, CSS-in-JS, next-themes, framer-motion, PostCSS plugins, tailwind.config.js, runtime color generation. See STACK.md for detailed rationale on each. ### Expected Features **Must have (table stakes -- P1):** - MD3 color token system (CSS custom properties for all color roles) - MD3 text fields (outlined variant with floating labels) - MD3 button hierarchy (filled, outlined, text) - MD3 card components with elevation - Dark mode toggle (system/light/dark, localStorage persistence) - MD3 step indicator (numbered circles, connecting lines, state indicators) - Responsive layout (mobile-friendly grids, collapsible step indicator) - App intro/landing section explaining what Ready2Blob does - Step-level descriptions on each wizard step - Remote name field clarity (prominent explanation, examples) - Accessible focus states (focus-visible, 3px outline) - Tech debt: FieldRenderer aria fix, StepIndicator inline style migration **Should have (differentiators -- P2, add after core is stable):** - User-selectable accent color (5-8 curated presets) - Animated step transitions (CSS fade/slide, 200ms) - Upgraded contextual help popovers - Scroll-to-error on validation failure **Defer (v2+):** - Custom MD3 select/dropdown (HIGH complexity for 2-3 selects) - Code syntax highlighting in review step - Arbitrary user hex color theming ### Architecture Approach A CSS custom properties layer bridges MD3 tokens with Tailwind v4. A thin `ThemeToggle` component manages the `.dark` class on `` via direct DOM manipulation -- NOT via React Context, to avoid re-rendering the entire wizard tree on toggle. Components are refactored bottom-up: primitives first (Button, Input, Card, Select), then composed components (FieldRenderer, BackendCard), then layout (AppShell, StepIndicator). The critical architectural insight is that theme state belongs in CSS (class on `` + custom properties), not in React state. **Major components:** 1. **CSS Token Layer** (`index.css` + `theme-tokens.css`) -- MD3 color roles, elevation, shape, motion as `@theme` values 2. **UI Primitives** (`ui/Button`, `ui/Input`, `ui/Select`, `ui/Card`) -- MD3-styled presentational components using `forwardRef` for react-hook-form compatibility 3. **ThemeToggle** -- standalone component, local state only, toggles `.dark` class on `` 4. **AppShell** -- layout wrapper extracted from current WizardShell, houses ThemeToggle 5. **Modified existing components** -- FieldRenderer, BackendCard, PasswordField, all wizard steps -- swap hardcoded colors for semantic tokens ### Critical Pitfalls 1. **Tailwind v4 dark mode misconfiguration** -- v3 `darkMode: 'class'` does not exist. Must use `@custom-variant dark (&:where(.dark, .dark *))` in CSS. Address in Phase 1 before any `dark:` classes are added. 2. **73 hardcoded color classes** -- Adding `dark:` counterparts to each creates unmaintainable 100+ char classNames. Instead, replace all with semantic tokens (`bg-surface`, `text-on-surface`) that swap values automatically via CSS variable override. 3. **Breaking 131 test selectors** -- Restyling touches the same JSX that tests query. Must restyle one component at a time, running all 159 tests after each. Never batch-restyle. 4. **FOUC on dark mode load** -- React applies `.dark` class after first paint. Add a synchronous inline `