Repository source: docs/plans/archive/forte_css_isolation_step2_feature_description.md
Forte CSS Isolation Step 2 Feature Description
Problem
Forte's paned-reader rules live inside site.css next to the classic UI's themeable rules, so every Forte selector has to defensively out-specificity the classic theme to stay visually independent — the cause of three dark-mode leaks fixed this session. Extracting Forte's CSS into its own file removes the shared cascade so this class of bug can't recur.
User Stories
As a maintainer, I want Forte's styles in their own file so that editing the classic theme (adding/changing a
button,a, or:rootrule) can never silently change how Forte renders.As a maintainer, I want Forte's rules in one place so that editing Forte's look doesn't require checking
site.cssfor competing selectors first.As a Forte user, I want no visible change from this work — the reader should look and behave exactly as it does today, in both light and dark browser/OS settings.
Core Requirements
All
.paned-*and.paned-windowrules move out ofsite.cssinto a newpublic/assets/forte.css; nothing else insite.csschanges.Both Forte pages (
/forteand/threads/{id}/forte) loadforte.cssin addition tosite.css(for the generic low-level resets Forte still relies on, e.g.button { appearance: none }), not instead of it.No classic-UI page (
/,/tags,/threads/{id}, etc.) loadsforte.css.forte.cssis served with the same content-hash fingerprinting as every other asset (works in the PHP dev server and inscripts/build_static_artifacts.php's static build).The four dark-mode leak fixes just made (button/link/scrollbar isolation) are preserved exactly — this is a pure relocation, not a rewrite.
Shared Component Inventory
TemplateRenderer::renderStandalonePage()— currently hardcodes a singlesiteCssPath; needs to accept an additional stylesheet path so Forte's two call sites can addforte.csswithout a bespoke rendering path.templates/standalone_layout.php— currently emits exactly one<link rel="stylesheet">; needs to emit the extra one when provided.public/assets/site.css— source of the.paned-*/.paned-windowblock being extracted; every other rule is untouched.AssetFingerprint::fingerprintedPath()/copyFingerprintedAssets()— already generic per-file hashing that scans everything underpublic/assets; a newforte.cssshould be picked up automatically, but this is confirmed in Step 3 rather than assumed.Application::renderForte()andApplication::renderForteBoard()— the two call sites that need to passforte.cssalongside their existing script paths.
Simple User Flow
A developer edits
forte.cssto change the paned reader's appearance;site.cssand the classic UI are unaffected.A visitor loads
/forteor/threads/{id}/forte; the page loads bothsite.css(generic resets) andforte.css(paned-specific rules).A visitor loads any classic page; only
site.cssloads, exactly as today.Running the static-artifact build produces a correctly content-hashed
forte.cssalongside the other hashed assets.
Success Criteria
site.csscontains zero.paned-*or.paned-windowselectors after the move.Forte renders pixel-identical to today in light mode, OS-level dark mode, and the site's explicit dark theme — including the four leaks fixed this session.
Classic UI pages are visually and behaviorally unchanged.
forte.cssis fingerprinted/served correctly by both the dev server and the static build script.No new database fields, tables, or endpoints; no JS behavior changes.