Cause — a layout trick meeting content it was never sized for
The admissions views are stacked in one grid cell so switching them never shifts layout, and the hidden ones keep their box (display: block; visibility: hidden). That works while the views are comparable in height.
The distance view I added in #102 carries a chart, a table and a map. It measured 1402px against the tile grid's 316px, so it sized the grid row and pinned every other view to its height — including the one that renders by default. The result was four tiles adrift in ~1080px of blank card, on a view nobody had clicked.
Fix — the detail moves out, rather than only unpinning it
Every other topic on the page is a section with a nav entry. "How close did we need to live, and would we have got in?" is a topic, not a variant reading of the intake figures — putting it in a tab inside Admissions is what made Admissions three times everything else. The headline number stays on the Admissions tile where the intake story is; the record behind it moves to a Distance section directly below, with its own nav entry.
Three further changes, each better as well as shorter
The map renders on request. Before a postcode is entered it is a circle drawn round a school, and it costs a Leaflet bundle and 240px of height to say that. A successful check opens it automatically — the point at which it starts answering something, since it then shows your home against the rings. Map height 320px → 240px.
The chart appears only at four published years — the same threshold that lets the summary state a direction. Below that we already refuse to call the series a trend, and a line through three points asserts one regardless of what the sentence beneath it admits. The table carries those years anyway, with the reasons a line cannot show. (The reported school has 3 years, so it gets the table and no chart.)
Three caveat paragraphs become one. They said walking-route twice and made the same point about priorities in two voices, for ~180px. The merged one sits in CutoffDistanceDetail rather than inside the check, so it still renders for a school with missing coordinates — where there is a table but no map and no check. Every claim is preserved; I listed them in the constant's docblock so a future trim can see what is load-bearing.
Also dropped a now-vestigial "Where the last place went" heading: it introduced a map that had moved behind a button, and echoed the section title directly above it.
The guard, and the version of it that proved nothing
The new e2e test asserts no section exceeds 2.5× the median section height — the reader's actual complaint, one section wildly out of proportion with its neighbours.
Measuring the card's internals cannot catch this. The tile grid is flex: 1, so it absorbs the stretch and every box still measures full; my first attempt compared a view's height to the sum of its children and reported 34px of slack on a page that was visibly broken.
The first working version then targeted an arbitrary primary via twoPrimaryUrns — and passed against the live bug, because a school with no cut-off history has no third view to do the padding. Pointed at a school that actually holds the history, it fails on staging with the diagnosis in the message:
#admissions is 1459px against a 526px median:
ofsted=201, results=526, admissions=1459, inclusion=215, history=528
Expected: < 2.5 Received: 2.77
Verification
tsc clean; next build green
218 frontend tests, 54 backend — including new assertions that the chart only appears with 4+ points, that the caveat renders exactly once, and that the map stays behind a request until asked for or answered
Rendered offline against the real compiled CSS in both themes and at 390px; no horizontal page scroll, heading order well-formed after the h4 → h3 promotion
e2e against staging: 48 of 54 pass. The 6 failures are expected and are the point — 5 assert #distance exists and staging still serves the pre-change build where it was a tab, and the 6th is the proportion guard failing on the live bug. All 6 should go green on deploy; worth confirming that rather than taking my word for it.
Reported on [Our Lady Queen of Heaven](https://stx.schoolcompare.co.uk/school/101051-our-lady-queen-of-heaven-rc-school): the Admissions card is enormous and pushes everything else down.
Measured on that page, it was not an impression — Admissions was **half the height of every section put together**:
```
admissions 1503px 50.5% #####################################
history 528px 17.7% #############
results 526px 17.7% #############
inclusion 215px 7.2% #####
ofsted 203px 6.8% #####
```
## Cause — a layout trick meeting content it was never sized for
The admissions views are stacked in one grid cell so switching them never shifts layout, and the hidden ones **keep their box** (`display: block; visibility: hidden`). That works while the views are comparable in height.
The distance view I added in #102 carries a chart, a table and a map. It measured **1402px against the tile grid's 316px**, so it sized the grid row and pinned every other view to its height — including the one that renders by default. The result was four tiles adrift in ~1080px of blank card, on a view nobody had clicked.
My regression, introduced in #102.
## Fix — the detail moves out, rather than only unpinning it
Every other topic on the page is a section with a nav entry. "How close did we need to live, and would we have got in?" is a *topic*, not a variant reading of the intake figures — putting it in a tab inside Admissions is what made Admissions three times everything else. The headline number stays on the Admissions tile where the intake story is; the record behind it moves to a **Distance** section directly below, with its own nav entry.
```
admissions 1503px -> 554px
distance new -> 743px (median section ~528px)
```
## Three further changes, each better as well as shorter
**The map renders on request.** Before a postcode is entered it is a circle drawn round a school, and it costs a Leaflet bundle and 240px of height to say that. A successful check opens it automatically — the point at which it starts answering something, since it then shows your home against the rings. Map height 320px → 240px.
**The chart appears only at four published years** — the same threshold that lets the summary state a direction. Below that we already refuse to call the series a trend, and a line through three points asserts one regardless of what the sentence beneath it admits. The table carries those years anyway, with the reasons a line cannot show. (The reported school has 3 years, so it gets the table and no chart.)
**Three caveat paragraphs become one.** They said walking-route twice and made the same point about priorities in two voices, for ~180px. The merged one sits in `CutoffDistanceDetail` rather than inside the check, so it still renders for a school with missing coordinates — where there is a table but no map and no check. Every claim is preserved; I listed them in the constant's docblock so a future trim can see what is load-bearing.
Also dropped a now-vestigial "Where the last place went" heading: it introduced a map that had moved behind a button, and echoed the section title directly above it.
## The guard, and the version of it that proved nothing
The new e2e test asserts **no section exceeds 2.5× the median section height** — the reader's actual complaint, one section wildly out of proportion with its neighbours.
Measuring the card's internals cannot catch this. The tile grid is `flex: 1`, so it absorbs the stretch and every box still measures full; my first attempt compared a view's height to the sum of its children and reported 34px of slack on a page that was visibly broken.
The first working version then targeted an arbitrary primary via `twoPrimaryUrns` — and **passed against the live bug**, because a school with no cut-off history has no third view to do the padding. Pointed at a school that actually holds the history, it fails on staging with the diagnosis in the message:
```
#admissions is 1459px against a 526px median:
ofsted=201, results=526, admissions=1459, inclusion=215, history=528
Expected: < 2.5 Received: 2.77
```
## Verification
- `tsc` clean; `next build` green
- **218 frontend tests**, **54 backend** — including new assertions that the chart only appears with 4+ points, that the caveat renders exactly once, and that the map stays behind a request until asked for or answered
- Rendered offline against the real compiled CSS in both themes and at 390px; no horizontal page scroll, heading order well-formed after the h4 → h3 promotion
**e2e against staging: 48 of 54 pass.** The 6 failures are expected and are the point — 5 assert `#distance` exists and staging still serves the pre-change build where it was a tab, and the 6th is the proportion guard failing on the live bug. All 6 should go green on deploy; worth confirming that rather than taking my word for it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01WDvkyqqHABm4bmth2kjAxE
The admissions card measured 1503px on a live school page — half the height
of every section put together, and nearly three times the next largest — with
its default view rendering as four tiles adrift in about 1080px of blank card.
The cause was a layout trick meeting content it was never sized for. The
admissions views are stacked in one grid cell so switching them never shifts
layout, and the hidden ones keep their box: only visibility is dropped. That
works while the views are comparable. The distance view added in #102 carries
a chart, a table and a map, came to 1402px against the tile grid's 316px, and
pinned every other view to its height — including the one that renders by
default, which nobody had clicked.
Rather than only unpinning it, the detail moves out. Every other topic on the
page is a section with a nav entry, and "how close did we need to live, and
would we have got in?" is a topic, not a variant reading of the intake
figures. The headline number stays on the Admissions tile where the intake
story is; the record behind it now lives in a Distance section directly below.
admissions 1503px -> 554px
distance new -> 743px (median section on the page is ~528px)
Three further changes, each of which also makes the content better rather
than only shorter:
* The map renders on request. Before a postcode is entered it is a circle
drawn round a school, and it costs a Leaflet bundle and 240px to say so;
a successful check opens it automatically, which is the point at which it
starts answering something. Map height 320px -> 240px.
* The chart appears only at the four published years that let the summary
state a direction. Below that we already refuse to call the series a
trend, and a line through three points asserts one regardless of what the
sentence beneath it admits. The table carries those years anyway, with
the reasons a line cannot show.
* Three caveat paragraphs become one. They said walking-route twice and
made the same point about priorities in two voices. It now sits in
CutoffDistanceDetail rather than inside the check, so it still renders
for a school with coordinates missing, where there is a table but no map
and no check.
The new e2e guard asserts no section exceeds 2.5x the median section height.
Measuring the card's internals cannot catch this: the tile grid is flex: 1,
so it absorbs the stretch and every box still looks full. The first version
of this test targeted an arbitrary primary, passed against the live bug, and
proved nothing; pointed at a school that actually holds cut-off history it
fails on staging with "#admissions is 1459px against a 526px median".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WDvkyqqHABm4bmth2kjAxE
This PR pulls the school-level cut-off distance detail (chart, table, map, postcode check) out of a tab inside the Admissions card into its own top-level 'Distance' section on both primary and secondary school pages, since the tall detail view was distorting the stacked-grid admissions card height. It also consolidates three separate caveat paragraphs into one, gates the trend chart on having 4+ published years (matching the existing trend-summary threshold), defers the Leaflet map behind a 'show on map' toggle, and updates e2e/unit tests accordingly. The refactor is internally consistent: the new hasCutoffDetail predicate is shared between the section components and the nav-builder functions so the sticky nav can't link to an unrendered anchor, prop threading through Primary/Secondary section components matches call sites, and no stale imports/exports (e.g. CUTOFF_MAP_CAVEAT, showCaveat) remain.
✅ No issues found.
## 🤖 AI Code Review (Claude Code)
This PR pulls the school-level cut-off distance detail (chart, table, map, postcode check) out of a tab inside the Admissions card into its own top-level 'Distance' section on both primary and secondary school pages, since the tall detail view was distorting the stacked-grid admissions card height. It also consolidates three separate caveat paragraphs into one, gates the trend chart on having 4+ published years (matching the existing trend-summary threshold), defers the Leaflet map behind a 'show on map' toggle, and updates e2e/unit tests accordingly. The refactor is internally consistent: the new `hasCutoffDetail` predicate is shared between the section components and the nav-builder functions so the sticky nav can't link to an unrendered anchor, prop threading through Primary/Secondary section components matches call sites, and no stale imports/exports (e.g. `CUTOFF_MAP_CAVEAT`, `showCaveat`) remain.
✅ No issues found.
tudor
merged commit 50b599a09b into main2026-08-20 14:03:02 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Reported on Our Lady Queen of Heaven: the Admissions card is enormous and pushes everything else down.
Measured on that page, it was not an impression — Admissions was half the height of every section put together:
Cause — a layout trick meeting content it was never sized for
The admissions views are stacked in one grid cell so switching them never shifts layout, and the hidden ones keep their box (
display: block; visibility: hidden). That works while the views are comparable in height.The distance view I added in #102 carries a chart, a table and a map. It measured 1402px against the tile grid's 316px, so it sized the grid row and pinned every other view to its height — including the one that renders by default. The result was four tiles adrift in ~1080px of blank card, on a view nobody had clicked.
My regression, introduced in #102.
Fix — the detail moves out, rather than only unpinning it
Every other topic on the page is a section with a nav entry. "How close did we need to live, and would we have got in?" is a topic, not a variant reading of the intake figures — putting it in a tab inside Admissions is what made Admissions three times everything else. The headline number stays on the Admissions tile where the intake story is; the record behind it moves to a Distance section directly below, with its own nav entry.
Three further changes, each better as well as shorter
The map renders on request. Before a postcode is entered it is a circle drawn round a school, and it costs a Leaflet bundle and 240px of height to say that. A successful check opens it automatically — the point at which it starts answering something, since it then shows your home against the rings. Map height 320px → 240px.
The chart appears only at four published years — the same threshold that lets the summary state a direction. Below that we already refuse to call the series a trend, and a line through three points asserts one regardless of what the sentence beneath it admits. The table carries those years anyway, with the reasons a line cannot show. (The reported school has 3 years, so it gets the table and no chart.)
Three caveat paragraphs become one. They said walking-route twice and made the same point about priorities in two voices, for ~180px. The merged one sits in
CutoffDistanceDetailrather than inside the check, so it still renders for a school with missing coordinates — where there is a table but no map and no check. Every claim is preserved; I listed them in the constant's docblock so a future trim can see what is load-bearing.Also dropped a now-vestigial "Where the last place went" heading: it introduced a map that had moved behind a button, and echoed the section title directly above it.
The guard, and the version of it that proved nothing
The new e2e test asserts no section exceeds 2.5× the median section height — the reader's actual complaint, one section wildly out of proportion with its neighbours.
Measuring the card's internals cannot catch this. The tile grid is
flex: 1, so it absorbs the stretch and every box still measures full; my first attempt compared a view's height to the sum of its children and reported 34px of slack on a page that was visibly broken.The first working version then targeted an arbitrary primary via
twoPrimaryUrns— and passed against the live bug, because a school with no cut-off history has no third view to do the padding. Pointed at a school that actually holds the history, it fails on staging with the diagnosis in the message:Verification
tscclean;next buildgreene2e against staging: 48 of 54 pass. The 6 failures are expected and are the point — 5 assert
#distanceexists and staging still serves the pre-change build where it was a tab, and the 6th is the proportion guard failing on the live bug. All 6 should go green on deploy; worth confirming that rather than taking my word for it.🤖 Generated with Claude Code
https://claude.ai/code/session_01WDvkyqqHABm4bmth2kjAxE
🤖 AI Code Review (Claude Code)
This PR pulls the school-level cut-off distance detail (chart, table, map, postcode check) out of a tab inside the Admissions card into its own top-level 'Distance' section on both primary and secondary school pages, since the tall detail view was distorting the stacked-grid admissions card height. It also consolidates three separate caveat paragraphs into one, gates the trend chart on having 4+ published years (matching the existing trend-summary threshold), defers the Leaflet map behind a 'show on map' toggle, and updates e2e/unit tests accordingly. The refactor is internally consistent: the new
hasCutoffDetailpredicate is shared between the section components and the nav-builder functions so the sticky nav can't link to an unrendered anchor, prop threading through Primary/Secondary section components matches call sites, and no stale imports/exports (e.g.CUTOFF_MAP_CAVEAT,showCaveat) remain.✅ No issues found.