PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m1s
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 46s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 10s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 1m5s
The marker was var(--brand) — the identical value to the bar fill it sits on.
Measured by pixel-sampling every bar on both templates, in both themes:
primary SatsChart .natTick 1.00:1 (6 bars)
secondary .att8VizNatLine 1.00:1
Not low contrast. The same colour. It scored 5.47:1 only against the empty
track, which means it was visible precisely when a school was BELOW the
national average and vanished for every school at or above it — failing for
exactly the schools people are looking for.
No single colour fixes this, because the marker's position is data-driven: it
can land on the bar, on the empty track, or across the boundary. It is now a
knockout — a light core carrying a dark edge, both from tokens that flip with
the theme, so one part or the other always separates:
on the bar on the track
light 5.47 / 9.70:1 15.17:1
dark 7.81 / 10.85:1 13.52:1
THE LEGEND DESCRIBED A CHART THAT DID NOT EXIST
Both data swatches were var(--status-above) green while their bars were
var(--brand) teal, and the two were identical to each other — one swatch for
two series. Worse, the only swatch matching the bar colour was the one
labelled "National average", so reading the chart by matching colours told you
the teal bars were the benchmark. Each swatch now carries its bar's exact
value, and the marker swatch mirrors the knockout.
TWO SERIES, ONE COLOUR
Expected and Exceeding were both var(--brand), distinguished only by row.
They are a sequential pair — exceeding is the same cohort at a harder bar — so
they take two steps of one hue, the harder measure being the step further from
the ground in each theme.
They measure 1.77:1 (light) and 1.39:1 (dark) against each other, and that is
accepted rather than overlooked: two fills that must EACH clear 3:1 against
the same white track are geometrically forced close together. The distinction
is carried by the row labels and printed values; colour is redundant here, not
load-bearing.
THE TEST THAT SHOULD HAVE CAUGHT THIS
The WCAG journey composites backgrounds by walking the ancestor chain, but
these markers are absolutely positioned over a sibling — ancestor-walking is
structurally blind to overlap, which is why this shipped in two templates and
passed every gate. The new journey asks the stacking order instead, via
document.elementsFromPoint.
Writing it surfaced a second trap worth recording: elementsFromPoint takes
viewport coordinates and returns an empty stack off-screen, and these markers
sit ~1200px down. The first version defaulted an empty stack to white, which
made teal-on-teal look like teal-on-white and PASS in the light theme. It now
scrolls each marker into view and counts any marker it cannot resolve a
backdrop for as a failure rather than a pass.
Verified both directions: the new journey fails against current staging with
"1.00:1 over rgb(15,118,110)" in both themes, and passes against this build
with 6/6 markers measured at 5.47–15.17:1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1965 lines
44 KiB
CSS
1965 lines
44 KiB
CSS
.container {
|
||
width: 100%;
|
||
min-width: 0;
|
||
max-width: 100%;
|
||
}
|
||
|
||
/* Standalone back link, sits above the header card on the page background. */
|
||
.topBack {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
margin: 0 0 0.75rem;
|
||
padding: 0.25rem 0;
|
||
font-size: 1.0625rem;
|
||
font-weight: 600;
|
||
color: var(--brand-strong);
|
||
background: none;
|
||
border: none;
|
||
cursor: pointer;
|
||
line-height: 1.2;
|
||
transition: color 0.15s ease;
|
||
}
|
||
|
||
.topBack:hover {
|
||
color: var(--brand-strong);
|
||
text-decoration: underline;
|
||
text-underline-offset: 2px;
|
||
}
|
||
|
||
/* Header Section */
|
||
.header {
|
||
position: relative;
|
||
background: var(--bg-card);
|
||
border: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
/* Padding lives on .headerContent so the map band can bleed to the edges. */
|
||
padding: 0;
|
||
margin-bottom: 0;
|
||
box-shadow: var(--shadow-soft);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.headerContent {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
gap: 1.5rem;
|
||
padding: 1.25rem 1.5rem;
|
||
}
|
||
|
||
/* With a map band above, slide the title up under the fade so map and title
|
||
read as one object; the Compare button floats glassy over the map. */
|
||
.headerHasMap .headerContent {
|
||
padding-top: 0;
|
||
margin-top: -0.5rem;
|
||
}
|
||
|
||
/* The title (not the whole content row) rises above the map fade. Keeping
|
||
.headerContent unpositioned matters: .actions must anchor to .header so it
|
||
floats over the map band, not over the title. */
|
||
.headerHasMap .titleSection {
|
||
position: relative;
|
||
z-index: 3;
|
||
}
|
||
|
||
.headerHasMap .actions {
|
||
position: absolute;
|
||
top: 14px;
|
||
right: 14px;
|
||
z-index: 6;
|
||
margin: 0;
|
||
/* Beat the mobile `.actions { width: 100% }` rule — a floating button
|
||
must never stretch across the title. */
|
||
width: auto;
|
||
}
|
||
|
||
.headerHasMap .actions .btnAdd {
|
||
background: var(--bg-card);
|
||
color: var(--brand-strong);
|
||
border-color: transparent;
|
||
-webkit-backdrop-filter: blur(6px);
|
||
backdrop-filter: blur(6px);
|
||
box-shadow: 0 2px 10px rgba(var(--shadow-rgb), 0.16);
|
||
}
|
||
|
||
.headerHasMap .actions .btnAdd:hover {
|
||
background: #fff;
|
||
}
|
||
|
||
/* Full label by default; phones over the map get an icon-only button
|
||
(same compact treatment as the section-nav compare icon). */
|
||
.btnCompareGlyph {
|
||
display: none;
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.headerHasMap .actions .btnCompareLabel {
|
||
display: none;
|
||
}
|
||
|
||
.headerHasMap .actions .btnCompareGlyph {
|
||
display: inline;
|
||
}
|
||
|
||
.headerHasMap .actions .btnAdd,
|
||
.headerHasMap .actions .btnRemove {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex: none;
|
||
width: 40px;
|
||
height: 40px;
|
||
padding: 0;
|
||
border-radius: 999px;
|
||
font-size: 1.375rem;
|
||
line-height: 1;
|
||
}
|
||
}
|
||
|
||
/* Inline "View on map ↗" trigger next to the address. */
|
||
.mapLink {
|
||
border: none;
|
||
background: none;
|
||
padding: 0;
|
||
font: inherit;
|
||
font-weight: 600;
|
||
color: var(--brand-strong);
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.mapLink:hover {
|
||
color: var(--brand-strong);
|
||
text-decoration: underline;
|
||
text-underline-offset: 2px;
|
||
}
|
||
|
||
.titleSection {
|
||
flex: 1;
|
||
}
|
||
|
||
.schoolName {
|
||
font-size: clamp(2rem, 5vw, 3.25rem);
|
||
font-weight: 700;
|
||
color: var(--text-primary);
|
||
margin-bottom: 0.5rem;
|
||
line-height: 1.1;
|
||
letter-spacing: -0.01em;
|
||
font-family: var(--font-display);
|
||
overflow-wrap: break-word;
|
||
}
|
||
|
||
.meta {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.5rem;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.metaItem {
|
||
font-size: 0.8125rem;
|
||
color: var(--text-secondary);
|
||
padding: 0.125rem 0.5rem;
|
||
background: var(--bg-secondary);
|
||
border-radius: 3px;
|
||
}
|
||
|
||
.address {
|
||
font-size: 0.875rem;
|
||
color: var(--text-muted);
|
||
margin: 0 0 0.75rem;
|
||
overflow-wrap: break-word;
|
||
}
|
||
|
||
/* Expanded header details (headteacher, website, trust, pupils) */
|
||
.headerDetails {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.5rem 1.25rem;
|
||
margin-top: 0.5rem;
|
||
}
|
||
|
||
.headerDetail {
|
||
font-size: 0.8125rem;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.headerDetail strong {
|
||
color: var(--text-primary);
|
||
font-weight: 600;
|
||
}
|
||
|
||
.headerDetail a {
|
||
color: var(--brand);
|
||
text-decoration: none;
|
||
}
|
||
|
||
.headerDetail a:hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
/* "Show all details" reveal — only rendered on mobile/tablet, where the
|
||
header details block is collapsed below the fold. Hidden on desktop. */
|
||
.detailsToggle {
|
||
display: none;
|
||
align-items: center;
|
||
gap: 0.25rem;
|
||
margin-top: 0.5rem;
|
||
padding: 0;
|
||
background: none;
|
||
border: none;
|
||
font-size: 0.8125rem;
|
||
font-weight: 600;
|
||
color: var(--brand);
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* Gender split card — sits in the Pupils & Inclusion heroStatGrid */
|
||
.genderSplitValue {
|
||
font-variant-numeric: tabular-nums;
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 0.3rem;
|
||
font-family: var(--font-display);
|
||
font-size: 1.55rem;
|
||
font-weight: 700;
|
||
line-height: 1;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.genderSplitGirls {
|
||
color: var(--phase-nursery-text);
|
||
}
|
||
|
||
.genderSplitBoys {
|
||
color: var(--phase-primary-text);
|
||
}
|
||
|
||
.genderSplitLabel {
|
||
font-family: var(--font-ui);
|
||
font-size: 0.78rem;
|
||
font-weight: 500;
|
||
color: var(--text-muted);
|
||
letter-spacing: 0;
|
||
}
|
||
|
||
.genderSplitSep {
|
||
color: var(--border);
|
||
font-weight: 400;
|
||
font-size: 1.2rem;
|
||
padding: 0 0.1rem;
|
||
}
|
||
|
||
.genderBar {
|
||
display: flex;
|
||
height: 6px;
|
||
border-radius: 999px;
|
||
overflow: hidden;
|
||
background: var(--border);
|
||
width: 100%;
|
||
}
|
||
|
||
.genderBarGirls {
|
||
background: var(--phase-nursery-text);
|
||
}
|
||
|
||
.genderBarBoys {
|
||
background: var(--phase-primary);
|
||
}
|
||
|
||
.actions {
|
||
display: flex;
|
||
gap: 0.5rem;
|
||
flex-shrink: 0;
|
||
align-self: center;
|
||
}
|
||
|
||
.btnAdd,
|
||
.btnRemove {
|
||
padding: 0.75rem 1.25rem;
|
||
font-size: 0.9375rem;
|
||
font-weight: 600;
|
||
border: none;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
white-space: nowrap;
|
||
box-shadow: var(--shadow-soft, 0 2px 8px rgba(var(--shadow-rgb), 0.08));
|
||
}
|
||
|
||
.btnAdd {
|
||
background: var(--brand-strong);
|
||
color: var(--brand-on);
|
||
}
|
||
|
||
.btnAdd:hover {
|
||
background: var(--brand-stronger);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
.btnRemove {
|
||
background: var(--brand);
|
||
color: var(--brand-on);
|
||
}
|
||
|
||
.btnRemove:hover {
|
||
opacity: 0.9;
|
||
}
|
||
|
||
/* ── Sticky Section Navigation ──────────────────────── */
|
||
/* Docks directly under the global header; Back and "All" stay pinned while
|
||
only the section links scroll. */
|
||
.sectionNav {
|
||
position: sticky;
|
||
top: 64px; /* global header height on desktop */
|
||
z-index: 10;
|
||
background: var(--bg-card);
|
||
border: 1px solid var(--border);
|
||
border-top: none;
|
||
border-radius: 0 0 10px 10px;
|
||
padding: 0.5rem 0.75rem;
|
||
margin-bottom: 1rem;
|
||
box-shadow: 0 2px 4px rgba(var(--shadow-rgb), 0.04);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.sectionNav {
|
||
top: 56px; /* global header is shorter on mobile */
|
||
padding: 0.4rem 0.6rem;
|
||
gap: 0.375rem;
|
||
}
|
||
}
|
||
|
||
.sectionNavBack {
|
||
flex: none;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.3rem;
|
||
padding: 0.3rem 0.625rem;
|
||
font-size: 0.75rem;
|
||
font-weight: 600;
|
||
color: var(--brand-strong);
|
||
background: none;
|
||
border: 1px solid var(--border);
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
transition: all 0.15s ease;
|
||
}
|
||
|
||
.sectionNavBack:hover {
|
||
background: var(--bg-secondary);
|
||
border-color: var(--brand);
|
||
}
|
||
|
||
/* The scrolling middle: section links only. */
|
||
.sectionNavLinks {
|
||
flex: 1;
|
||
min-width: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.375rem;
|
||
overflow-x: auto;
|
||
white-space: nowrap;
|
||
-webkit-overflow-scrolling: touch;
|
||
scrollbar-width: none;
|
||
scroll-snap-type: x proximity;
|
||
scroll-padding-inline: 0.5rem;
|
||
}
|
||
|
||
.sectionNavLinks::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
/* Right-edge fade so users see there's more to scroll to. */
|
||
@media (max-width: 640px) {
|
||
.sectionNavLinks {
|
||
-webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
|
||
mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
|
||
}
|
||
|
||
/* When scrolled to the end, drop the fade so the last item isn't dimmed. */
|
||
.sectionNavLinks.atEnd {
|
||
-webkit-mask-image: none;
|
||
mask-image: none;
|
||
}
|
||
}
|
||
|
||
.sectionNavLink {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
padding: 0.3rem 0.625rem;
|
||
font-size: 0.75rem;
|
||
font-weight: 500;
|
||
color: var(--text-secondary);
|
||
text-decoration: none;
|
||
border-radius: 4px;
|
||
transition: all 0.15s ease;
|
||
white-space: nowrap;
|
||
scroll-snap-align: start;
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.sectionNavLink,
|
||
.sectionNavBack {
|
||
min-height: 36px;
|
||
padding: 0.5rem 0.75rem;
|
||
font-size: 0.8125rem;
|
||
}
|
||
}
|
||
|
||
.sectionNavLink:hover {
|
||
background: var(--bg-secondary);
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.sectionNavLinkActive {
|
||
background: var(--brand-strong);
|
||
color: var(--brand-on);
|
||
font-weight: 600;
|
||
}
|
||
|
||
.sectionNavLinkActive:hover {
|
||
background: var(--brand-strong);
|
||
color: var(--brand-on);
|
||
}
|
||
|
||
/* ── Mobile: the scrolling links collapse into one "section" menu button ──
|
||
(hidden on desktop, where the links fit). */
|
||
.sectionNavMenu {
|
||
display: none; /* shown only ≤640px */
|
||
flex: 1;
|
||
min-width: 0;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 0.5rem;
|
||
min-height: 38px;
|
||
padding: 0.34rem 0.7rem;
|
||
background: var(--bg-secondary);
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
font-family: var(--font-ui);
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.sectionNavMenuCur {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.45rem;
|
||
min-width: 0;
|
||
}
|
||
|
||
.sectionNavMenuEyebrow {
|
||
flex: none;
|
||
font-size: 0.64rem;
|
||
font-weight: 600;
|
||
letter-spacing: 0.04em;
|
||
text-transform: uppercase;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.sectionNavMenuNow {
|
||
font-size: 0.85rem;
|
||
font-weight: 600;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.sectionNavMenuChev {
|
||
flex: none;
|
||
color: var(--text-muted);
|
||
font-size: 0.7rem;
|
||
}
|
||
|
||
/* Compact icon version of the Compare CTA, used on mobile. */
|
||
.sectionNavCompareIcon {
|
||
display: none; /* shown only ≤640px */
|
||
position: relative;
|
||
flex: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 38px;
|
||
height: 38px;
|
||
border-radius: 9px;
|
||
border: 1px solid var(--brand-strong);
|
||
background: var(--brand-strong);
|
||
color: var(--brand-on);
|
||
cursor: pointer;
|
||
transition: background 0.15s ease, border-color 0.15s ease;
|
||
}
|
||
|
||
.sectionNavCompareIcon svg {
|
||
width: 19px;
|
||
height: 19px;
|
||
}
|
||
|
||
.sectionNavCompareBadge {
|
||
position: absolute;
|
||
top: -5px;
|
||
right: -5px;
|
||
width: 16px;
|
||
height: 16px;
|
||
border-radius: 50%;
|
||
background: var(--bg-card);
|
||
color: var(--brand-strong);
|
||
border: 1.5px solid var(--brand);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 0.7rem;
|
||
font-weight: 800;
|
||
line-height: 1;
|
||
}
|
||
|
||
.sectionNavCompareIconIn {
|
||
background: var(--bg-card);
|
||
border-color: var(--brand);
|
||
color: var(--brand);
|
||
}
|
||
|
||
/* Compare CTA carried into the bar once the hero's button scrolls away. */
|
||
.sectionNavCompare {
|
||
flex: none;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
padding: 0.34rem 0.7rem;
|
||
font-size: 0.75rem;
|
||
font-weight: 600;
|
||
color: var(--brand-on);
|
||
background: var(--brand-strong);
|
||
border: 1px solid var(--brand-strong);
|
||
border-radius: 999px;
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
transition: all 0.15s ease;
|
||
}
|
||
|
||
.sectionNavCompare:hover {
|
||
background: var(--brand-stronger);
|
||
border-color: var(--brand-stronger);
|
||
}
|
||
|
||
.sectionNavCompareIn {
|
||
background: var(--bg-card);
|
||
color: var(--brand);
|
||
border-color: var(--brand);
|
||
}
|
||
|
||
.sectionNavCompareIn:hover {
|
||
background: var(--bg-secondary);
|
||
border-color: var(--brand);
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.sectionNavCompare {
|
||
min-height: 36px;
|
||
}
|
||
}
|
||
|
||
/* "All ▾" jump menu (desktop). */
|
||
.sectionNavAll {
|
||
flex: none;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.25rem;
|
||
padding: 0.34rem 0.65rem;
|
||
font-size: 0.75rem;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
background: var(--bg-secondary);
|
||
border: none;
|
||
border-radius: 999px;
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
transition: background 0.15s ease;
|
||
}
|
||
|
||
.sectionNavAll:hover {
|
||
background: var(--border);
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.sectionNavAll {
|
||
min-height: 36px;
|
||
}
|
||
}
|
||
|
||
.sectionsBackdrop {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 1500;
|
||
background: rgba(var(--shadow-rgb), 0.28);
|
||
}
|
||
|
||
.sectionsPanel {
|
||
position: absolute;
|
||
top: calc(100% + 6px);
|
||
right: 0;
|
||
z-index: 1600;
|
||
width: 230px;
|
||
max-height: min(70vh, 460px);
|
||
overflow-y: auto;
|
||
background: var(--bg-card);
|
||
border: 1px solid var(--border);
|
||
border-radius: 12px;
|
||
box-shadow: 0 18px 44px rgba(var(--shadow-rgb), 0.2);
|
||
padding: 0.35rem;
|
||
}
|
||
|
||
.sectionsPanelHead {
|
||
font-family: var(--font-display);
|
||
font-size: 0.9rem;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
padding: 0.4rem 0.6rem 0.5rem;
|
||
}
|
||
|
||
.sectionsItem {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 0.5rem;
|
||
padding: 0.55rem 0.6rem;
|
||
border-radius: 8px;
|
||
font-size: 0.85rem;
|
||
color: var(--text-secondary);
|
||
text-decoration: none;
|
||
transition: background 0.12s ease;
|
||
}
|
||
|
||
.sectionsItem:hover {
|
||
background: var(--bg-secondary);
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.sectionsItemActive {
|
||
background: var(--brand-bg);
|
||
color: var(--brand-strong);
|
||
font-weight: 600;
|
||
}
|
||
|
||
.sectionsTick {
|
||
color: var(--brand-strong);
|
||
}
|
||
|
||
/* On phones the menu becomes a bottom sheet. */
|
||
@media (max-width: 640px) {
|
||
.sectionsPanel {
|
||
position: fixed;
|
||
top: auto;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
width: auto;
|
||
max-height: 74vh;
|
||
border-radius: 16px 16px 0 0;
|
||
padding: 0.5rem 0.6rem calc(0.8rem + env(safe-area-inset-bottom, 0));
|
||
box-shadow: 0 -10px 40px rgba(var(--shadow-rgb), 0.25);
|
||
}
|
||
|
||
.sectionsItem {
|
||
padding: 0.7rem 0.6rem;
|
||
font-size: 0.9rem;
|
||
}
|
||
}
|
||
|
||
/* Swap which controls show at the mobile breakpoint. Declared last so these
|
||
display rules win over the base (equal-specificity) declarations above. */
|
||
@media (max-width: 640px) {
|
||
.sectionNavLinks,
|
||
.sectionNavCompare,
|
||
.sectionNavAll,
|
||
.sectionNavBackLabel {
|
||
display: none;
|
||
}
|
||
|
||
.sectionNavMenu {
|
||
display: flex;
|
||
}
|
||
|
||
.sectionNavCompareIcon {
|
||
display: inline-flex;
|
||
}
|
||
}
|
||
|
||
/* Unified card for all content sections */
|
||
.card {
|
||
background: var(--bg-card);
|
||
border: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
padding: 1.25rem 1.5rem;
|
||
margin-bottom: 1rem;
|
||
box-shadow: var(--shadow-soft);
|
||
scroll-margin-top: 6rem;
|
||
min-width: 0;
|
||
max-width: 100%;
|
||
}
|
||
|
||
/* Section Title */
|
||
.sectionTitle {
|
||
font-size: 1.125rem;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
margin-bottom: 0.875rem;
|
||
padding-bottom: 0.5rem;
|
||
border-bottom: 2px solid var(--border);
|
||
font-family: var(--font-display);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.375rem;
|
||
flex-wrap: wrap;
|
||
overflow-wrap: break-word;
|
||
min-width: 0;
|
||
}
|
||
|
||
.sectionTitle::before {
|
||
content: "";
|
||
display: inline-block;
|
||
width: 3px;
|
||
height: 1em;
|
||
background: var(--brand);
|
||
border-radius: 2px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.sectionSubtitle {
|
||
font-size: 0.85rem;
|
||
color: var(--text-muted);
|
||
margin: -0.5rem 0 1rem;
|
||
}
|
||
|
||
.subSectionTitle {
|
||
font-size: 0.875rem;
|
||
font-weight: 600;
|
||
color: var(--text-secondary);
|
||
margin: 1.25rem 0 0.75rem;
|
||
}
|
||
|
||
/* Metrics Grid & Cards */
|
||
.metricsGrid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.metricCard {
|
||
background: var(--bg-secondary);
|
||
border: 1px solid var(--border);
|
||
border-radius: 6px;
|
||
padding: 0.75rem;
|
||
text-align: center;
|
||
}
|
||
|
||
.metricLabel {
|
||
font-size: 0.6875rem;
|
||
color: var(--text-muted);
|
||
margin-bottom: 0.25rem;
|
||
font-weight: 500;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.03em;
|
||
}
|
||
|
||
.metricValue {
|
||
font-variant-numeric: tabular-nums;
|
||
font-size: 1.25rem;
|
||
font-weight: 700;
|
||
color: var(--text-primary);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 0.25rem;
|
||
overflow-wrap: break-word;
|
||
word-break: break-word;
|
||
}
|
||
|
||
.metricHint {
|
||
font-size: 0.7rem;
|
||
color: var(--text-muted);
|
||
margin-top: 0.3rem;
|
||
font-style: italic;
|
||
}
|
||
|
||
/* ── Hero stat cards (RWM combined, Pupils & Inclusion, etc.) ── */
|
||
/* Larger brand-tinted cards with display-weight numbers — reserved for
|
||
the top-of-section headline metrics. Use .metricCard for denser
|
||
secondary metrics. */
|
||
.heroStatGrid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
gap: 0.85rem;
|
||
margin-bottom: 0.25rem;
|
||
}
|
||
|
||
.heroStatCard {
|
||
font-variant-numeric: tabular-nums;
|
||
background: var(--status-above-bg);
|
||
border: 1px solid rgba(var(--status-above-rgb), 0.2);
|
||
border-radius: 12px;
|
||
padding: 1rem 1.1rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.4rem;
|
||
text-align: left;
|
||
}
|
||
|
||
.heroStatLabel {
|
||
font-size: 0.6rem;
|
||
font-weight: 700;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.08em;
|
||
color: var(--text-muted);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.3rem;
|
||
line-height: 1.3;
|
||
}
|
||
|
||
.heroStatValue {
|
||
font-variant-numeric: tabular-nums;
|
||
font-family: var(--font-display);
|
||
font-size: 2.1rem;
|
||
font-weight: 700;
|
||
line-height: 1;
|
||
color: var(--status-above);
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 0.5rem;
|
||
flex-wrap: wrap;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.heroStatHint {
|
||
font-variant-numeric: tabular-nums;
|
||
font-size: 0.7rem;
|
||
color: var(--text-muted);
|
||
font-style: normal;
|
||
margin-top: 0;
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
.heroStatGrid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.heroStatValue {
|
||
font-size: 1.85rem;
|
||
}
|
||
}
|
||
|
||
/* Progress score colour coding */
|
||
.progressPositive {
|
||
color: var(--status-above);
|
||
font-weight: 700;
|
||
}
|
||
|
||
.progressNegative {
|
||
color: var(--status-below);
|
||
font-weight: 700;
|
||
}
|
||
|
||
/* ── Semantic status colours (unified) ────────────── */
|
||
.statusGood {
|
||
background: var(--status-above-bg);
|
||
color: var(--status-above);
|
||
}
|
||
|
||
.statusWarn {
|
||
background: var(--status-below-bg);
|
||
color: var(--status-below);
|
||
}
|
||
|
||
.statusBad {
|
||
background: var(--status-below-bg);
|
||
color: var(--status-below);
|
||
}
|
||
|
||
/* Charts Section */
|
||
.chartContainer {
|
||
width: 100%;
|
||
/* Taller on desktop so the trend lines have vertical room to separate
|
||
and read clearly. Mobile overrides this to height:auto below (the
|
||
max-width:768px query), so this only affects desktop. */
|
||
height: 380px;
|
||
position: relative;
|
||
}
|
||
|
||
/* Detailed Metrics - Compact Grid Layout */
|
||
.metricGroupsGrid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 1rem;
|
||
}
|
||
|
||
.metricGroup {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.metricGroupTitle {
|
||
font-size: 0.875rem;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
margin-bottom: 0.5rem;
|
||
padding-bottom: 0.375rem;
|
||
border-bottom: 1px solid var(--border);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.375rem;
|
||
}
|
||
|
||
.metricTable {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.375rem;
|
||
}
|
||
|
||
.metricRow {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 0.375rem 0.625rem;
|
||
background: var(--bg-secondary);
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.metricName {
|
||
font-size: 0.75rem;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.metricRow .metricValue {
|
||
font-size: 0.875rem;
|
||
font-weight: 600;
|
||
color: var(--status-above);
|
||
}
|
||
|
||
/* History Table */
|
||
.tableWrapper {
|
||
overflow-x: auto;
|
||
max-width: 100%;
|
||
margin-top: 0.5rem;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
.historicalSubtitle {
|
||
font-size: 0.8rem;
|
||
color: var(--text-muted);
|
||
margin: 1.25rem 0 0.25rem;
|
||
}
|
||
|
||
.dataTable {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
font-size: 0.8125rem;
|
||
}
|
||
|
||
.dataTable thead {
|
||
background: var(--bg-secondary);
|
||
}
|
||
|
||
.dataTable th {
|
||
padding: 0.625rem 0.75rem;
|
||
text-align: left;
|
||
font-weight: 600;
|
||
font-size: 0.6875rem;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.03em;
|
||
color: var(--text-primary);
|
||
border-bottom: 2px solid var(--border);
|
||
}
|
||
|
||
.dataTable td {
|
||
padding: 0.5rem 0.75rem;
|
||
border-bottom: 1px solid var(--border);
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.dataTable tbody tr:last-child td {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.dataTable tbody tr:hover {
|
||
background: var(--bg-secondary);
|
||
}
|
||
|
||
.yearCell {
|
||
font-weight: 600;
|
||
color: var(--status-below);
|
||
}
|
||
|
||
/* Ofsted */
|
||
.ofstedHeader {
|
||
display: flex;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
gap: 0.75rem;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.ofstedGrade {
|
||
display: inline-block;
|
||
padding: 0.35rem 0.75rem;
|
||
font-size: 1rem;
|
||
line-height: 1.4;
|
||
font-weight: 700;
|
||
border-radius: 6px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.ofstedGrade1 {
|
||
background: var(--status-above-bg);
|
||
color: var(--status-above);
|
||
}
|
||
.ofstedGrade2 {
|
||
background: rgba(var(--status-above-rgb), 0.12);
|
||
color: var(--status-above);
|
||
}
|
||
.ofstedGrade3 {
|
||
background: var(--status-below-bg);
|
||
color: var(--status-below);
|
||
}
|
||
.ofstedGrade4 {
|
||
background: var(--status-below);
|
||
color: var(--text-inverse);
|
||
}
|
||
|
||
/* Report Card grade colours (5-level scale, lower = better) */
|
||
.rcGrade1 {
|
||
background: var(--status-above-bg);
|
||
color: var(--status-above);
|
||
} /* Exceptional */
|
||
.rcGrade2 {
|
||
background: rgba(var(--status-above-rgb), 0.12);
|
||
color: var(--status-above);
|
||
} /* Strong */
|
||
.rcGrade3 {
|
||
background: var(--status-below-bg);
|
||
color: var(--status-below);
|
||
} /* Expected standard */
|
||
.rcGrade4 {
|
||
background: rgba(var(--status-below-rgb), 0.12);
|
||
color: var(--status-below);
|
||
} /* Needs attention */
|
||
.rcGrade5 {
|
||
background: var(--status-below);
|
||
color: var(--text-inverse);
|
||
} /* Urgent improvement */
|
||
|
||
/* Safeguarding value (used inside a standard metricCard) */
|
||
.safeguardingMet {
|
||
display: inline-block;
|
||
padding: 0.2rem 0.6rem;
|
||
border-radius: 4px;
|
||
font-size: 0.8125rem;
|
||
font-weight: 600;
|
||
background: var(--status-above-bg);
|
||
color: var(--status-above);
|
||
}
|
||
.safeguardingNotMet {
|
||
display: inline-block;
|
||
padding: 0.2rem 0.6rem;
|
||
border-radius: 4px;
|
||
font-size: 0.8125rem;
|
||
font-weight: 700;
|
||
background: var(--brand-bg);
|
||
color: var(--brand-strong);
|
||
}
|
||
|
||
/* ── 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 {
|
||
font-size: 0.8rem;
|
||
color: var(--text-muted);
|
||
font-style: italic;
|
||
margin: 0 0 1rem;
|
||
}
|
||
|
||
.ofstedDate {
|
||
font-size: 0.85rem;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.ofstedPrevious {
|
||
font-size: 0.8125rem;
|
||
color: var(--text-muted);
|
||
font-style: italic;
|
||
}
|
||
|
||
.ofstedReportLink {
|
||
font-size: 0.8125rem;
|
||
color: var(--brand);
|
||
text-decoration: none;
|
||
margin-left: auto;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.ofstedReportLink:hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
/* Admissions badge — uses unified status colours */
|
||
.admissionsBadge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.35rem;
|
||
padding: 0.3rem 0.75rem;
|
||
border-radius: 6px;
|
||
font-size: 0.8125rem;
|
||
font-weight: 600;
|
||
margin-top: 0.75rem;
|
||
}
|
||
|
||
/* Deprivation dot scale */
|
||
.deprivationDots {
|
||
display: flex;
|
||
gap: 0.375rem;
|
||
margin: 0.75rem 0 0.5rem;
|
||
align-items: center;
|
||
}
|
||
|
||
.deprivationDot {
|
||
width: 1.25rem;
|
||
height: 1.25rem;
|
||
border-radius: 50%;
|
||
background: var(--bg-secondary);
|
||
border: 2px solid var(--border);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.deprivationDotFilled {
|
||
background: var(--brand);
|
||
border-color: var(--brand);
|
||
}
|
||
|
||
.deprivationDesc {
|
||
font-size: 0.875rem;
|
||
color: var(--text-secondary);
|
||
line-height: 1.5;
|
||
margin: 0;
|
||
}
|
||
|
||
.deprivationScaleLabel {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
font-size: 0.7rem;
|
||
color: var(--text-muted);
|
||
margin-top: 0.25rem;
|
||
}
|
||
|
||
/* Progress note */
|
||
.ofstedAllSame {
|
||
font-size: 0.9375rem;
|
||
color: var(--text-secondary);
|
||
margin: 0.5rem 0 0;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.ofstedAllSame strong {
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.progressNote {
|
||
margin-top: 0.75rem;
|
||
font-size: 0.8rem;
|
||
color: var(--text-muted);
|
||
font-style: italic;
|
||
}
|
||
|
||
/* ── Responsive ──────────────────────────────────────── */
|
||
@media (max-width: 768px) {
|
||
.headerContent {
|
||
flex-direction: column;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.actions {
|
||
width: 100%;
|
||
}
|
||
|
||
.btnAdd,
|
||
.btnRemove {
|
||
flex: 1;
|
||
}
|
||
|
||
.schoolName {
|
||
font-size: 1.25rem;
|
||
word-break: break-word;
|
||
}
|
||
|
||
/* Pills wrap horizontally instead of stacking — short tokens like
|
||
"Manchester" / "Voluntary aided" fit 2 per row instead of 3 full
|
||
rows of empty horizontal space. */
|
||
.meta {
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
gap: 0.375rem;
|
||
}
|
||
|
||
/* Secondary header info (headteacher, website, pupil count, trust,
|
||
contact, area) isn't needed above the fold on phones/tablets, so it's
|
||
collapsed by default and revealed on demand via the "Show all details"
|
||
link — reclaiming the vertical space so the metrics surface sooner. */
|
||
.detailsToggle {
|
||
display: inline-flex;
|
||
}
|
||
|
||
.headerDetails {
|
||
display: none;
|
||
}
|
||
|
||
.headerDetailsOpen {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.375rem;
|
||
}
|
||
|
||
.metricsGrid {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
|
||
.metricGroupsGrid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
/* PerformanceChart on mobile now stacks: trend banner → chip subtitle →
|
||
chip row → canvas → mini-legend → COVID footnote. The container must
|
||
flow naturally instead of clipping to a fixed 220px — PerformanceChart's
|
||
own .chartWrapper carries the canvas height. */
|
||
.chartContainer {
|
||
height: auto;
|
||
}
|
||
|
||
.dataTable {
|
||
font-size: 0.75rem;
|
||
}
|
||
|
||
.dataTable th,
|
||
.dataTable td {
|
||
padding: 0.5rem 0.375rem;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
.card {
|
||
padding: 1rem;
|
||
}
|
||
}
|
||
|
||
/* .heroStatLabel is shared by the SATs / Pupils stat cards below. */
|
||
.heroStatLabel {
|
||
font-size: 0.6875rem;
|
||
font-weight: 600;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.heroSummary {
|
||
font-size: 1rem;
|
||
margin-top: 1rem;
|
||
}
|
||
}
|
||
|
||
/* ── RWM bridge ("Why is combined lower?") ── */
|
||
.rwmBridge {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 0.75rem;
|
||
margin: 0.5rem 0 1.5rem;
|
||
padding: 0.9rem 1rem;
|
||
background: var(--bg-secondary);
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.rwmBridgeIcon {
|
||
flex-shrink: 0;
|
||
width: 22px;
|
||
height: 22px;
|
||
border-radius: 50%;
|
||
background: var(--brand);
|
||
color: var(--text-inverse);
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-weight: 700;
|
||
font-size: 0.8rem;
|
||
font-family: var(--font-display);
|
||
margin-top: 0.05rem;
|
||
}
|
||
|
||
.rwmBridgeBody {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.rwmBridgeText {
|
||
font-size: 0.85rem;
|
||
color: var(--text-secondary);
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.rwmBridgeText strong {
|
||
color: var(--text-primary);
|
||
font-weight: 700;
|
||
}
|
||
|
||
.rwmBridgeMath {
|
||
display: flex;
|
||
gap: 0.35rem;
|
||
margin-top: 0.35rem;
|
||
flex-wrap: wrap;
|
||
font-family: var(--font-display);
|
||
color: var(--text-muted);
|
||
font-size: 0.78rem;
|
||
font-style: italic;
|
||
align-items: baseline;
|
||
}
|
||
|
||
.rwmBridgeMath strong {
|
||
color: var(--text-primary);
|
||
font-weight: 700;
|
||
font-style: normal;
|
||
}
|
||
|
||
.rwmBridgeMathSep {
|
||
opacity: 0.5;
|
||
}
|
||
|
||
/* ── Progress scores row (below SatsChart) ── */
|
||
.progressScoresRow {
|
||
margin-top: 1.25rem;
|
||
padding-top: 1rem;
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
|
||
.progressScoresGrid {
|
||
display: flex;
|
||
gap: 1.5rem;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.progressScoreItem {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 0.4rem;
|
||
}
|
||
|
||
.progressScoreLabel {
|
||
font-size: 0.78rem;
|
||
font-weight: 500;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.progressScoreValue {
|
||
font-variant-numeric: tabular-nums;
|
||
font-size: 0.9rem;
|
||
font-weight: 700;
|
||
color: var(--text-primary);
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
/* ── Admissions Q&A list ── */
|
||
/* 2×2 stat tiles — number and label grouped together so the eye
|
||
doesn't travel the full card width. Hairline grid via gap + bg. */
|
||
.admissionsTiles {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 1px;
|
||
background: var(--border);
|
||
border: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
overflow: hidden;
|
||
margin: 0;
|
||
}
|
||
|
||
.admissionsTile {
|
||
background: var(--bg-card);
|
||
padding: 1.15rem 1.25rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.admissionsTileNum {
|
||
font-variant-numeric: tabular-nums;
|
||
font-family: var(--font-display);
|
||
font-size: 2.4rem;
|
||
font-weight: 700;
|
||
line-height: 1;
|
||
color: var(--text-primary);
|
||
font-variant-numeric: tabular-nums;
|
||
margin: 0;
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 0.4rem;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.admissionsTileSub {
|
||
font-family: var(--font-ui);
|
||
font-size: 0.85rem;
|
||
font-weight: 500;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.admissionsTileLabel {
|
||
margin: 0.55rem 0 0;
|
||
font-size: 0.78rem;
|
||
font-weight: 600;
|
||
letter-spacing: 0.04em;
|
||
text-transform: uppercase;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.admissionsTileAccent .admissionsTileNum {
|
||
color: var(--brand-strong);
|
||
}
|
||
|
||
.admissionsVerdict {
|
||
margin-top: 0.75rem;
|
||
margin-bottom: 0.25rem;
|
||
}
|
||
|
||
.admissionsVerdictHeadline {
|
||
font-family: var(--font-display);
|
||
font-size: 1.35rem;
|
||
font-weight: 700;
|
||
line-height: 1.2;
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.admissionsVerdictOver {
|
||
color: var(--brand-strong);
|
||
}
|
||
|
||
.admissionsVerdictUnder {
|
||
color: var(--status-above);
|
||
}
|
||
|
||
.admissionsVerdictSub {
|
||
font-size: 0.8rem;
|
||
color: var(--text-muted);
|
||
line-height: 1.4;
|
||
margin-top: 0.2rem;
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
.admissionsTile {
|
||
padding: 0.95rem 1rem;
|
||
}
|
||
|
||
.admissionsTileNum {
|
||
font-size: 2rem;
|
||
}
|
||
}
|
||
|
||
/* ── Admissions: header + view toggle ── */
|
||
.admissionsHeader {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 1rem;
|
||
flex-wrap: wrap;
|
||
margin-bottom: 1.25rem;
|
||
}
|
||
|
||
.admissionsHeader .sectionTitle {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.admissionsSeg {
|
||
display: inline-flex;
|
||
background: var(--bg-secondary);
|
||
border-radius: 999px;
|
||
padding: 3px;
|
||
gap: 2px;
|
||
flex: none;
|
||
}
|
||
|
||
.admissionsSeg button {
|
||
appearance: none;
|
||
border: none;
|
||
background: none;
|
||
cursor: pointer;
|
||
font: inherit;
|
||
font-size: 0.8125rem;
|
||
font-weight: 600;
|
||
color: var(--text-muted);
|
||
padding: 0.4rem 0.9rem;
|
||
border-radius: 999px;
|
||
white-space: nowrap;
|
||
transition: background 0.15s ease, color 0.15s ease;
|
||
}
|
||
|
||
.admissionsSeg button[aria-pressed="true"] {
|
||
background: var(--bg-card);
|
||
color: var(--text-primary);
|
||
box-shadow: var(--shadow-soft, 0 2px 8px rgba(var(--shadow-rgb), 0.06));
|
||
}
|
||
|
||
.admissionsSeg button:hover[aria-pressed="false"] {
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
/* Stack both views in one grid cell so the card sizes to the taller view —
|
||
toggling modes never shifts layout. */
|
||
.admissionsViewport {
|
||
display: grid;
|
||
}
|
||
|
||
.admissionsViewYear,
|
||
.admissionsViewTrend {
|
||
grid-area: 1 / 1;
|
||
}
|
||
|
||
.admissionsViewYear[hidden],
|
||
.admissionsViewTrend[hidden] {
|
||
display: block;
|
||
visibility: hidden;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* The tile grid fills the height reserved by the taller (trend) view. */
|
||
.admissionsViewYear {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.admissionsViewYear .admissionsTiles {
|
||
flex: 1;
|
||
grid-template-rows: 1fr 1fr;
|
||
}
|
||
|
||
.admissionsChartCap {
|
||
font-size: 0.8125rem;
|
||
font-weight: 600;
|
||
letter-spacing: 0.04em;
|
||
text-transform: uppercase;
|
||
color: var(--text-muted);
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.admissionsTrendSummary {
|
||
font-size: 1rem;
|
||
color: var(--text-secondary);
|
||
margin: 1.25rem 0 0;
|
||
padding-top: 1.1rem;
|
||
border-top: 1px solid var(--border);
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.admissionsTrendSummary strong {
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
/* ── History accordion ── */
|
||
.historyDisclosure {
|
||
margin-top: 1rem;
|
||
}
|
||
|
||
.historyToggle {
|
||
font-size: 0.8125rem;
|
||
font-weight: 600;
|
||
color: var(--text-muted);
|
||
cursor: pointer;
|
||
padding: 0.5rem 0;
|
||
list-style: none;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
user-select: none;
|
||
}
|
||
|
||
.historyToggle::-webkit-details-marker {
|
||
display: none;
|
||
}
|
||
|
||
.historyToggle::before {
|
||
content: "▸";
|
||
display: inline-block;
|
||
transition: transform 0.2s ease;
|
||
font-size: 0.7rem;
|
||
}
|
||
|
||
.historyDisclosure[open] > .historyToggle::before {
|
||
transform: rotate(90deg);
|
||
}
|
||
|
||
/* GIAS "Open, but proposed to close" notice strip */
|
||
.closingStrip {
|
||
background: var(--status-below-bg);
|
||
border-left: 4px solid var(--status-below-bg);
|
||
border-radius: 0 6px 6px 0;
|
||
padding: 0.55rem 0.9rem;
|
||
margin: 0.5rem 0;
|
||
font-size: 0.88rem;
|
||
color: var(--status-below);
|
||
max-width: 68ch;
|
||
}
|
||
.closingStrip strong {
|
||
color: var(--status-below);
|
||
}
|
||
/* ── Secondary-only rules, merged from SecondarySchoolDetailView.module.css ── */
|
||
.badges {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.375rem;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
.badge {
|
||
font-size: 0.8125rem;
|
||
color: var(--text-secondary);
|
||
padding: 0.125rem 0.5rem;
|
||
background: var(--bg-secondary);
|
||
border-radius: 3px;
|
||
}
|
||
.badgeSelective {
|
||
background: rgba(var(--status-below-rgb), 0.1);
|
||
color: var(--status-below);
|
||
}
|
||
.badgeFaith {
|
||
background: rgba(var(--status-above-rgb), 0.1);
|
||
color: var(--phase-secondary-text);
|
||
}
|
||
/* ── Tab Navigation (sticky) ─────────────────────────── */
|
||
.tabNav {
|
||
position: sticky;
|
||
top: 4rem;
|
||
z-index: 10;
|
||
background: var(--bg-card);
|
||
border: 1px solid var(--border);
|
||
border-top: none;
|
||
border-radius: 0 0 10px 10px;
|
||
padding: 0.5rem 1rem;
|
||
margin-bottom: 1rem;
|
||
overflow-x: auto;
|
||
white-space: nowrap;
|
||
-webkit-overflow-scrolling: touch;
|
||
scrollbar-width: none;
|
||
box-shadow: 0 2px 4px rgba(var(--shadow-rgb), 0.04);
|
||
}
|
||
.tabNav::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
.tabNavInner {
|
||
display: inline-flex;
|
||
gap: 0.25rem;
|
||
align-items: center;
|
||
}
|
||
.backBtn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
padding: 0.3rem 0.625rem;
|
||
font-size: 0.75rem;
|
||
font-weight: 600;
|
||
color: var(--brand-strong);
|
||
background: none;
|
||
border: 1px solid var(--border);
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
transition: all 0.15s ease;
|
||
margin-right: 0.25rem;
|
||
}
|
||
.backBtn:hover {
|
||
background: var(--bg-secondary);
|
||
border-color: var(--brand);
|
||
}
|
||
.tabNavDivider {
|
||
width: 1px;
|
||
height: 1rem;
|
||
background: var(--border);
|
||
margin: 0 0.25rem;
|
||
flex-shrink: 0;
|
||
}
|
||
.tabBtn {
|
||
display: inline-block;
|
||
padding: 0.3rem 0.75rem;
|
||
font-size: 0.75rem;
|
||
font-weight: 500;
|
||
color: var(--text-secondary);
|
||
background: none;
|
||
border: none;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
transition: all 0.15s ease;
|
||
white-space: nowrap;
|
||
text-decoration: none;
|
||
}
|
||
.tabBtn:hover {
|
||
background: var(--bg-secondary);
|
||
color: var(--text-primary);
|
||
}
|
||
.tabBtnActive {
|
||
background: var(--brand-strong);
|
||
color: var(--brand-on);
|
||
font-weight: 600;
|
||
}
|
||
.tabBtnActive:hover {
|
||
background: var(--brand-stronger);
|
||
color: var(--brand-on);
|
||
}
|
||
/* ── Progress 8 suspension banner ───────────────────── */
|
||
.p8Banner {
|
||
background: rgba(var(--status-below-rgb), 0.1);
|
||
border: 1px solid rgba(var(--status-below-rgb), 0.3);
|
||
color: var(--status-below);
|
||
border-radius: 6px;
|
||
padding: 0.625rem 0.875rem;
|
||
font-size: 0.825rem;
|
||
margin-bottom: 1rem;
|
||
line-height: 1.5;
|
||
}
|
||
/* ── Admissions ──────────────────────────────────────── */
|
||
.admissionsTypeBadge {
|
||
border-radius: 6px;
|
||
padding: 0.5rem 0.875rem;
|
||
font-size: 0.8125rem;
|
||
margin-bottom: 1rem;
|
||
line-height: 1.5;
|
||
}
|
||
.admissionsSelective {
|
||
background: rgba(var(--status-below-rgb), 0.1);
|
||
color: var(--status-below);
|
||
border: 1px solid rgba(var(--status-below-rgb), 0.25);
|
||
}
|
||
.admissionsFaith {
|
||
background: rgba(var(--status-above-rgb), 0.08);
|
||
color: var(--phase-secondary-text);
|
||
border: 1px solid rgba(var(--status-above-rgb), 0.2);
|
||
}
|
||
.sixthFormNote {
|
||
margin-top: 1rem;
|
||
padding: 0.625rem 0.875rem;
|
||
background: var(--bg-secondary);
|
||
border-radius: 6px;
|
||
font-size: 0.825rem;
|
||
color: var(--text-secondary);
|
||
border-left: 3px solid var(--brand);
|
||
}
|
||
.genderSplitHint {
|
||
font-size: 0.7rem;
|
||
color: var(--text-muted);
|
||
margin-top: 0.35rem;
|
||
font-weight: 500;
|
||
}
|
||
/* ── Attainment 8 visual bar ─────────────────────────── */
|
||
.att8Viz {
|
||
margin: 1.25rem 0 0.5rem;
|
||
}
|
||
.att8VizLabel {
|
||
font-size: 0.6875rem;
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.07em;
|
||
color: var(--text-muted);
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
.att8VizTrack {
|
||
position: relative;
|
||
height: 14px;
|
||
background: rgba(var(--status-above-rgb), 0.08);
|
||
border: 1px solid var(--border);
|
||
border-radius: 4px;
|
||
overflow: visible;
|
||
}
|
||
.att8VizFill {
|
||
height: 100%;
|
||
background: var(--brand);
|
||
border-radius: 4px 0 0 4px;
|
||
transition: width 0.6s ease;
|
||
}
|
||
/*
|
||
* Knockout, for the same reason as .natTick in SatsChart.module.css: this was
|
||
* var(--brand), identical to .att8VizFill above it, so where the marker
|
||
* crossed the school's own bar it measured 1.00:1 — invisible for exactly the
|
||
* schools at or above the national average.
|
||
*
|
||
* A light core with a dark edge reads on the teal fill and on the pale track
|
||
* alike, and both tokens flip with the theme. Keep this in step with
|
||
* SatsChart's .natTick; they are the same marker on two templates.
|
||
*/
|
||
.att8VizNatLine {
|
||
position: absolute;
|
||
top: -4px;
|
||
bottom: -4px;
|
||
width: 3px;
|
||
background: var(--bg-card);
|
||
box-shadow: 0 0 0 1px var(--text-primary);
|
||
border-radius: 2px;
|
||
z-index: 2;
|
||
}
|
||
.att8VizNatPill {
|
||
position: absolute;
|
||
top: -20px;
|
||
transform: translateX(-50%);
|
||
background: var(--brand-strong);
|
||
color: var(--text-inverse);
|
||
font-size: 0.6rem;
|
||
font-weight: 700;
|
||
padding: 0.1rem 0.3rem;
|
||
border-radius: 3px;
|
||
white-space: nowrap;
|
||
}
|
||
.att8VizTicks {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-top: 0.25rem;
|
||
font-size: 0.6rem;
|
||
color: var(--text-muted);
|
||
}
|
||
/* ── Progress 8 number line ──────────────────────────── */
|
||
.p8Viz {
|
||
margin: 1.25rem 0 0.5rem;
|
||
}
|
||
.p8VizLabel {
|
||
font-size: 0.6875rem;
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.07em;
|
||
color: var(--text-muted);
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
.p8VizTrack {
|
||
position: relative;
|
||
height: 14px;
|
||
background: rgba(var(--status-above-rgb), 0.06);
|
||
border: 1px solid var(--border);
|
||
border-radius: 4px;
|
||
overflow: visible;
|
||
}
|
||
.p8VizCi {
|
||
position: absolute;
|
||
top: 0;
|
||
bottom: 0;
|
||
background: rgba(var(--status-above-rgb), 0.18);
|
||
border-radius: 3px;
|
||
}
|
||
.p8VizZero {
|
||
position: absolute;
|
||
top: -4px;
|
||
bottom: -4px;
|
||
width: 2px;
|
||
background: var(--border);
|
||
z-index: 1;
|
||
}
|
||
.p8VizDot {
|
||
position: absolute;
|
||
top: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 12px;
|
||
height: 12px;
|
||
border-radius: 50%;
|
||
background: var(--brand);
|
||
border: 2px solid white;
|
||
box-shadow: 0 1px 4px rgba(var(--shadow-rgb), 0.2);
|
||
z-index: 3;
|
||
}
|
||
.p8VizDotNeg {
|
||
background: var(--brand);
|
||
}
|
||
.p8VizTicks {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-top: 0.25rem;
|
||
font-size: 0.6rem;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
/* ── Secondary variants ───────────────────────────────────────────────────
|
||
Three rules differ between the primary and secondary detail pages in ways
|
||
that are genuinely visual rather than incidental drift. Rather than pick a
|
||
winner (which would change one of the two pages) they are kept as explicit
|
||
variant classes, so the divergence is deliberate and reviewable instead of
|
||
accidental. Sections select them via a `variant` prop. */
|
||
|
||
/* Secondary renders a slimmer gender bar on a translucent track. */
|
||
.genderBarSecondary {
|
||
height: 4px;
|
||
background: var(--border);
|
||
margin-top: 0.45rem;
|
||
}
|
||
|
||
/* Secondary emphasises the split figures. */
|
||
.genderSplitBoysSecondary {
|
||
font-weight: 600;
|
||
}
|
||
|
||
.genderSplitGirlsSecondary {
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* Secondary hero stats sit tighter and omit the Georgia fallback. */
|
||
.heroStatValueSecondary {
|
||
font-variant-numeric: tabular-nums;
|
||
gap: 0.4rem;
|
||
font-family: var(--font-display);
|
||
}
|
||
|
||
/* ── Secondary-scoped overrides ──────────────────────────────────────────
|
||
These rules exist only in the secondary stylesheet but target class names
|
||
the primary page also uses (.card, .sectionTitle, .metricCard …). Applied
|
||
flat they would restyle the primary page, so they are scoped to a wrapper
|
||
class that only SecondarySchoolSections carries. Same principle as the
|
||
variant classes above, applied at rule scope. */
|
||
|
||
.secondaryScope .heroStatCard .heroStatLabel { font-size: 0.6rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); }
|
||
.secondaryScope .heroStatCard .heroStatValue { font-family: var(--font-display); font-size: 2.1rem; font-weight: 700; line-height: 1; color: var(--status-above); display: flex; align-items: baseline; gap: 0.4rem; flex-wrap: wrap; }
|
||
.secondaryScope .heroStatCard .heroStatHint { font-size: 0.7rem; color: var(--text-muted); font-style: normal; margin-top: 0; }
|
||
.secondaryScope .historyDisclosure[open] .historyToggle::before { transform: rotate(90deg); }
|
||
@media (max-width: 480px) {
|
||
.secondaryScope .metricsGrid { grid-template-columns: 1fr 1fr; gap: 0.5rem; }
|
||
.secondaryScope .metricCard { padding: 0.5rem; }
|
||
.secondaryScope .metricLabel { font-size: 0.625rem; }
|
||
}
|
||
@media (max-width: 768px) {
|
||
.secondaryScope .header { padding: 1rem; }
|
||
.secondaryScope .badges { gap: 0.25rem; }
|
||
.secondaryScope .badge { font-size: 0.75rem; padding: 0.1rem 0.375rem; }
|
||
.secondaryScope .metricValue { font-size: 1rem; }
|
||
.secondaryScope .heroStatGrid { grid-template-columns: 1fr; }
|
||
.secondaryScope .heroStatCard .heroStatValue { font-size: 1.85rem; }
|
||
.secondaryScope .card { padding: 1rem; }
|
||
.secondaryScope .sectionTitle { font-size: 1rem; }
|
||
.secondaryScope .ofstedReportLink { margin-left: 0; display: block; margin-top: 0.25rem; }
|
||
.secondaryScope .admissionsTypeBadge { font-size: 0.75rem; }
|
||
}
|