Compare commits

..
Author SHA1 Message Date
TudorandClaude Opus 4.8 1c1df77961 fix(detail): align Ofsted Report Card grade chips
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m4s
PR Checks / Backend Smoke (pull_request) Successful in 7s
PR Checks / Build Backend (no push) (pull_request) Successful in 11s
PR Checks / Build Frontend (no push) (pull_request) Successful in 44s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 9s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 8s
The grade boxes rendered inconsistently: Safeguarding "Met" was a small
0.8125rem inline pill while grade values ("Strong") were 1.25rem full-width
chips, and because category labels wrap to one or two lines each value sat at
a different vertical position. Two-line values like "Expected standard" also
produced a taller box.

Add a scoped `.gradeGrid` modifier (Report Card + OEIF grids in both the
primary and secondary detail views) that reserves two label lines so every
chip shares a baseline, and gives all value chips one font size, padding and
min-height — long text wraps inside an equal-height chip via max-width:100%.
Scoped rather than touching the shared `.metricCard`/`.metricValue` used by
the finance, phonics and admissions sections.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0146VHeLAWjDVE2B5uU67jCB
2026-07-20 22:31:58 +01:00
5 changed files with 78 additions and 19 deletions
+3 -5
View File
@@ -172,13 +172,11 @@ test('an all-through school shows BOTH its KS2 SATs and its GCSE results, not ju
// Labelled as all-through in the hero meta. // Labelled as all-through in the hero meta.
await expect(page.getByText(/All-through/i).first()).toBeVisible(); await expect(page.getByText(/All-through/i).first()).toBeVisible();
// The combined results section carries both phases, each under its own // The combined results section carries both phases.
// all-through sub-heading (a unique visible node — unlike "Attainment 8",
// which also appears in hidden MetricTooltip labels).
const results = page.locator('#results'); const results = page.locator('#results');
await expect(results.getByText(/SATs & GCSE Results/)).toBeVisible(); await expect(results.getByText(/SATs & GCSE Results/)).toBeVisible();
await expect(results.getByRole('heading', { name: /Primary.*KS2 SATs/ })).toBeVisible(); // KS2 block await expect(results.getByText('Reading, Writing & Maths combined')).toBeVisible(); // KS2
await expect(results.getByRole('heading', { name: /Secondary.*GCSEs/ })).toBeVisible(); // KS4 block await expect(results.getByText('Attainment 8').first()).toBeVisible(); // KS4
}); });
test('school with no performance data still gets a working detail page', async ({ page }) => { test('school with no performance data still gets a working detail page', async ({ page }) => {
@@ -1040,6 +1040,41 @@
color: var(--accent-coral-dark, #b04a2e); color: var(--accent-coral-dark, #b04a2e);
} }
/* ── Ofsted grade grids (Report Card + OEIF) ──
Uniform, vertically-aligned grade chips. Labels reserve two lines so
single- and double-line labels put their chips on the same baseline;
every chip (Met, Strong, Expected standard, …) shares one font size,
padding and min-height regardless of how many lines its text wraps to. */
.gradeGrid .metricCard {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
padding: 0.85rem 0.75rem;
}
.gradeGrid .metricLabel {
min-height: 2.6em;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.gradeGrid .metricValue {
margin-top: auto;
display: inline-flex;
align-items: center;
justify-content: center;
max-width: 100%;
min-height: 2.6em;
padding: 0.3rem 0.7rem;
border-radius: 5px;
font-size: 1rem;
font-weight: 700;
line-height: 1.25;
text-align: center;
}
.ofstedDisclaimer { .ofstedDisclaimer {
font-size: 0.8rem; font-size: 0.8rem;
color: var(--text-muted, #8a847a); color: var(--text-muted, #8a847a);
+2 -11
View File
@@ -555,7 +555,7 @@ export function SchoolDetailView({
<p className={styles.ofstedDisclaimer}> <p className={styles.ofstedDisclaimer}>
From November 2025, Ofsted replaced single overall grades with Report Cards rating schools across several areas. From November 2025, Ofsted replaced single overall grades with Report Cards rating schools across several areas.
</p> </p>
<div className={styles.metricsGrid}> <div className={`${styles.metricsGrid} ${styles.gradeGrid}`}>
{ofsted.rc_safeguarding_met != null && ( {ofsted.rc_safeguarding_met != null && (
<div className={styles.metricCard}> <div className={styles.metricCard}>
<div className={styles.metricLabel}>Safeguarding</div> <div className={styles.metricLabel}>Safeguarding</div>
@@ -601,7 +601,7 @@ export function SchoolDetailView({
Rated <strong>{OFSTED_LABELS[ofsted.overall_effectiveness!]}</strong> across all inspected areas Quality of Teaching, Behaviour, Pupils&apos; Development and Leadership. Rated <strong>{OFSTED_LABELS[ofsted.overall_effectiveness!]}</strong> across all inspected areas Quality of Teaching, Behaviour, Pupils&apos; Development and Leadership.
</p> </p>
) : ( ) : (
<div className={styles.metricsGrid}> <div className={`${styles.metricsGrid} ${styles.gradeGrid}`}>
{oeifAreas.map(({ label, value }) => ( {oeifAreas.map(({ label, value }) => (
<div key={label} className={styles.metricCard}> <div key={label} className={styles.metricCard}>
<div className={styles.metricLabel}>{label}</div> <div className={styles.metricLabel}>{label}</div>
@@ -887,15 +887,6 @@ export function SchoolDetailView({
</div> </div>
)} )}
</div> </div>
{/* All-through admissions data covers a single entry point (usually the
Year 7 secondary intake), not reception — say so, or a parent could
read these as the whole-school figures. */}
{isAllThrough && admissions.school_phase && (
<p className={styles.sectionSubtitle}>
These figures are for {admissions.school_phase.toLowerCase()} entry
{/secondary/i.test(admissions.school_phase) ? ' (Year 7)' : /primary/i.test(admissions.school_phase) ? ' (Reception)' : ''}.
</p>
)}
<div className={styles.admissionsViewport}> <div className={styles.admissionsViewport}>
{/* This-year Q&A */} {/* This-year Q&A */}
@@ -623,6 +623,41 @@
color: var(--accent-coral-dark, #b04a2e); color: var(--accent-coral-dark, #b04a2e);
} }
/* ── Ofsted grade grids (Report Card + OEIF) ──
Uniform, vertically-aligned grade chips. Labels reserve two lines so
single- and double-line labels put their chips on the same baseline;
every chip (Met, Strong, Expected standard, …) shares one font size,
padding and min-height regardless of how many lines its text wraps to. */
.gradeGrid .metricCard {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
padding: 0.85rem 0.75rem;
}
.gradeGrid .metricLabel {
min-height: 2.6em;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.gradeGrid .metricValue {
margin-top: auto;
display: inline-flex;
align-items: center;
justify-content: center;
max-width: 100%;
min-height: 2.6em;
padding: 0.3rem 0.7rem;
border-radius: 5px;
font-size: 1rem;
font-weight: 700;
line-height: 1.25;
text-align: center;
}
.ofstedDisclaimer { .ofstedDisclaimer {
font-size: 0.8rem; font-size: 0.8rem;
color: var(--text-muted, #8a847a); color: var(--text-muted, #8a847a);
@@ -363,7 +363,7 @@ export function SecondarySchoolDetailView({
<p className={styles.ofstedDisclaimer}> <p className={styles.ofstedDisclaimer}>
From November 2025, Ofsted replaced single overall grades with Report Cards rating schools across several areas. From November 2025, Ofsted replaced single overall grades with Report Cards rating schools across several areas.
</p> </p>
<div className={styles.metricsGrid}> <div className={`${styles.metricsGrid} ${styles.gradeGrid}`}>
{ofsted.rc_safeguarding_met != null && ( {ofsted.rc_safeguarding_met != null && (
<div className={styles.metricCard}> <div className={styles.metricCard}>
<div className={styles.metricLabel}>Safeguarding</div> <div className={styles.metricLabel}>Safeguarding</div>
@@ -408,7 +408,7 @@ export function SecondarySchoolDetailView({
Rated <strong>{OFSTED_LABELS[ofsted.overall_effectiveness]}</strong> across all inspected areas Quality of Teaching, Behaviour, Pupils&apos; Development and Leadership. Rated <strong>{OFSTED_LABELS[ofsted.overall_effectiveness]}</strong> across all inspected areas Quality of Teaching, Behaviour, Pupils&apos; Development and Leadership.
</p> </p>
) : ( ) : (
<div className={styles.metricsGrid}> <div className={`${styles.metricsGrid} ${styles.gradeGrid}`}>
{oeifAreas.map(({ label, value }) => ( {oeifAreas.map(({ label, value }) => (
<div key={label} className={styles.metricCard}> <div key={label} className={styles.metricCard}>
<div className={styles.metricLabel}>{label}</div> <div className={styles.metricLabel}>{label}</div>
@@ -425,7 +425,7 @@ export function SecondarySchoolDetailView({
<p className={styles.sectionSubtitle}> <p className={styles.sectionSubtitle}>
From September 2024, Ofsted no longer gives a single overall grade. From September 2024, Ofsted no longer gives a single overall grade.
</p> </p>
<div className={styles.metricsGrid}> <div className={`${styles.metricsGrid} ${styles.gradeGrid}`}>
{[ {[
{ label: 'Quality of Education', value: ofsted.quality_of_education }, { label: 'Quality of Education', value: ofsted.quality_of_education },
{ label: 'Behaviour & Attitudes', value: ofsted.behaviour_attitudes }, { label: 'Behaviour & Attitudes', value: ofsted.behaviour_attitudes },