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 + buttonsstyles/clip-grid.cssβ search results layoutstyles/page-shared.cssβ page-head, card-section, error-banner, toast, empty-statestyles/persons-page.cssβ PersonsPage chromestyles/download-page.cssβ DownloadPage chromestyles/search-page.cssβ SearchPage chrome (created in Step 1)components/<Panel>.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.