fix(detail): restore the shell's mobile header/nav CSS #85

Merged
tudor merged 1 commits from perf/server-client-split into main 2026-08-06 09:33:34 +00:00
Owner

The server/client split moved the header and sticky-nav markup into SchoolDetailShell, but their responsive rules stayed behind in schoolSections.module.css. CSS Modules hash class names per file, so those rules stopped matching entirely.

Symptom: the staging E2E journey header details collapse behind a "Show all details" toggle on mobile failed — #school-header-details was visible at 390px because .headerDetails { display: none } no longer applied. The toggle button was invisible too (base rule is display: none; the media query flipping it to inline-flex was stranded in the same block).

Wider blast radius: three shell classes had no rule at all in the shell stylesheet — headerDetailsOpen, atEnd, sectionNavBackLabel — so the mobile section-nav swap (menu button in, link row out), the scroll-fade mask and the bottom-sheet panel were dead as well.

Changes

  • SchoolDetailShell.module.css: ports the stranded blocks verbatim from the pre-refactor stylesheet — the 768px header block (stacked header, wrapped meta pills, details toggle + collapse) and the 640px section-nav blocks.
  • __tests__/components/schoolStyles.test.ts: guards the class of bug — every styles.X a components/school component references must be defined in the stylesheet that component imports. Verified it fails on the pre-fix tree (3 missing classes) and passes after.

Verification

  • jest 159/159 pass
  • tsc --noEmit clean
  • next build succeeds
  • The mobile toggle itself is confirmed by CSS-rule restoration + the guard test, not by a local Playwright run (E2E targets staging).

Known, left alone (pre-existing since the refactor)

  • schoolSections.module.css still carries the header/nav rules as dead code.
  • .secondaryScope .header { padding: 1rem } at ≤768px is stranded by the same split — the shell's <header> sits outside .secondaryScope, so secondary detail headers keep desktop padding on mobile. The guard test can't catch cross-file descendant selectors.

🤖 Generated with Claude Code

The server/client split moved the header and sticky-nav markup into `SchoolDetailShell`, but their responsive rules stayed behind in `schoolSections.module.css`. CSS Modules hash class names per file, so those rules stopped matching entirely. **Symptom:** the staging E2E journey `header details collapse behind a "Show all details" toggle on mobile` failed — `#school-header-details` was visible at 390px because `.headerDetails { display: none }` no longer applied. The toggle button was invisible too (base rule is `display: none`; the media query flipping it to `inline-flex` was stranded in the same block). **Wider blast radius:** three shell classes had no rule at all in the shell stylesheet — `headerDetailsOpen`, `atEnd`, `sectionNavBackLabel` — so the mobile section-nav swap (menu button in, link row out), the scroll-fade mask and the bottom-sheet panel were dead as well. ## Changes - `SchoolDetailShell.module.css`: ports the stranded blocks verbatim from the pre-refactor stylesheet — the 768px header block (stacked header, wrapped meta pills, details toggle + collapse) and the 640px section-nav blocks. - `__tests__/components/schoolStyles.test.ts`: guards the class of bug — every `styles.X` a `components/school` component references must be defined in the stylesheet that component imports. Verified it fails on the pre-fix tree (3 missing classes) and passes after. ## Verification - `jest` 159/159 pass - `tsc --noEmit` clean - `next build` succeeds - The mobile toggle itself is confirmed by CSS-rule restoration + the guard test, not by a local Playwright run (E2E targets staging). ## Known, left alone (pre-existing since the refactor) - `schoolSections.module.css` still carries the header/nav rules as dead code. - `.secondaryScope .header { padding: 1rem }` at ≤768px is stranded by the same split — the shell's `<header>` sits outside `.secondaryScope`, so secondary detail headers keep desktop padding on mobile. The guard test can't catch cross-file descendant selectors. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
tudor added 1 commit 2026-08-06 09:32:38 +00:00
fix(detail): restore the shell's mobile header/nav CSS
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m6s
PR Checks / Backend Smoke (pull_request) Successful in 8s
PR Checks / Build Backend (no push) (pull_request) Successful in 36s
PR Checks / Build Frontend (no push) (pull_request) Successful in 46s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 1m19s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 9s
e098ad4bd1
The server/client split moved the header and sticky nav markup into
SchoolDetailShell, but their responsive rules stayed behind in
schoolSections.module.css. CSS Modules hash class names per file, so those
rules stopped matching entirely: on mobile the header details block never
collapsed ("Show all details" e2e journey failed), the toggle itself never
appeared, and the section-nav mobile swap (menu button in, link row out)
never applied.

Ports the stranded blocks into SchoolDetailShell.module.css verbatim: the
768px header block (stacked header, wrapped meta pills, details toggle +
collapse) and the 640px section-nav blocks (scroll-fade mask, bottom-sheet
panel, control swap). Adds a jest guard that every class a components/school
component references is defined in the stylesheet that component imports —
it fails on the three classes that had no rule at all here
(headerDetailsOpen, atEnd, sectionNavBackLabel).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tudor merged commit c298a29b61 into main 2026-08-06 09:33:34 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: tudor/school_compare#85