From d365c38b61d6d0733e4998d7971f2e99e3fd01eb Mon Sep 17 00:00:00 2001 From: chihlasm Date: Sat, 7 Mar 2026 22:10:44 -0500 Subject: [PATCH] =?UTF-8?q?chore:=20Tailwind=20CSS=20v3=20=E2=86=92=20v4?= =?UTF-8?q?=20migration=20(#99)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: run Tailwind v4 upgrade tool (Phase 1) - Upgraded tailwindcss v3 → v4.2.1, postcss plugin to @tailwindcss/postcss - Deleted tailwind.config.js, migrated theme to CSS @theme block in index.css - Replaced @tailwind directives with @import 'tailwindcss' - Added @custom-variant dark, @utility blocks for custom utilities - Updated class names across 128 files (shadow-sm → shadow-xs, etc.) - Removed autoprefixer (built into v4) - Added migration plan doc Co-Authored-By: Claude Opus 4.6 * chore: switch from @tailwindcss/postcss to @tailwindcss/vite (Phase 2) - Replaced @tailwindcss/postcss with @tailwindcss/vite plugin - Deleted postcss.config.js (no longer needed) - Tailwind now runs as a native Vite plugin for faster HMR Co-Authored-By: Claude Opus 4.6 * refactor: convert to OKLCH colors, move keyframes into @theme (Phase 3-4) - Replaced all HSL color indirection with direct OKLCH values in @theme - Moved all keyframes inside @theme block (v4 pattern) - Eliminated hsl(var(--x)) double-indirection across 17 component files - Replaced hsl() inline styles with var(--color-*) theme references - Cleaned up redundant rdp-* utility blocks - Fixed @custom-variant dark syntax to use :where() - Added sidebar/glass/shadow vars as OKLCH in :root Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- docs/tailwind-v4-migration.md | 633 ++++++++ frontend/package-lock.json | 1433 +++++++---------- frontend/package.json | 4 +- frontend/postcss.config.js | 6 - .../src/components/account/AccountLayout.tsx | 2 +- .../components/account/DeleteAccountModal.tsx | 4 +- .../components/account/LeaveAccountModal.tsx | 2 +- .../account/TransferOwnershipModal.tsx | 8 +- frontend/src/components/admin/AdminLayout.tsx | 6 +- .../components/admin/CreateCategoryModal.tsx | 6 +- .../components/admin/EditCategoryModal.tsx | 6 +- frontend/src/components/admin/SearchInput.tsx | 2 +- .../analytics/FlowAnalyticsPanel.tsx | 16 +- .../src/components/assistant/ChatMessage.tsx | 4 +- .../src/components/assistant/ChatSidebar.tsx | 4 +- .../assistant/ConcludeSessionModal.tsx | 28 +- .../src/components/common/ContextMenu.tsx | 2 +- .../components/common/CreateFlowDropdown.tsx | 2 +- frontend/src/components/common/Modal.tsx | 10 +- frontend/src/components/common/TagInput.tsx | 2 +- .../src/components/copilot/CopilotPanel.tsx | 12 +- .../src/components/copilot/CopilotToggle.tsx | 2 +- .../src/components/dashboard/OpenSessions.tsx | 2 +- .../src/components/dashboard/QuickStats.tsx | 4 +- .../components/dashboard/SessionsPanel.tsx | 2 +- .../src/components/dashboard/TreeListItem.tsx | 4 +- .../components/dashboard/WeeklyCalendar.tsx | 4 +- .../components/editor-ai/AIPromptDialog.tsx | 8 +- frontend/src/components/editor-ai/ChatTab.tsx | 8 +- .../components/editor-ai/EditorAIPanel.tsx | 2 +- .../src/components/editor-ai/NodeSummary.tsx | 4 +- .../components/editor-ai/SuggestionsTab.tsx | 4 +- frontend/src/components/guides/GuideCard.tsx | 2 +- frontend/src/components/layout/AppLayout.tsx | 12 +- .../src/components/layout/CommandPalette.tsx | 6 +- .../layout/EmailVerificationBanner.tsx | 2 +- frontend/src/components/layout/NavItem.tsx | 14 +- .../src/components/layout/QuickLaunch.tsx | 4 +- frontend/src/components/layout/Sidebar.tsx | 2 +- .../components/library/AddToFolderMenu.tsx | 2 +- .../components/library/FolderEditModal.tsx | 6 +- .../src/components/library/FolderSidebar.tsx | 6 +- frontend/src/components/library/ForkModal.tsx | 4 +- .../components/library/ImportFlowModal.tsx | 4 +- .../src/components/library/ShareTreeModal.tsx | 4 +- .../src/components/library/SortDropdown.tsx | 2 +- .../src/components/library/TreeListView.tsx | 12 +- .../src/components/library/TreeTableView.tsx | 8 +- .../maintenance/BatchLaunchModal.tsx | 4 +- .../maintenance/BatchStatusCard.tsx | 2 +- .../procedural-editor/IntakeFieldEditor.tsx | 16 +- .../procedural-editor/IntakeFormBuilder.tsx | 2 +- .../MaintenanceScheduleSection.tsx | 10 +- .../procedural-editor/StepEditor.tsx | 22 +- .../components/procedural-editor/StepList.tsx | 4 +- .../components/procedural/IntakeFormModal.tsx | 4 +- .../src/components/procedural/StepDetail.tsx | 8 +- frontend/src/components/session/CSATModal.tsx | 2 +- .../components/session/ContinuationModal.tsx | 8 +- .../components/session/ExportPreviewModal.tsx | 6 +- .../src/components/session/ForkTreeModal.tsx | 6 +- .../session/SaveSessionAsTreeModal.tsx | 6 +- .../components/session/ScratchpadSidebar.tsx | 4 +- .../src/components/session/SessionFilters.tsx | 6 +- .../session/SessionOutcomeModal.tsx | 4 +- .../components/session/SessionTimeline.tsx | 2 +- .../components/session/ShareSessionModal.tsx | 8 +- .../session/SharedSessionTreePreview.tsx | 2 +- .../components/session/StepRatingModal.tsx | 4 +- .../session/VariablePromptModal.tsx | 4 +- .../src/components/sidebar/CategoryList.tsx | 8 +- .../components/sidebar/PinnedFlowsSection.tsx | 4 +- .../step-library/CustomStepModal.tsx | 4 +- .../step-library/StepDetailModal.tsx | 2 +- .../src/components/step-library/StepForm.tsx | 12 +- .../components/step-library/StepFormModal.tsx | 2 +- .../step-library/StepLibraryBrowser.tsx | 10 +- .../tree-editor/AIFixReviewModal.tsx | 4 +- .../src/components/tree-editor/FlowCanvas.tsx | 6 +- .../tree-editor/FlowCanvasAnswerNode.tsx | 4 +- .../components/tree-editor/FlowCanvasNode.tsx | 8 +- .../tree-editor/MetadataSidePanel.tsx | 2 +- .../components/tree-editor/NodeFormAction.tsx | 10 +- .../tree-editor/NodeFormDecision.tsx | 6 +- .../tree-editor/NodeFormResolution.tsx | 6 +- .../src/components/tree-editor/NodeList.tsx | 4 +- .../src/components/tree-editor/NodePicker.tsx | 4 +- .../src/components/tree-editor/TreeCanvas.tsx | 4 +- .../components/tree-editor/TreeCanvasNode.tsx | 2 +- .../tree-editor/TreeMetadataForm.tsx | 8 +- .../tree-editor/ValidationSummary.tsx | 6 +- .../components/tree-editor/useTreeLayout.ts | 14 +- .../tree-preview/TreePreviewNode.tsx | 2 +- frontend/src/components/ui/Button.tsx | 6 +- frontend/src/components/ui/Input.tsx | 2 +- frontend/src/components/ui/Skeleton.tsx | 2 +- frontend/src/components/ui/Textarea.tsx | 2 +- frontend/src/index.css | 618 ++++--- frontend/src/pages/AccountSettingsPage.tsx | 10 +- frontend/src/pages/AssistantChatPage.tsx | 8 +- frontend/src/pages/ChangePasswordPage.tsx | 8 +- frontend/src/pages/FeedbackPage.tsx | 6 +- frontend/src/pages/ForgotPasswordPage.tsx | 4 +- frontend/src/pages/GuideDetailPage.tsx | 6 +- frontend/src/pages/LoginPage.tsx | 8 +- frontend/src/pages/MyAnalyticsPage.tsx | 18 +- frontend/src/pages/MyTreesPage.tsx | 2 +- frontend/src/pages/ProceduralEditorPage.tsx | 4 +- .../src/pages/ProceduralNavigationPage.tsx | 4 +- frontend/src/pages/QuickStartPage.tsx | 12 +- frontend/src/pages/RegisterPage.tsx | 12 +- frontend/src/pages/ResetPasswordPage.tsx | 6 +- frontend/src/pages/SessionDetailPage.tsx | 6 +- frontend/src/pages/StepLibraryPage.tsx | 2 +- frontend/src/pages/SurveyPage.tsx | 36 +- frontend/src/pages/SurveyThankYouPage.tsx | 2 +- frontend/src/pages/TeamAnalyticsPage.tsx | 16 +- frontend/src/pages/TreeEditorPage.tsx | 4 +- frontend/src/pages/TreeLibraryPage.tsx | 4 +- frontend/src/pages/TreeNavigationPage.tsx | 16 +- frontend/src/pages/VerifyEmailPage.tsx | 4 +- .../account/ChatRetentionSettingsPage.tsx | 10 +- .../src/pages/account/ProfileSettingsPage.tsx | 8 +- .../src/pages/account/TargetListsPage.tsx | 6 +- .../src/pages/account/TeamCategoriesPage.tsx | 2 +- frontend/src/pages/admin/AuditLogsPage.tsx | 4 +- frontend/src/pages/admin/FeatureFlagsPage.tsx | 2 +- .../src/pages/admin/GlobalCategoriesPage.tsx | 2 +- frontend/src/pages/admin/InviteCodesPage.tsx | 2 +- frontend/src/pages/admin/PlanLimitsPage.tsx | 2 +- frontend/src/pages/admin/SettingsPage.tsx | 2 +- .../src/pages/admin/SurveyInvitesPage.tsx | 30 +- .../src/pages/admin/SurveyResponsesPage.tsx | 36 +- frontend/src/pages/admin/UserDetailPage.tsx | 2 +- frontend/src/pages/admin/UsersPage.tsx | 20 +- frontend/tailwind.config.js | 81 - frontend/vite.config.ts | 2 + 137 files changed, 1922 insertions(+), 1709 deletions(-) create mode 100644 docs/tailwind-v4-migration.md delete mode 100644 frontend/postcss.config.js delete mode 100644 frontend/tailwind.config.js diff --git a/docs/tailwind-v4-migration.md b/docs/tailwind-v4-migration.md new file mode 100644 index 00000000..2b14ea2d --- /dev/null +++ b/docs/tailwind-v4-migration.md @@ -0,0 +1,633 @@ +# ResolutionFlow — Tailwind v4 Migration & Feature Guide +**Claude Code Handoff Document · Pre-Investor Pitch Sprint** + +--- + +## Purpose + +This document gives Claude Code everything needed to: +1. Execute the mechanical Tailwind v3 → v4 upgrade +2. Know which new v4 features to use going forward so the ResolutionFlow UI looks and feels premium for the investor pitch demo + +## Branch + +This migration touches nearly every file in the frontend. **Always work on a dedicated branch:** + +```bash +git checkout -b feat/tailwind-v4-upgrade +``` + +Do not merge to `main` until all phases are complete and the full visual QA pass is done. + +--- + +## Stack Context + +| | | +|---|---| +| Frontend | React 19.2 + Vite 7 + TypeScript 5.9 | +| Current Tailwind | v3.4.19 | +| Component Library | shadcn/ui (target: new-york style post-upgrade) | +| Canvas Editor | React Flow (@xyflow/react) | +| Brand Color | Cyan — `#06b6d4 → #22d3ee` (hsl 187 72% 43%) | +| Background | `hsl(228 12% 7%)` — dark theme only, no light mode | +| Body Font | IBM Plex Sans | +| Heading Font | Bricolage Grotesque | +| Label/Mono Font | JetBrains Mono | +| Brand Gradient | `linear-gradient(135deg, #06b6d4 0%, #22d3ee 100%)` | +| Animation Library | tailwindcss-animate → **replace with tw-animate-css** | +| Tailwind Plugins | None | + +--- + +--- + +# PART 1: Mechanical Migration + +Execute phases in order. Verify the app builds and renders correctly after each phase before proceeding. + +--- + +## Phase 1 — Update Dependencies + +Run the official Tailwind upgrade tool from the `/frontend` directory. It handles the majority of migration automatically: + +```bash +# Run from /frontend +npx @tailwindcss/upgrade@latest +``` + +This tool will: +- Update `tailwindcss` to v4 +- Install `@tailwindcss/vite` (replaces the PostCSS plugin) +- Migrate `tailwind.config.js` → CSS `@theme` block +- Update `@tailwind` directives to `@import` +- Handle renamed utility classes in template files + +After running, verify `package.json` reflects: + +```json +// devDependencies should now include: +"tailwindcss": "^4.x.x", +"@tailwindcss/vite": "^4.x.x" + +// These are no longer needed and can be removed: +// "autoprefixer" (bundled in v4 via Lightning CSS) +// "postcss" (unless used for something other than Tailwind) +``` + +--- + +## Phase 2 — Update Vite Config + +Replace the PostCSS-based Tailwind setup with the first-party Vite plugin: + +```ts +// vite.config.ts — BEFORE +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], +}) + +// vite.config.ts — AFTER +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) +``` + +Remove `postcss.config.js` if it exists and was only used for Tailwind. Lightning CSS is now bundled inside Tailwind v4. + +--- + +## Phase 3 — Migrate CSS Entry Point + +Update `index.css`: + +```css +/* BEFORE — v3 directives */ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* AFTER — v4 single import */ +@import "tailwindcss"; +@import "tw-animate-css"; + +/* ResolutionFlow is dark-only. Replace darkMode: ["class"] from tailwind.config.js + with this custom variant declaration. This is the v4 equivalent. */ +@custom-variant dark (&:where(.dark, .dark *)); + +/* React Flow styles must now live in CSS, not imported in App.tsx */ +@layer base { + @import "@xyflow/react/dist/style.css"; +} +``` + +> **Important:** Remove `import '@xyflow/react/dist/style.css'` from `App.tsx` after adding it here. +> **Important:** Remove `darkMode: ["class"]` from `tailwind.config.js` — it is now handled by `@custom-variant dark` above. Since ResolutionFlow is dark-only with no light mode toggle, verify that the `.dark` class is still present on the `` element in `index.html`. + +--- + +## Phase 4 — Migrate Theme Configuration + +The upgrade tool migrates `tailwind.config.js` automatically, but verify the ResolutionFlow design tokens are correctly expressed. The `@theme` block lives in `index.css` after the imports. + +### OKLCH Color Values + +Claude Code flagged that the cyan range benefits from OKLCH for better gradient interpolation. Use these OKLCH equivalents for brand colors inside `@theme` — they render more accurately on wide-gamut displays (MacBooks, modern monitors used in pitch settings): + +| Hex | OKLCH | +|---|---| +| `#06b6d4` (brand-from) | `oklch(72% 0.15 195)` | +| `#22d3ee` (brand-to) | `oklch(82% 0.13 195)` | +| `#0891b2` (brand-dark) | `oklch(62% 0.14 195)` | + +### Full `@theme` Block + +```css +@import "tailwindcss"; +@import "tw-animate-css"; + +@custom-variant dark (&:where(.dark, .dark *)); + +@theme { + /* ResolutionFlow Brand — Cyan system (OKLCH for wide-gamut accuracy) */ + --color-brand-from: oklch(72% 0.15 195); /* #06b6d4 */ + --color-brand-to: oklch(82% 0.13 195); /* #22d3ee */ + --color-brand-dark: oklch(62% 0.14 195); /* #0891b2 */ + + /* Dark surface palette */ + --color-dark-DEFAULT: #101114; + --color-dark-card: #14161a; + --color-dark-surface: #14161a; + + /* Text palette */ + --color-text-primary: #f8fafc; + --color-text-secondary: #8891a0; + --color-text-muted: #5a6170; + + /* Typography */ + --font-sans: 'IBM Plex Sans', system-ui, -apple-system, sans-serif; + --font-heading: 'Bricolage Grotesque', system-ui, sans-serif; + --font-label: 'JetBrains Mono', monospace; + + /* Border radius */ + --radius-lg: 0.75rem; + --radius-md: calc(0.75rem - 2px); + --radius-sm: calc(0.75rem - 4px); + + /* Keyframe animations — move ALL @keyframes from index.css into @theme */ + --animate-fade-in: fade-in 200ms ease-out; + --animate-fade-in-up: fade-in-up 200ms ease-out; + --animate-slide-in-left: slide-in-from-left 200ms ease-out; + --animate-slide-in-bottom: slide-in-from-bottom 200ms ease-out; + --animate-scale-in: scale-in 150ms ease-out; + --animate-breathe-glow: breatheGlow 3s ease-in-out infinite alternate; + --animate-bell-wobble: bellWobble 0.5s ease-in-out; + + @keyframes fade-in { + from { opacity: 0; } + to { opacity: 1; } + } + @keyframes fade-in-up { + from { opacity: 0; transform: translateY(4px); } + to { opacity: 1; transform: translateY(0); } + } + @keyframes slide-in-from-left { + from { transform: translateX(-100%); } + to { transform: translateX(0); } + } + @keyframes slide-in-from-bottom { + from { opacity: 0; transform: translateY(16px); } + to { opacity: 1; transform: translateY(0); } + } + @keyframes scale-in { + from { opacity: 0; transform: scale(0.95); } + to { opacity: 1; transform: scale(1); } + } + @keyframes breatheGlow { + from { box-shadow: 0 8px 32px rgba(0,0,0,0.3), 0 0 20px oklch(72% 0.15 195 / 0.04); } + to { box-shadow: 0 8px 32px rgba(0,0,0,0.3), 0 0 30px oklch(72% 0.15 195 / 0.12); } + } + @keyframes bellWobble { + 0% { transform: rotate(0deg); } + 20% { transform: rotate(8deg); } + 40% { transform: rotate(-6deg); } + 60% { transform: rotate(4deg); } + 80% { transform: rotate(-2deg); } + 100% { transform: rotate(0deg); } + } +} +``` + +> **Important:** Remove the loose `@keyframes` blocks from `index.css` after moving them into `@theme`. They should not exist in both places. + +### shadcn/ui CSS Variable Bridge + +Keep the existing `:root` block as-is — shadcn still uses HSL format for its variables: + +```css +/* shadcn/ui CSS variable bridge — keep as-is from existing index.css */ +@layer base { + :root { + --background: 228 12% 7%; + --foreground: 210 40% 98%; + --card: 220 10% 10%; + --card-foreground: 210 40% 98%; + --popover: 220 10% 10%; + --popover-foreground: 210 40% 98%; + --primary: 187 72% 43%; + --primary-foreground: 228 12% 7%; + --secondary: 220 8% 14%; + --secondary-foreground: 210 40% 98%; + --muted: 220 8% 14%; + --muted-foreground: 215 10% 58%; + --accent: 220 8% 14%; + --accent-foreground: 210 40% 98%; + --destructive: 350 81% 55%; + --destructive-foreground: 210 40% 98%; + --border: 220 8% 14%; + --input: 220 8% 14%; + --ring: 187 72% 43%; + --radius: 0.75rem; + /* ... rest of existing tokens ... */ + } +} + +--- + +## Phase 5 — Replace Animation Library + +```bash +# Remove old plugin +npm uninstall tailwindcss-animate + +# Install replacement +npm install -D tw-animate-css +``` + +Remove any `@plugin 'tailwindcss-animate'` references from CSS files. The `@import "tw-animate-css"` added in Phase 3 replaces it. + +--- + +## Phase 7 — Consolidate Hardcoded Inline Colors + +Claude Code identified **128 instances of `style={{}}` inline color values across 44 files**, including atmosphere orbs in `AppLayout.tsx` using hardcoded `rgba(6,182,212,...)`. Now that brand colors are proper CSS variables in `@theme`, replace all hardcoded cyan/brand references with variables. + +**Search and replace targets:** + +```ts +// FIND these hardcoded patterns: +rgba(6, 182, 212, ...) // brand-from with opacity +rgba(34, 211, 238, ...) // brand-to with opacity +#06b6d4 // brand-from hex +#22d3ee // brand-to hex +#0891b2 // brand-dark hex + +// REPLACE with CSS variable equivalents: +oklch(72% 0.15 195 / 0.XX) // brand-from with opacity (XX = your alpha) +oklch(82% 0.13 195 / 0.XX) // brand-to with opacity +var(--color-brand-from) // brand-from solid +var(--color-brand-to) // brand-to solid +var(--color-brand-dark) // brand-dark solid +``` + +**Specifically in `AppLayout.tsx`** — atmosphere orbs should become: + +```tsx +// BEFORE +style={{ background: 'rgba(6, 182, 212, 0.08)' }} + +// AFTER — references the theme token, respects any future brand color changes +style={{ background: 'oklch(72% 0.15 195 / 0.08)' }} + +// Or better yet, move to a CSS utility class entirely: +// .atmosphere-orb { background: oklch(72% 0.15 195 / 0.08); } +``` + +> This is the right time to do this cleanup — the theme is already being touched, and it means future brand color changes only require updating `@theme` instead of hunting through 44 files. + +--- + +## Phase 8 — Reinstall shadcn/ui Components + +shadcn/ui components have been updated for Tailwind v4 and React 19. Commit any custom component modifications first, then reinstall to get refreshed versions. + +```bash +# Re-initialize with v4 defaults +npx shadcn@latest init + +# When prompted: +# Style: new-york (more refined than 'default') +# Base color: cyan (matches ResolutionFlow brand) + +# Reinstall actively used components: +npx shadcn@latest add button card dialog dropdown-menu +npx shadcn@latest add badge input label select textarea +npx shadcn@latest add table tabs tooltip separator +npx shadcn@latest add sheet command popover +``` + +**What's new in shadcn v4 components:** +- `forwardRef` removed from all components (React 19 handles ref natively) +- `data-slot` attributes added for easier CSS targeting +- HSL colors converted to OKLCH for wider color gamut +- Dark mode colors revisited for better accessibility +- `tailwindcss-animate` deprecated in favor of `tw-animate-css` + +--- + +## Phase 9 — Visual QA Checklist + +Work through the app after Phases 1–6. These are the most likely regression areas: + +- [ ] **Borders** — default border color changed from `gray-200` to `currentColor`. Check all card, table, and input borders against the `hsl(var(--border))` token. +- [ ] **Focus rings** — default ring changed from `3px blue` to `1px currentColor`. Verify form fields and button focus states look intentional. +- [ ] **Placeholder text** — changed from `gray-400` to `currentColor` at 50% opacity. Check all inputs. +- [ ] **Button cursors** — now `cursor:default` (browser standard). Add `cursor-pointer` explicitly where desired. +- [ ] **React Flow canvas** — verify nodes, handles, edges, and controls render correctly with CSS import moved to `@layer base`. +- [ ] **Animations** — check dialog open/close, sheet slide, dropdown appear animations after the animation library swap. +- [ ] **Keyframe animations** — verify `breatheGlow` on stat cards, `bellWobble` on notification bell, and all `fade-in-*` utilities still work after moving keyframes into `@theme`. +- [ ] **Cyan brand gradient** — verify `bg-gradient-brand` still renders correctly. Check it looks at least as good (ideally better) with OKLCH values. +- [ ] **Atmosphere orbs** — verify `AppLayout.tsx` orbs render correctly after inline style replacement with OKLCH variables. +- [ ] **Glass morphism** — verify `.glass-card` and `.glass-card-static` backdrop blur still applies on all surfaces. +- [ ] **JetBrains Mono** — verify label/code elements still use mono font correctly. +- [ ] **Sonner toasts** — verify custom toast styling (card bg, border, icon colors) still applies. +- [ ] **Dark variant** — verify `.dark` class on `` is present and the `@custom-variant dark` replacement behaves identically to the old `darkMode: ["class"]` config. + +--- + +## Commit Strategy + +```bash +git checkout -b feat/tailwind-v4-upgrade + +git commit -m "chore: upgrade Tailwind v3 → v4, update Vite plugin" +git commit -m "chore: migrate CSS entry point — @import, @custom-variant dark" +git commit -m "chore: migrate theme to @theme block — OKLCH colors, keyframes" +git commit -m "chore: swap tailwindcss-animate for tw-animate-css" +git commit -m "chore: consolidate 128 hardcoded inline colors to CSS variables" +git commit -m "chore: reinstall shadcn/ui components for v4 (new-york style, cyan)" +git commit -m "fix: visual QA pass — borders, rings, placeholders, glass, animations" +git commit -m "feat: apply v4 feature enhancements across components" + +# When complete and QA passes: +git checkout main +git merge feat/tailwind-v4-upgrade +``` + +--- + +--- + +# PART 2: Tailwind v4 Feature Guide + +**These are new capabilities available after the upgrade. Apply them proactively when building or modifying components — do not default to v3 patterns when a v4 equivalent is listed here.** + +--- + +## Feature 1 — Auto-Resizing Textareas (`field-sizing-content`) + +Apply to every multi-line text input in the app. Engineers typing session notes and documentation should never fight a fixed-height box. + +**Where to apply:** Session runner documentation field · step notes input · FlowPilot prompt input · any multi-line input in the flow editor + +```tsx +// BEFORE — v3, fixed height or JS resize logic +