Reorders the detail-page sections so the most-sought content leads, based on
30-day section_nav_used analytics (nav clicks over-count buried sections, so a
low, high-demand section is a strong "surface me" signal):
Primary: Ofsted → SATs Results → Admissions → Pupils & Inclusion → History →
Phonics → What Parents Say → School Life → Location → Local Area → Finances
Secondary: Ofsted → GCSEs → Admissions → History → Parents → Wellbeing →
Location → Finances
Key moves: Admissions (23%, most-clicked) lifted from #6→#3; Pupils & Inclusion
(18%) from #7→#4; History (13%) off the bottom. Ofsted stays first (its low click
rate is positional — everyone reaches it first). Low-demand context sections
(Local Area, Finances) stay last. Brings the primary page in line with secondary.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lh7Js5xSetKNzLVr9ArXLF
The mobile breakpoint's display:none for .sectionNavAll / .sectionNavCompare was
declared before their base display rules, so equal-specificity cascade let the
base win and "All ▾" showed on mobile alongside the section menu. Move the
breakpoint swap block after the base declarations so the hide rules win.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lh7Js5xSetKNzLVr9ArXLF
Fixes the cramped mobile bar where Back, the carried Compare pill and All ▾ all
competed with the scrolling section links:
- On mobile the horizontal swipe strip collapses into a single "Section: <current> ▾"
button that opens the existing jump-to-section sheet — no fragile horizontal
swipe, and it doubles as a "you are here" indicator.
- The carried Compare CTA becomes a compact 38px icon on mobile (compare-arrows +
"add" badge; flips to a teal check when in the comparison), so it no longer
crowds the section control. Desktop keeps the labelled pill.
- Back is icon-only on mobile (label hidden), text on desktop.
- Desktop is unchanged: horizontal links + All ▾, full CTA in the hero.
Both the mobile section menu and the desktop All ▾ open the same sheet.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lh7Js5xSetKNzLVr9ArXLF
Reworks the sticky section bar on the school detail page so mobile users can
perceive the page's breadth and get back to their results without hunting:
- Dock the bar directly under the global header (top: 56px mobile / 64px desktop)
so it's reachable immediately instead of buried below the tall hero.
- Pin "← Back" so it never scrolls off; only the section links scroll, keeping
the existing right-edge fade. Back uses router.back() with a /search fallback
so deep-links never dead-end.
- Carry the hero's "Add to Compare" CTA into the bar as a compact pill once the
hero button scrolls out of view, so the conversion action survives.
- Add an "All ▾" menu (dropdown on desktop, bottom sheet on mobile) listing every
section with the active one ticked — full breadth without horizontal scrolling.
Reuses the site's existing pill / coral / edge-fade / sheet vocabulary rather
than introducing a new navigation paradigm.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lh7Js5xSetKNzLVr9ArXLF
The "How Hard to Get Into This School" this-year view rendered four
question/answer rows stretched to fill the trend chart's height, leaving
tall gaps and a long horizontal jump from a small muted question to its
number. Replace with a 2×2 grid of stat tiles — each number paired with
its label directly beneath — so the panel reads quickly and fills the
reserved height without artificial spacing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A first-choice offer rate sitting on the y-max ceiling (100%) was drawn
flush against the top of the plot area, clipping the point marker. Add 8px
top layout padding and clip:false so ceiling values render in full, without
introducing a misleading >100% tick.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Brings the AdmissionsTrendChart (Chart.js) fix into main; the earlier PR
merged only the initial SVG version, which rendered with oversized,
overlapping labels.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The hand-rolled SVG sparkline used px font sizes inside a 520-wide viewBox
that stretched to the full card width, so labels ballooned ~4x and collided —
and with 10+ years of real data the per-point labels and year ticks
overlapped badly, while the oversized chart stretched the "this year" view.
Replace it with a Chart.js line chart (AdmissionsTrendChart) in a fixed
200px wrapper, matching PerformanceChart: responsive px fonts, auto-skipping
x ticks, auto-scaled y-axis clamped to 0-100, emphasised latest point.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The school detail page only showed the latest admissions year. We store
every year, which is more decision-relevant for parents (the trend and its
consistency matter more than a single noisy year).
Backend now returns the full admissions_history (oldest first) alongside the
existing latest-year object. The primary SchoolDetailView gains a header
toggle ("This year | N-year trend") that swaps the Q&A for an SVG sparkline
of the first-choice offer rate. The toggle only appears when >=2 years carry
an offer rate; otherwise it falls back to the single-year card. Both views
share one CSS-grid cell so switching causes no layout shift.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The standalone dbt Fusion binary (dbt-core 2.x) on PATH shadows the
pip-installed classic dbt-postgres ~=1.10 and rejects the Postgres
adapter (dbt1005), breaking every DAG's dbt_build task. Invoke dbt via
`python -m dbt.cli.main` in the DAGs and the Dockerfile dbt deps step so
the classic Postgres-capable engine is always used regardless of PATH.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>