Implements the direction agreed from the identity board: Route C ("Cohort")
with the paper ground from C1, the Schibsted Grotesk / Literata pairing from
C2, and the iris accent from C3. Dark theme is in scope from the start rather
than retrofitted.
The audit found three things wrong beyond taste:
* No brand asset set. og:image was absent entirely, so every link shared into
a class WhatsApp group rendered as a bare grey card. apple-touch-icon pointed
at an SVG, which iOS ignores, and the manifest shipped no PNGs, so Android
installs had no icon. The header mark and the favicon had also drifted into
two different logos.
* No colour discipline. --primary and --trend-down were the same coral, so the
main CTA and "below average" shared a hue. 58 distinct hex values were spread
across component CSS, and the chart palette was still Chart.js's stock demo
colours.
* A dark theme that was declared but never built — themeColor announced a dark
variant with no dark styling behind it.
What changed:
Colour now has exactly three jobs that never borrow each other's hues: brand
(iris) for interactive and identity, status (teal/amber) for above/below a
comparison point, and phase for categories. Teal/amber rather than green/red
keeps the above/below signal readable for every form of colour blindness.
Every chromatic literal in component CSS is now a token, and the JS-painted
surfaces (Chart.js, Leaflet) read the tokens through lib/theme so they follow
the theme instead of ignoring it.
The mark is the five-bar cohort spread — the same object as the distribution
strip inside a school row, built from opacity steps so it inverts cleanly.
components/Logo.tsx is the single source; the favicon, apple-icon and share
card all derive from its geometry.
globals.css drops 123 dead global classes left over from the vanilla-JS app
(only the btn family, .skip-link and .main were still referenced), along with
the noise overlay. It also gains prefers-reduced-motion support, which was
missing entirely, and a type scale so the 54 ad-hoc font sizes have somewhere
to converge.
Verified: tsc clean, 159 unit tests pass, production build succeeds and
prerenders /icon.svg, /apple-icon and /opengraph-image. Three e2e journeys
added for the asset set, the themeColor/background match, and the dark theme
actually repainting — all silent failures that nothing on the page reveals.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
SF1 (expert sign-off): the secondary academics 'Grade 5+ in English &
maths' and 'EBacc entry' rows rendered as bare numbers — the one place
the 'every number anchored against the England average' promise broke.
Both now show the official England anchor (already in the payload) + an
Above/Close/Below verdict chip, matching Attainment 8 (which also gains a
chip for consistency).
Button affordance: globals.css has a duplicate .btn block whose
'border: none' overrode the base '1px solid transparent', so
.btn-secondary/.btn-active's 'border-color' had no width — every outline
button (the modal's '+ Compare', search-result '+ Compare', 'Comparing')
rendered as borderless teal text. Give the outline variants the full
'border' shorthand so the outline renders regardless of the clobbered base.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0146VHeLAWjDVE2B5uU67jCB
Live axe-core inventory found 13 failing fg/bg pairs (3.12:1 coral text/
fills, 4.0-4.5 teal near-misses, 2.7 gold badge, 1.9 chart-colour text).
All replacement values validated ≥4.5:1 against every background they
sit on:
- --accent-coral-dark deepened to #b04a2e and used for coral text roles
(nav active, back/map links, kickers, chips) and coral fills under
white text (btn-primary, phase tabs, section-nav compare, chart chips);
new --accent-coral-darker #9c3f26 for their hovers. Decorative coral
(pins, bars, borders, focus ring) keeps the brand #e07256.
- --accent-teal darkened to #296f6f (rankings values, metric rows,
ofsted grades, eyebrows all pass).
- Ofsted green #3c8c3c→#2f7a2f; off-token gold #b8920e→--accent-gold-text.
- Gender-split pink text #b45778→#a04a68; admissions tip numerals to a
3.8:1 muted brown (28px display text).
- New CHART_TEXT_COLORS: AA-dark counterparts of the Chart.js series
palette for compare-card values (swatch dots keep true series colour).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MOB-19: Add a viewport Viewport export with viewportFit: 'cover' and
themeColor entries for light (#faf7f2) / dark (#1a1612), plus the
appleWebApp metadata for the home-screen status bar style and title.
Manifest's stale #3b82f6 theme_color updated to match brand cream.
MOB-20: Apply env(safe-area-inset-*) to the sticky chrome — the top
header gets max(padding, inset-left/right) so the logo and tab links
clear the notch in landscape; the bottom tab bar already had
inset-bottom and now also gets inset-left/right.
MOB-21: Replace 100vh with 100dvh in body min-height, modal max-heights,
the map view container, and the fullscreen map. Older engines fall
back via the duplicated vh declaration.
MOB-22: Set -webkit-tap-highlight-color: transparent on body to
suppress the iOS Safari grey flash; add a generic touch-pointer
:active rule (opacity 0.7) so taps still register visually on plain
anchors and bare buttons. Components with their own :active styling
are unaffected.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
MOB-01: At ≤640px the top inline nav is hidden and replaced by a
fixed bottom tab bar (Search / Compare / Rankings / Admissions) with
icon + label, 56px tap targets, env(safe-area-inset-bottom) padding,
and the Compare count rendered as a badge on the icon. Eliminates
horizontal page overflow on every route (docW was 401–429 at vw 390;
now docW === vw).
MOB-02: Logo link gains a padded hit area so the touch target is
≥44×44 (was 36×36), without resizing the visual mark.
ComparisonToast lifted above the new bottom bar on mobile so the two
do not stack on top of each other. body gets a bottom padding equal
to the bar height + safe-area inset so page content is never hidden.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- rankings: hide Type/Action columns on mobile so metric value stays visible;
ensure filter selects and table wrapper stay within viewport
- school detail: add min-width:0 / max-width:100% containment so internal
overflow-x wrappers actually clip rather than pushing the page wider;
explicit line-height on Ofsted grade badges to fix glyph clipping
- compare: sticky first column on the Detailed Comparison table so the Year
labels remain visible while horizontally scrolling school columns
- search: shorten placeholder to "School name or postcode" so it fits mobile
input width
- globals: overflow-x:clip safety net on .main wrapper
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add coloured left-border and phase label pill to visually differentiate
school phases (Primary, Secondary, All-through, Post-16, Nursery) in
search result lists. Colours are accessible (WCAG AA) and don't clash
with existing Ofsted/trend semantic colours.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Increased header z-index from 100 to 1000 to ensure it stays above
Leaflet map elements (which typically use z-index 400-600).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The "Add to Compare" button on individual school pages was invisible
because the CSS variables --primary, --primary-dark, --success, and
--border-light were not defined in globals.css.
Added these variables mapped to the existing color palette:
- --primary: coral accent (#e07256)
- --primary-dark: dark coral (#c45a3f)
- --success: teal accent (#2d7d7d)
- --border-light: border color (#e5dfd5)
The button was already in the DOM but had no background color.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Copy complete original styles.css (1900+ lines) to globals.css
- Add Google Fonts (DM Sans and Playfair Display) via next/font
- Use CSS variables for fonts
- Restore warm color palette (#faf7f2 bg, coral/teal accents)
- Restore noise overlay texture
- Restore all original animations and transitions
- Match original card styles, buttons, modals
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Migrate from vanilla JavaScript SPA to Next.js 16 with App Router
- Add server-side rendering for all pages (Home, Compare, Rankings)
- Create individual school pages with dynamic routing (/school/[urn])
- Implement Chart.js and Leaflet map integrations
- Add comprehensive SEO with sitemap, robots.txt, and JSON-LD
- Set up Docker multi-service architecture (PostgreSQL, FastAPI, Next.js)
- Update CI/CD pipeline to build both backend and frontend images
- Fix Dockerfile to include devDependencies for TypeScript compilation
- Add Jest testing configuration
- Implement performance optimizations (code splitting, caching)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>