# App.css reduction plan This document tracks the work to retire the legacy `frontend/src/App.css` in favour of the redesign's design tokens (`styles/design.css`), shared utilities (`styles/page-shared.css`, `styles/clip-grid.css`), and per-page CSS files (`styles/persons-page.css`, `styles/download-page.css`). ## Where we are now | Snapshot | Lines | Notes | |---|---|---| | Pre-redesign baseline (main) | 6,401 | Single mega-file with mixed concerns. | | After first orphan sweep (`09c416c`) | 5,892 | Removed 78 classes tied to deleted UI (.tab-bar-*, .results-*, .grid-*, etc.). | | After deeper sweep (`1c47412`) | 4,695 | 145 more classes (details-panel cluster, frame thumbnails, batch forms, etc.). | | After persons extraction (`be7f4cd`) | 3,828 | 144 rule blocks moved to `styles/persons-page.css`. | | After download extraction (`3ef5161`) | 2,183 | 303 rule blocks moved to `styles/download-page.css`. | | After iterative orphan scrub (`497e72c`) | **2,161** | **Current.** Eight passes of comma-orphan removal until stable. | Net reduction so far: **6,401 → 2,161 lines (−66 %)**. Other CSS files at the same date: | File | Lines | Purpose | |---|---|---| | `App.css` | 2,161 | Mostly legacy, see breakdown below. | | `styles/design.css` | 342 | Tokens, topbar, layout, buttons, status pills, frame gradients. | | `styles/clip-grid.css` | 421 | Search clip grid + inline player + Open Subtitles modal. | | `styles/page-shared.css` | 109 | page-shell, page-head, card-section, settings rows, error banner. | | `styles/persons-page.css` | 878 | All PersonsPage-only chrome. | | `styles/download-page.css` | 1,625 | All DownloadPage-only chrome. | ## What's left in App.css Roughly 83 unique base classes remain, falling into four buckets: ### 1. Legacy SearchPage controls (~28 classes, ~580 lines) Used only by `SearchPage.jsx`'s in-page Search Mode / Sort By / Filters strip. The redesign already lifted the search input, language picker, and method toggle into the topbar; the page-local controls below it still ride on these legacy class names: `.search-controls`, `.controls-row`, `.control-group`, `.control-label`, `.control-select`, `.search-input`, `.filter-toggle-button`, `.filter-panel`, `.filter-row`, `.filter-group`, `.filter-group-wide`, `.filter-label`, `.filter-date-inputs`, `.filter-duration-inputs`, `.filter-input`, `.filter-separator`, `.filter-select`, `.filter-hint`, `.filter-actions`, `.filter-clear-button`, `.image-drop-overlay`, `.smart-search-info` (+ children), `.scripture-input` (+ children). ### 2. Legacy SearchPage face / image / scripture / save-person panels (~18 classes, ~350 lines) Used by the empty-state panels rendered when the corresponding search method is selected. Most of these moved into `components/FaceSearchPanel`, `ImageUploadPanel`, `ScriptureSearchPanel`, `SavePersonBanner` during the panel extraction, but their CSS still lives in `App.css`: `.face-drop-zone`, `.face-drop-hint`, `.face-search-controls`, `.face-search-divider`, `.face-search-hint`, `.face-quick-actions`, `.drop-indicator`, `.upload-image-button`, `.scripture-search-form`, `.scripture-search-button`, `.scripture-hint`, `.scripture-colon`, `.scripture-inputs`, `.save-person-banner`, `.save-person-form`, `.save-person-input`, `.save-person-confirm`, `.save-person-cancel`, `.save-person-text`, `.save-person-button`, `.person-select`, `.empty-state.face-drop-zone.dragging`. ### 3. Truly shared utilities (~5 classes, ~60 lines) Consumed by more than one page or component: `.empty-state` (Search/Download/Persons + 3 panel components), `.error-message` (Search/Download/Persons), `.toast` and `.toast-message` (DownloadPage Toast + PersonsPage toast renderer). `.app` and `.main-content` are wrappers used by the mockup-viewer branch in `App.jsx`. (`.face-crop-container` was previously listed here but already lives in `styles/persons-page.css` — only PersonsPage references it.) ### 4. Genuinely orphan / dead (~30 classes, ~350 lines) Rules with no current consumer; survived prior sweeps because their last selector was paired with a still-active class via comma list. Includes `.add-person-button`, `.assign-button` and several `.appearance-thumbnail*` modifiers that were superseded by persons-page.css equivalents. ## Sweep order for the rest Each step is its own atomic commit, each verified with a 3-agent QC panel (completeness + cross-page safety + runtime regression). ### Step 1 — Move SearchPage in-page controls into a new `styles/search-page.css` Bucket #1 above. The SearchPage component is finally under the 600-line cap and its inner JSX is stable, so an extraction now is low-risk. Expected impact: App.css ≈ **−320 lines** → ~1,840 (the controls cluster spans App.css:22–283 plus the scripture sub-cluster near 1011–1037 plus the small drag-overlay rule near 1484). ### Step 2 — Move SearchPage panel-specific styles into the panel components Bucket #2 above. Each empty-state panel component (FaceSearchPanel.jsx, ImageUploadPanel.jsx, ScriptureSearchPanel.jsx, SavePersonBanner.jsx) gains its own `.css` sibling and CSS module import. Expected impact: ≈ **−200 lines** → ~1,640 (the face-drop / save-person / image-upload clusters span roughly App.css:858–1037). ### Step 3 — Promote the `.toast`, `.error-message`, `.empty-state` rules into `styles/page-shared.css` Bucket #3. These are the truly shared utilities. Once they're in the shared file, App.css can drop them. Expected impact: ≈ **−60 lines** → ~1,580. ### Step 4 — Sweep the remaining orphans Bucket #4. Confirm with a per-class JSX grep that every selector in the file has a current consumer before deleting. Expected impact: ≈ **−350 lines** → ~1,230. ### Step 5 — Audit what remains Whatever survives Step 4 is genuinely shared between the redesign and a legacy page that hasn't been refactored yet. Decide for each remaining rule whether it (a) graduates into design tokens, (b) stays in App.css as a temporary holding area, or (c) is dead and removable. ## Ground rules during the sweep - **Never delete the last selector of a multi-selector list without also moving its rule body somewhere.** The bug pattern that reviewer #1 caught on 3ef5161 (orphan trailing-comma silently extending into the next rule) is real — every extraction that touches a comma-list must move both the relevant selectors AND the rule body in one operation. - **Run the iterative orphan-comma sweep after every extraction.** Sweeping once isn't always enough — removing a trailing-comma orphan can leave the line above it freshly orphaned. - **Each commit must pass a three-reviewer QC panel** (completeness + cross-page safety + runtime regression check) before the next step starts. ## Final target `App.css` removed entirely; everything lives in: - `styles/design.css` — tokens + global resets + topbar + buttons - `styles/clip-grid.css` — search results layout - `styles/page-shared.css` — page-head, card-section, error-banner, toast, empty-state - `styles/persons-page.css` — PersonsPage chrome - `styles/download-page.css` — DownloadPage chrome - `styles/search-page.css` — SearchPage chrome (created in Step 1) - `components/.css` — panel-specific styles (created in Step 2) Estimated final state: **App.css = 0 lines (file deleted)**. Cumulative deltas across Steps 1-4: ≈ −930 lines, leaving ~1,230 lines that need a Step 5 audit before the file can be removed entirely.