Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29f79fe948 | ||
|
|
0294038fd3 | ||
|
|
a1fa4fe874 |
+18
-17
@@ -16,8 +16,9 @@
|
|||||||
--text-inverse: #faf7f2;
|
--text-inverse: #faf7f2;
|
||||||
|
|
||||||
--accent-coral: #e07256;
|
--accent-coral: #e07256;
|
||||||
--accent-coral-dark: #c45a3f;
|
--accent-coral-dark: #b04a2e; /* AA: 4.5+ as text on white/cream tints; 5.4:1 under white text */
|
||||||
--accent-teal: #2d7d7d;
|
--accent-coral-darker: #9c3f26; /* hover for coral-dark fills */
|
||||||
|
--accent-teal: #296f6f; /* AA: 4.8+ as text on the cream/tint backgrounds */
|
||||||
--accent-teal-light: #3a9e9e;
|
--accent-teal-light: #3a9e9e;
|
||||||
--accent-gold: #c9a227;
|
--accent-gold: #c9a227;
|
||||||
--accent-gold-text: #7a6800; /* WCAG AA safe for text on white/cream */
|
--accent-gold-text: #7a6800; /* WCAG AA safe for text on white/cream */
|
||||||
@@ -172,13 +173,13 @@ body {
|
|||||||
|
|
||||||
/* Primary: coral background — main CTAs (Search, Compare Now) */
|
/* Primary: coral background — main CTAs (Search, Compare Now) */
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
background: var(--accent-coral);
|
background: var(--accent-coral-dark);
|
||||||
color: white;
|
color: white;
|
||||||
border-color: var(--accent-coral);
|
border-color: var(--accent-coral-dark);
|
||||||
}
|
}
|
||||||
.btn-primary:hover:not(:disabled) {
|
.btn-primary:hover:not(:disabled) {
|
||||||
background: var(--accent-coral-dark);
|
background: var(--accent-coral-darker);
|
||||||
border-color: var(--accent-coral-dark);
|
border-color: var(--accent-coral-darker);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Secondary: teal outline — supporting actions (+ Compare) */
|
/* Secondary: teal outline — supporting actions (+ Compare) */
|
||||||
@@ -210,8 +211,8 @@ body {
|
|||||||
}
|
}
|
||||||
.btn-active:hover:not(:disabled) {
|
.btn-active:hover:not(:disabled) {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--accent-coral);
|
color: var(--accent-coral-dark);
|
||||||
border-color: var(--accent-coral);
|
border-color: var(--accent-coral-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Small variant */
|
/* Small variant */
|
||||||
@@ -745,14 +746,14 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-compare {
|
.btn-compare {
|
||||||
background: var(--accent-coral);
|
background: var(--accent-coral-dark);
|
||||||
color: white;
|
color: white;
|
||||||
border: 1px solid var(--accent-coral);
|
border: 1px solid var(--accent-coral-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-compare:hover {
|
.btn-compare:hover {
|
||||||
background: #d4654a;
|
background: var(--accent-coral-darker);
|
||||||
border-color: #d4654a;
|
border-color: var(--accent-coral-darker);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-compare.active {
|
.btn-compare.active {
|
||||||
@@ -916,7 +917,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.stat-value.negative {
|
.stat-value.negative {
|
||||||
color: var(--accent-coral);
|
color: var(--accent-coral-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Trend indicators */
|
/* Trend indicators */
|
||||||
@@ -930,7 +931,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.trend-down {
|
.trend-down {
|
||||||
color: var(--accent-coral);
|
color: var(--accent-coral-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
.trend-stable {
|
.trend-stable {
|
||||||
@@ -1018,7 +1019,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.map-modal-close:hover {
|
.map-modal-close:hover {
|
||||||
color: var(--accent-coral);
|
color: var(--accent-coral-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
.map-modal-content {
|
.map-modal-content {
|
||||||
@@ -1567,12 +1568,12 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
background: var(--accent-coral);
|
background: var(--accent-coral-dark);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary:hover {
|
.btn-primary:hover {
|
||||||
background: var(--accent-coral-dark);
|
background: var(--accent-coral-darker);
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export default async function RankingsPage({ searchParams }: RankingsPageProps)
|
|||||||
const { metric: metricParam, local_authority, year: yearParam, phase: phaseParam } = await searchParams;
|
const { metric: metricParam, local_authority, year: yearParam, phase: phaseParam } = await searchParams;
|
||||||
|
|
||||||
const phase = phaseParam || 'primary';
|
const phase = phaseParam || 'primary';
|
||||||
const metric = metricParam || (phase === 'secondary' ? 'attainment_8_score' : 'rwm_high_pct');
|
const metric = metricParam || (phase === 'secondary' ? 'attainment_8_score' : 'rwm_expected_pct');
|
||||||
const year = yearParam ? parseInt(yearParam) : undefined;
|
const year = yearParam ? parseInt(yearParam) : undefined;
|
||||||
|
|
||||||
// Fetch rankings data with error handling
|
// Fetch rankings data with error handling
|
||||||
|
|||||||
@@ -196,7 +196,7 @@
|
|||||||
margin-bottom: 0.15rem;
|
margin-bottom: 0.15rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipTrackDeadline { color: var(--accent-coral, #e07256); }
|
.chipTrackDeadline { color: var(--accent-coral-dark, #b04a2e); }
|
||||||
.chipTrackOffer { color: var(--accent-teal, #2d7d7d); }
|
.chipTrackOffer { color: var(--accent-teal, #2d7d7d); }
|
||||||
|
|
||||||
.chipTrackDot {
|
.chipTrackDot {
|
||||||
@@ -278,7 +278,7 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
margin-bottom: 0.35rem;
|
margin-bottom: 0.35rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +399,7 @@
|
|||||||
margin-bottom: 0.2rem;
|
margin-bottom: 0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stepDeadline .stepDate { color: var(--accent-coral, #e07256); }
|
.stepDeadline .stepDate { color: var(--accent-coral-dark, #b04a2e); }
|
||||||
.stepOffer .stepDate { color: var(--accent-teal, #2d7d7d); }
|
.stepOffer .stepDate { color: var(--accent-teal, #2d7d7d); }
|
||||||
|
|
||||||
.stepTitle {
|
.stepTitle {
|
||||||
@@ -472,7 +472,7 @@
|
|||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-playfair), 'Playfair Display', serif;
|
||||||
font-size: 1.75rem;
|
font-size: 1.75rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--border-color, #e5dfd5);
|
color: #7d766b; /* 3.8:1 on cream — AA large-text for this 28px numeral */
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
margin-bottom: 0.6rem;
|
margin-bottom: 0.6rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.removeSchoolBtn:hover {
|
.removeSchoolBtn:hover {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.toastActions {
|
.toastActions {
|
||||||
@@ -145,7 +145,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btnClearAll:hover {
|
.btnClearAll:hover {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btnCompare {
|
.btnCompare {
|
||||||
|
|||||||
@@ -63,13 +63,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.phaseTabActive {
|
.phaseTabActive {
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--accent-coral-dark, #b04a2e);
|
||||||
color: white;
|
color: white;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phaseTabActive:hover {
|
.phaseTabActive:hover {
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--accent-coral-darker, #9c3f26);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Metric Selector */
|
/* Metric Selector */
|
||||||
@@ -198,7 +198,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.schoolName a:hover {
|
.schoolName a:hover {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.schoolMeta {
|
.schoolMeta {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { SchoolSearchModal } from './SchoolSearchModal';
|
|||||||
import { EmptyState } from './EmptyState';
|
import { EmptyState } from './EmptyState';
|
||||||
import { LoadingSkeleton } from './LoadingSkeleton';
|
import { LoadingSkeleton } from './LoadingSkeleton';
|
||||||
import type { ComparisonData, MetricDefinition, School } from '@/lib/types';
|
import type { ComparisonData, MetricDefinition, School } from '@/lib/types';
|
||||||
import { formatPercentage, formatProgress, formatAcademicYear, CHART_COLORS, schoolUrl } from '@/lib/utils';
|
import { formatPercentage, formatProgress, formatAcademicYear, CHART_COLORS, CHART_TEXT_COLORS, schoolUrl } from '@/lib/utils';
|
||||||
import { fetchComparison } from '@/lib/api';
|
import { fetchComparison } from '@/lib/api';
|
||||||
import { track } from '@/lib/analytics';
|
import { track } from '@/lib/analytics';
|
||||||
import styles from './ComparisonView.module.css';
|
import styles from './ComparisonView.module.css';
|
||||||
@@ -58,7 +58,7 @@ export function ComparisonView({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const { selectedSchools, removeSchool, addSchool, isInitialized } = useComparison();
|
const { selectedSchools, removeSchool, addSchool, replaceSchools, isInitialized } = useComparison();
|
||||||
|
|
||||||
const [selectedMetric, setSelectedMetric] = useState(initialMetric);
|
const [selectedMetric, setSelectedMetric] = useState(initialMetric);
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
@@ -69,16 +69,22 @@ export function ComparisonView({
|
|||||||
// While true, auto-phase detection is suppressed so manual selections aren't overridden.
|
// While true, auto-phase detection is suppressed so manual selections aren't overridden.
|
||||||
const phaseLockedByUser = useRef(false);
|
const phaseLockedByUser = useRef(false);
|
||||||
|
|
||||||
// Seed context from initialData when component mounts and localStorage is empty
|
// Seed context from the URL on mount. An explicit ?urns=… (e.g. a link a
|
||||||
|
// parent shared with their partner) always wins over this visitor's stored
|
||||||
|
// selection — otherwise the recipient silently sees their own old schools.
|
||||||
|
// The replacement is then persisted like any other selection change.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isInitialized) return;
|
if (!isInitialized) return;
|
||||||
if (selectedSchools.length === 0 && initialUrns.length > 0 && initialData) {
|
if (initialUrns.length > 0 && initialData) {
|
||||||
initialUrns.forEach(urn => {
|
const urlSchools = initialUrns
|
||||||
const data = initialData[String(urn)];
|
.map(urn => initialData[String(urn)]?.school_info)
|
||||||
if (data?.school_info) {
|
.filter((info): info is NonNullable<typeof info> => Boolean(info));
|
||||||
addSchool(data.school_info);
|
const sameSet =
|
||||||
|
urlSchools.length === selectedSchools.length &&
|
||||||
|
urlSchools.every(s => selectedSchools.some(sel => sel.urn === s.urn));
|
||||||
|
if (urlSchools.length > 0 && !sameSet) {
|
||||||
|
replaceSchools(urlSchools);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, [isInitialized]); // eslint-disable-line react-hooks/exhaustive-deps
|
}, [isInitialized]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
|
||||||
@@ -378,7 +384,8 @@ export function ComparisonView({
|
|||||||
{activeComparisonData[school.urn] && (
|
{activeComparisonData[school.urn] && (
|
||||||
<div className={styles.latestValue}>
|
<div className={styles.latestValue}>
|
||||||
<div className={styles.latestLabel}>{metricLabel}</div>
|
<div className={styles.latestLabel}>{metricLabel}</div>
|
||||||
<div className={styles.latestNumber} style={{ color: CHART_COLORS[index % CHART_COLORS.length] }}>
|
{/* Text uses the AA-dark variant; the swatch dot keeps the true series colour */}
|
||||||
|
<div className={styles.latestNumber} style={{ color: CHART_TEXT_COLORS[index % CHART_TEXT_COLORS.length] }}>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
.bad {
|
.bad {
|
||||||
background: var(--accent-coral-bg, rgba(224, 114, 86, 0.12));
|
background: var(--accent-coral-bg, rgba(224, 114, 86, 0.12));
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.neutral {
|
.neutral {
|
||||||
|
|||||||
@@ -121,7 +121,7 @@
|
|||||||
|
|
||||||
.viewToggleBtn.active {
|
.viewToggleBtn.active {
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card, white);
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
box-shadow: 0 2px 4px rgba(26, 22, 18, 0.08);
|
box-shadow: 0 2px 4px rgba(26, 22, 18, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,7 +222,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.compactItemName:hover {
|
.compactItemName:hover {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.distanceBadge {
|
.distanceBadge {
|
||||||
@@ -536,7 +536,7 @@
|
|||||||
|
|
||||||
.geoError {
|
.geoError {
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
max-width: 340px;
|
max-width: 340px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -567,9 +567,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.quickSearchChip:hover {
|
.quickSearchChip:hover {
|
||||||
background: var(--accent-coral);
|
background: var(--accent-coral-dark);
|
||||||
color: white;
|
color: white;
|
||||||
border-color: var(--accent-coral);
|
border-color: var(--accent-coral-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
.exploringRow {
|
.exploringRow {
|
||||||
@@ -712,7 +712,7 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hiwTitle {
|
.hiwTitle {
|
||||||
@@ -1062,7 +1062,7 @@
|
|||||||
|
|
||||||
.editorialKicker {
|
.editorialKicker {
|
||||||
font-size: 0.68rem;
|
font-size: 0.68rem;
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
@@ -1300,7 +1300,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chipTrackDeadline {
|
.chipTrackDeadline {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipTrackOffer {
|
.chipTrackOffer {
|
||||||
|
|||||||
@@ -620,8 +620,8 @@ function CompactSchoolItem({ school, onAddToCompare, isInCompare, nationalAvgRwm
|
|||||||
borderRadius: '3px',
|
borderRadius: '3px',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
...(ofstedBadge.cssClass === 'ofsted1' ? { background: 'var(--accent-teal-bg)', color: 'var(--accent-teal, #2d7d7d)' } :
|
...(ofstedBadge.cssClass === 'ofsted1' ? { background: 'var(--accent-teal-bg)', color: 'var(--accent-teal, #2d7d7d)' } :
|
||||||
ofstedBadge.cssClass === 'ofsted2' ? { background: 'rgba(60,140,60,0.12)', color: '#3c8c3c' } :
|
ofstedBadge.cssClass === 'ofsted2' ? { background: 'rgba(60,140,60,0.12)', color: '#2f7a2f' } :
|
||||||
ofstedBadge.cssClass === 'ofsted3' ? { background: 'var(--accent-gold-bg)', color: '#b8920e' } :
|
ofstedBadge.cssClass === 'ofsted3' ? { background: 'var(--accent-gold-bg)', color: 'var(--accent-gold-text, #7a6800)' } :
|
||||||
ofstedBadge.cssClass === 'ofsted4' ? { background: 'var(--accent-coral-bg)', color: 'var(--accent-coral, #e07256)' } :
|
ofstedBadge.cssClass === 'ofsted4' ? { background: 'var(--accent-coral-bg)', color: 'var(--accent-coral, #e07256)' } :
|
||||||
ofstedBadge.cssClass === 'ofstedRc' ? { background: '#5a3a6e', color: '#fff' } :
|
ofstedBadge.cssClass === 'ofstedRc' ? { background: '#5a3a6e', color: '#fff' } :
|
||||||
ofstedBadge.cssClass === 'ofstedPending' ? { background: '#e0e0e0', color: '#666' } :
|
ofstedBadge.cssClass === 'ofstedPending' ? { background: '#e0e0e0', color: '#666' } :
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ function buildPopupBadge(school: School): PopupBadge {
|
|||||||
const labels: Record<number, string> = { 1: 'Outstanding', 2: 'Good', 3: 'Req. Improvement', 4: 'Inadequate' };
|
const labels: Record<number, string> = { 1: 'Outstanding', 2: 'Good', 3: 'Req. Improvement', 4: 'Inadequate' };
|
||||||
const colours: Record<number, string> = {
|
const colours: Record<number, string> = {
|
||||||
1: 'background:#d4f0ea;color:#2d7d7d',
|
1: 'background:#d4f0ea;color:#2d7d7d',
|
||||||
2: 'background:rgba(60,140,60,0.12);color:#3c8c3c',
|
2: 'background:rgba(60,140,60,0.12);color:#2f7a2f',
|
||||||
3: 'background:#fef3cd;color:#b8920e',
|
3: 'background:#fef3cd;color:#7a6800',
|
||||||
4: 'background:#fde8e0;color:#e07256',
|
4: 'background:#fde8e0;color:#e07256',
|
||||||
};
|
};
|
||||||
return { label: `${labels[school.ofsted_grade]}${yearStr}`, style: colours[school.ofsted_grade] };
|
return { label: `${labels[school.ofsted_grade]}${yearStr}`, style: colours[school.ofsted_grade] };
|
||||||
|
|||||||
@@ -6,7 +6,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
font-size: 0.85em;
|
/* A real button: 24px tap target (WCAG 2.5.8) drawn as the small glyph. */
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 24px;
|
||||||
|
min-height: 24px;
|
||||||
|
margin: -6px 0;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
font-size: 0.9em;
|
||||||
color: var(--text-muted, #8a7a72);
|
color: var(--text-muted, #8a7a72);
|
||||||
cursor: help;
|
cursor: help;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
@@ -14,8 +24,9 @@
|
|||||||
transition: color 0.15s ease;
|
transition: color 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper:hover .icon {
|
.wrapper:hover .icon,
|
||||||
color: var(--accent-coral, #e07256);
|
.icon[aria-expanded="true"] {
|
||||||
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip {
|
.tooltip {
|
||||||
@@ -39,12 +50,18 @@
|
|||||||
transition: opacity 0.15s ease, visibility 0.15s ease;
|
transition: opacity 0.15s ease, visibility 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep tooltip visible when hovering over it */
|
/* Reveal on hover (desktop), keyboard focus, or explicit tap/click toggle. */
|
||||||
.wrapper:hover .tooltip {
|
.wrapper:hover .tooltip,
|
||||||
|
.wrapper:focus-within .tooltip,
|
||||||
|
.tooltipOpen {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tooltipOpen {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
/* Small arrow pointing down */
|
/* Small arrow pointing down */
|
||||||
.tooltip::after {
|
.tooltip::after {
|
||||||
content: '';
|
content: '';
|
||||||
@@ -75,19 +92,23 @@
|
|||||||
margin-top: 0.1rem;
|
margin-top: 0.1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Flip tooltip below when near top of screen */
|
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
.tooltip {
|
.tooltip {
|
||||||
width: 180px;
|
width: 180px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On phones the icon was rendering at ~9px and the tooltip relied on
|
/* Anchor the bubble to open rightward on phones — icons follow their labels,
|
||||||
:hover, which doesn't fire on touch. Rather than build a tap-to-show
|
which start at the left edge, so centring pushed the bubble off-screen. */
|
||||||
layer with backdrop dismissal, hide the helper entirely — the metric
|
|
||||||
labels themselves carry the meaning. */
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
.wrapper {
|
.tooltip {
|
||||||
display: none;
|
left: -12px;
|
||||||
|
right: auto;
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip::after {
|
||||||
|
left: 16px;
|
||||||
|
transform: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { METRIC_EXPLANATIONS } from '@/lib/metrics';
|
import { METRIC_EXPLANATIONS } from '@/lib/metrics';
|
||||||
import styles from './MetricTooltip.module.css';
|
import styles from './MetricTooltip.module.css';
|
||||||
|
|
||||||
@@ -16,12 +17,43 @@ export function MetricTooltip({ metricKey, label, plain, detail }: MetricTooltip
|
|||||||
const tooltipPlain = plain ?? explanation?.plain;
|
const tooltipPlain = plain ?? explanation?.plain;
|
||||||
const tooltipDetail = detail ?? explanation?.detail;
|
const tooltipDetail = detail ?? explanation?.detail;
|
||||||
|
|
||||||
|
// Tap/click/keyboard toggle so the definition is reachable on touch devices
|
||||||
|
// and by keyboard, not just mouse hover (hover still works on desktop).
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const wrapperRef = useRef<HTMLSpanElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!open) return;
|
||||||
|
const dismiss = (e: Event) => {
|
||||||
|
if (wrapperRef.current && e.target instanceof Node && !wrapperRef.current.contains(e.target)) {
|
||||||
|
setOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onKey = (e: KeyboardEvent) => {
|
||||||
|
if (e.key === 'Escape') setOpen(false);
|
||||||
|
};
|
||||||
|
document.addEventListener('click', dismiss);
|
||||||
|
document.addEventListener('keydown', onKey);
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('click', dismiss);
|
||||||
|
document.removeEventListener('keydown', onKey);
|
||||||
|
};
|
||||||
|
}, [open]);
|
||||||
|
|
||||||
if (!tooltipPlain) return null;
|
if (!tooltipPlain) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={styles.wrapper}>
|
<span className={styles.wrapper} ref={wrapperRef}>
|
||||||
<span className={styles.icon} aria-label={tooltipLabel ?? 'More information'} role="img">ⓘ</span>
|
<button
|
||||||
<span className={styles.tooltip} role="tooltip">
|
type="button"
|
||||||
|
className={styles.icon}
|
||||||
|
aria-expanded={open}
|
||||||
|
aria-label={`What does ${tooltipLabel ?? 'this metric'} mean?`}
|
||||||
|
onClick={() => setOpen((o) => !o)}
|
||||||
|
>
|
||||||
|
ⓘ
|
||||||
|
</button>
|
||||||
|
<span className={`${styles.tooltip}${open ? ` ${styles.tooltipOpen}` : ''}`} role="tooltip">
|
||||||
{tooltipLabel && <span className={styles.tooltipLabel}>{tooltipLabel}</span>}
|
{tooltipLabel && <span className={styles.tooltipLabel}>{tooltipLabel}</span>}
|
||||||
<span className={styles.tooltipPlain}>{tooltipPlain}</span>
|
<span className={styles.tooltipPlain}>{tooltipPlain}</span>
|
||||||
{tooltipDetail && <span className={styles.tooltipDetail}>{tooltipDetail}</span>}
|
{tooltipDetail && <span className={styles.tooltipDetail}>{tooltipDetail}</span>}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.logo:hover {
|
.logo:hover {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.logoIcon {
|
.logoIcon {
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.navLink.active {
|
.navLink.active {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
background: var(--accent-coral-bg);
|
background: var(--accent-coral-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tabActive {
|
.tabActive {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabIconWrap {
|
.tabIconWrap {
|
||||||
|
|||||||
@@ -87,7 +87,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chipActive {
|
.chipActive {
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--accent-coral-dark, #b04a2e);
|
||||||
color: white;
|
color: white;
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--accent-coral, #e07256);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|||||||
@@ -55,13 +55,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.phaseTabActive {
|
.phaseTabActive {
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--accent-coral-dark, #b04a2e);
|
||||||
color: white;
|
color: white;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phaseTabActive:hover {
|
.phaseTabActive:hover {
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--accent-coral-darker, #9c3f26);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Filters */
|
/* Filters */
|
||||||
@@ -290,7 +290,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.schoolLink:hover {
|
.schoolLink:hover {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.areaCell,
|
.areaCell,
|
||||||
@@ -298,6 +298,14 @@
|
|||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary, #5c564d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* LA subline under the school name — mobile only (Area column hidden there). */
|
||||||
|
.schoolCellArea {
|
||||||
|
display: none;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--text-muted, #8a847a);
|
||||||
|
}
|
||||||
|
|
||||||
.valueCell {
|
.valueCell {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
@@ -374,20 +382,26 @@
|
|||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hide less-critical columns on mobile so the metric value stays visible */
|
/* Hide less-critical columns on mobile so the metric value stays visible.
|
||||||
|
Area moves to a subline under the school name (.schoolCellArea) — with a
|
||||||
|
four-column layout the value still overflowed a 390px viewport and the
|
||||||
|
whole point of the page (the score) needed a sideways swipe to see. */
|
||||||
.typeHeader,
|
.typeHeader,
|
||||||
.typeCell,
|
.typeCell,
|
||||||
.actionHeader,
|
.actionHeader,
|
||||||
.actionCell {
|
.actionCell,
|
||||||
|
.areaHeader,
|
||||||
|
.areaCell {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.schoolHeader {
|
.schoolCellArea {
|
||||||
min-width: 140px;
|
display: block;
|
||||||
|
margin-top: 0.15rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.areaHeader {
|
.schoolHeader {
|
||||||
min-width: 80px;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.valueHeader,
|
.valueHeader,
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export function RankingsView({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handlePhaseChange = (phase: string) => {
|
const handlePhaseChange = (phase: string) => {
|
||||||
const defaultMetric = phase === 'secondary' ? 'attainment_8_score' : 'rwm_high_pct';
|
const defaultMetric = phase === 'secondary' ? 'attainment_8_score' : 'rwm_expected_pct';
|
||||||
updateFilters({ phase, metric: defaultMetric });
|
updateFilters({ phase, metric: defaultMetric });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -273,6 +273,11 @@ export function RankingsView({
|
|||||||
<a href={schoolUrl(ranking.urn, ranking.school_name)} className={styles.schoolLink}>
|
<a href={schoolUrl(ranking.urn, ranking.school_name)} className={styles.schoolLink}>
|
||||||
{ranking.school_name}
|
{ranking.school_name}
|
||||||
</a>
|
</a>
|
||||||
|
{/* On phones the Area column is hidden; the LA moves here
|
||||||
|
so the metric value fits on screen without swiping. */}
|
||||||
|
{ranking.local_authority && (
|
||||||
|
<span className={styles.schoolCellArea}>{ranking.local_authority}</span>
|
||||||
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td className={styles.areaCell}>{ranking.local_authority || '-'}</td>
|
<td className={styles.areaCell}>{ranking.local_authority || '-'}</td>
|
||||||
<td className={styles.typeCell}>{ranking.school_type || '-'}</td>
|
<td className={styles.typeCell}>{ranking.school_type || '-'}</td>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
padding: 0.25rem 0;
|
padding: 0.25rem 0;
|
||||||
font-size: 1.0625rem;
|
font-size: 1.0625rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
|
|
||||||
.headerHasMap .actions .btnAdd {
|
.headerHasMap .actions .btnAdd {
|
||||||
background: rgba(255, 255, 255, 0.9);
|
background: rgba(255, 255, 255, 0.9);
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
-webkit-backdrop-filter: blur(6px);
|
-webkit-backdrop-filter: blur(6px);
|
||||||
backdrop-filter: blur(6px);
|
backdrop-filter: blur(6px);
|
||||||
@@ -124,7 +124,7 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
font: inherit;
|
font: inherit;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
@@ -210,7 +210,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.genderSplitGirls {
|
.genderSplitGirls {
|
||||||
color: #b45778;
|
color: #a04a68;
|
||||||
}
|
}
|
||||||
|
|
||||||
.genderSplitBoys {
|
.genderSplitBoys {
|
||||||
@@ -242,7 +242,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.genderBarGirls {
|
.genderBarGirls {
|
||||||
background: #b45778;
|
background: #a04a68;
|
||||||
}
|
}
|
||||||
|
|
||||||
.genderBarBoys {
|
.genderBarBoys {
|
||||||
@@ -270,12 +270,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btnAdd {
|
.btnAdd {
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--accent-coral-dark, #b04a2e);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btnAdd:hover {
|
.btnAdd:hover {
|
||||||
background: var(--accent-coral-dark, #c45a3f);
|
background: var(--accent-coral-darker, #9c3f26);
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +323,7 @@
|
|||||||
padding: 0.3rem 0.625rem;
|
padding: 0.3rem 0.625rem;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
background: none;
|
background: none;
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border-color, #e5dfd5);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -399,7 +399,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sectionNavLinkActive {
|
.sectionNavLinkActive {
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--accent-coral-dark, #b04a2e);
|
||||||
color: white;
|
color: white;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
@@ -468,8 +468,8 @@
|
|||||||
width: 38px;
|
width: 38px;
|
||||||
height: 38px;
|
height: 38px;
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
border: 1px solid var(--accent-coral, #e07256);
|
border: 1px solid var(--accent-coral-dark, #b04a2e);
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--accent-coral-dark, #b04a2e);
|
||||||
color: white;
|
color: white;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.15s ease, border-color 0.15s ease;
|
transition: background 0.15s ease, border-color 0.15s ease;
|
||||||
@@ -513,8 +513,8 @@
|
|||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: white;
|
color: white;
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--accent-coral-dark, #b04a2e);
|
||||||
border: 1px solid var(--accent-coral, #e07256);
|
border: 1px solid var(--accent-coral-dark, #b04a2e);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -522,8 +522,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sectionNavCompare:hover {
|
.sectionNavCompare:hover {
|
||||||
background: var(--accent-coral-dark, #c45a3f);
|
background: var(--accent-coral-darker, #9c3f26);
|
||||||
border-color: var(--accent-coral-dark, #c45a3f);
|
border-color: var(--accent-coral-darker, #9c3f26);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sectionNavCompareIn {
|
.sectionNavCompareIn {
|
||||||
@@ -626,7 +626,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sectionsTick {
|
.sectionsTick {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On phones the menu becomes a bottom sheet. */
|
/* On phones the menu becomes a bottom sheet. */
|
||||||
@@ -856,7 +856,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.progressNegative {
|
.progressNegative {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -868,12 +868,12 @@
|
|||||||
|
|
||||||
.statusWarn {
|
.statusWarn {
|
||||||
background: var(--accent-gold-bg);
|
background: var(--accent-gold-bg);
|
||||||
color: #b8920e;
|
color: var(--accent-gold-text, #7a6800);
|
||||||
}
|
}
|
||||||
|
|
||||||
.statusBad {
|
.statusBad {
|
||||||
background: var(--accent-coral-bg);
|
background: var(--accent-coral-bg);
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Charts Section */
|
/* Charts Section */
|
||||||
@@ -1011,15 +1011,15 @@
|
|||||||
}
|
}
|
||||||
.ofstedGrade2 {
|
.ofstedGrade2 {
|
||||||
background: rgba(60, 140, 60, 0.12);
|
background: rgba(60, 140, 60, 0.12);
|
||||||
color: #3c8c3c;
|
color: #2f7a2f;
|
||||||
}
|
}
|
||||||
.ofstedGrade3 {
|
.ofstedGrade3 {
|
||||||
background: var(--accent-gold-bg);
|
background: var(--accent-gold-bg);
|
||||||
color: #b8920e;
|
color: var(--accent-gold-text, #7a6800);
|
||||||
}
|
}
|
||||||
.ofstedGrade4 {
|
.ofstedGrade4 {
|
||||||
background: var(--accent-coral-bg);
|
background: var(--accent-coral-bg);
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Report Card grade colours (5-level scale, lower = better) */
|
/* Report Card grade colours (5-level scale, lower = better) */
|
||||||
@@ -1029,11 +1029,11 @@
|
|||||||
} /* Exceptional */
|
} /* Exceptional */
|
||||||
.rcGrade2 {
|
.rcGrade2 {
|
||||||
background: rgba(60, 140, 60, 0.12);
|
background: rgba(60, 140, 60, 0.12);
|
||||||
color: #3c8c3c;
|
color: #2f7a2f;
|
||||||
} /* Strong */
|
} /* Strong */
|
||||||
.rcGrade3 {
|
.rcGrade3 {
|
||||||
background: var(--accent-gold-bg);
|
background: var(--accent-gold-bg);
|
||||||
color: #b8920e;
|
color: var(--accent-gold-text, #7a6800);
|
||||||
} /* Expected standard */
|
} /* Expected standard */
|
||||||
.rcGrade4 {
|
.rcGrade4 {
|
||||||
background: rgba(249, 115, 22, 0.12);
|
background: rgba(249, 115, 22, 0.12);
|
||||||
@@ -1041,7 +1041,7 @@
|
|||||||
} /* Needs attention */
|
} /* Needs attention */
|
||||||
.rcGrade5 {
|
.rcGrade5 {
|
||||||
background: var(--accent-coral-bg);
|
background: var(--accent-coral-bg);
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
} /* Urgent improvement */
|
} /* Urgent improvement */
|
||||||
|
|
||||||
/* Safeguarding value (used inside a standard metricCard) */
|
/* Safeguarding value (used inside a standard metricCard) */
|
||||||
@@ -1061,7 +1061,7 @@
|
|||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
background: var(--accent-coral-bg);
|
background: var(--accent-coral-bg);
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ofstedDisclaimer {
|
.ofstedDisclaimer {
|
||||||
|
|||||||
@@ -201,8 +201,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ofsted1 { background: var(--accent-teal-bg); color: var(--accent-teal, #2d7d7d); }
|
.ofsted1 { background: var(--accent-teal-bg); color: var(--accent-teal, #2d7d7d); }
|
||||||
.ofsted2 { background: rgba(60, 140, 60, 0.12); color: #3c8c3c; }
|
.ofsted2 { background: rgba(60, 140, 60, 0.12); color: #2f7a2f; }
|
||||||
.ofsted3 { background: var(--accent-gold-bg); color: #b8920e; }
|
.ofsted3 { background: var(--accent-gold-bg); color: var(--accent-gold-text, #7a6800); }
|
||||||
.ofsted4 { background: var(--accent-coral-bg); color: var(--accent-coral, #e07256); }
|
.ofsted4 { background: var(--accent-coral-bg); color: var(--accent-coral, #e07256); }
|
||||||
|
|
||||||
/* ── Ofsted badge variants ──────────────────────────────────────────────── */
|
/* ── Ofsted badge variants ──────────────────────────────────────────────── */
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
padding: 0.25rem 0;
|
padding: 0.25rem 0;
|
||||||
font-size: 1.0625rem;
|
font-size: 1.0625rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
|
|
||||||
.headerHasMap .actions .btnAdd {
|
.headerHasMap .actions .btnAdd {
|
||||||
background: rgba(255, 255, 255, 0.9);
|
background: rgba(255, 255, 255, 0.9);
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
-webkit-backdrop-filter: blur(6px);
|
-webkit-backdrop-filter: blur(6px);
|
||||||
backdrop-filter: blur(6px);
|
backdrop-filter: blur(6px);
|
||||||
@@ -124,7 +124,7 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
font: inherit;
|
font: inherit;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
@@ -226,12 +226,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btnAdd {
|
.btnAdd {
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--accent-coral-dark, #b04a2e);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btnAdd:hover {
|
.btnAdd:hover {
|
||||||
background: var(--accent-coral-dark, #c45a3f);
|
background: var(--accent-coral-darker, #9c3f26);
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,7 +278,7 @@
|
|||||||
padding: 0.3rem 0.625rem;
|
padding: 0.3rem 0.625rem;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
background: none;
|
background: none;
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border-color, #e5dfd5);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -322,13 +322,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tabBtnActive {
|
.tabBtnActive {
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--accent-coral-dark, #b04a2e);
|
||||||
color: white;
|
color: white;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabBtnActive:hover {
|
.tabBtnActive:hover {
|
||||||
background: var(--accent-coral-dark, #c45a3f);
|
background: var(--accent-coral-darker, #9c3f26);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,7 +456,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.progressNegative {
|
.progressNegative {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,7 +468,7 @@
|
|||||||
|
|
||||||
.statusWarn {
|
.statusWarn {
|
||||||
background: var(--accent-gold-bg);
|
background: var(--accent-gold-bg);
|
||||||
color: #b8920e;
|
color: var(--accent-gold-text, #7a6800);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Metric table (row-based) ────────────────────────── */
|
/* ── Metric table (row-based) ────────────────────────── */
|
||||||
@@ -582,15 +582,15 @@
|
|||||||
}
|
}
|
||||||
.ofstedGrade2 {
|
.ofstedGrade2 {
|
||||||
background: rgba(60, 140, 60, 0.12);
|
background: rgba(60, 140, 60, 0.12);
|
||||||
color: #3c8c3c;
|
color: #2f7a2f;
|
||||||
}
|
}
|
||||||
.ofstedGrade3 {
|
.ofstedGrade3 {
|
||||||
background: var(--accent-gold-bg);
|
background: var(--accent-gold-bg);
|
||||||
color: #b8920e;
|
color: var(--accent-gold-text, #7a6800);
|
||||||
}
|
}
|
||||||
.ofstedGrade4 {
|
.ofstedGrade4 {
|
||||||
background: var(--accent-coral-bg);
|
background: var(--accent-coral-bg);
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rcGrade1 {
|
.rcGrade1 {
|
||||||
@@ -599,11 +599,11 @@
|
|||||||
}
|
}
|
||||||
.rcGrade2 {
|
.rcGrade2 {
|
||||||
background: rgba(60, 140, 60, 0.12);
|
background: rgba(60, 140, 60, 0.12);
|
||||||
color: #3c8c3c;
|
color: #2f7a2f;
|
||||||
}
|
}
|
||||||
.rcGrade3 {
|
.rcGrade3 {
|
||||||
background: var(--accent-gold-bg);
|
background: var(--accent-gold-bg);
|
||||||
color: #b8920e;
|
color: var(--accent-gold-text, #7a6800);
|
||||||
}
|
}
|
||||||
.rcGrade4 {
|
.rcGrade4 {
|
||||||
background: rgba(249, 115, 22, 0.12);
|
background: rgba(249, 115, 22, 0.12);
|
||||||
@@ -611,7 +611,7 @@
|
|||||||
}
|
}
|
||||||
.rcGrade5 {
|
.rcGrade5 {
|
||||||
background: var(--accent-coral-bg);
|
background: var(--accent-coral-bg);
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.safeguardingMet {
|
.safeguardingMet {
|
||||||
@@ -631,7 +631,7 @@
|
|||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
background: var(--accent-coral-bg);
|
background: var(--accent-coral-bg);
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--accent-coral-dark, #b04a2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ofstedDisclaimer {
|
.ofstedDisclaimer {
|
||||||
@@ -874,7 +874,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.genderBarGirls {
|
.genderBarGirls {
|
||||||
background: #b45778;
|
background: #a04a68;
|
||||||
}
|
}
|
||||||
|
|
||||||
.genderBarBoys {
|
.genderBarBoys {
|
||||||
@@ -889,7 +889,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.genderSplitGirls {
|
.genderSplitGirls {
|
||||||
color: #b45778;
|
color: #a04a68;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -946,7 +946,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: -20px;
|
top: -20px;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--accent-coral-dark, #b04a2e);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 0.6rem;
|
font-size: 0.6rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
|||||||
@@ -125,7 +125,7 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.deltaPositive { color: #3c8c3c; }
|
.deltaPositive { color: #2f7a2f; }
|
||||||
.deltaNegative { color: var(--accent-coral, #e07256); }
|
.deltaNegative { color: var(--accent-coral, #e07256); }
|
||||||
|
|
||||||
/* Line 4: location + distance */
|
/* Line 4: location + distance */
|
||||||
@@ -203,8 +203,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ofsted1 { background: var(--accent-teal-bg); color: var(--accent-teal, #2d7d7d); }
|
.ofsted1 { background: var(--accent-teal-bg); color: var(--accent-teal, #2d7d7d); }
|
||||||
.ofsted2 { background: rgba(60, 140, 60, 0.12); color: #3c8c3c; }
|
.ofsted2 { background: rgba(60, 140, 60, 0.12); color: #2f7a2f; }
|
||||||
.ofsted3 { background: var(--accent-gold-bg); color: #b8920e; }
|
.ofsted3 { background: var(--accent-gold-bg); color: var(--accent-gold-text, #7a6800); }
|
||||||
.ofsted4 { background: var(--accent-coral-bg); color: var(--accent-coral, #e07256); }
|
.ofsted4 { background: var(--accent-coral-bg); color: var(--accent-coral, #e07256); }
|
||||||
|
|
||||||
/* ── Ofsted badge variants ──────────────────────────────────────────────── */
|
/* ── Ofsted badge variants ──────────────────────────────────────────────── */
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ interface ComparisonContextType {
|
|||||||
error: any;
|
error: any;
|
||||||
addSchool: (school: School) => void;
|
addSchool: (school: School) => void;
|
||||||
removeSchool: (urn: number) => void;
|
removeSchool: (urn: number) => void;
|
||||||
|
replaceSchools: (schools: School[]) => void;
|
||||||
clearAll: () => void;
|
clearAll: () => void;
|
||||||
isSelected: (urn: number) => boolean;
|
isSelected: (urn: number) => boolean;
|
||||||
canAddMore: boolean;
|
canAddMore: boolean;
|
||||||
|
|||||||
@@ -65,6 +65,12 @@ export function ComparisonProvider({ children }: { children: React.ReactNode })
|
|||||||
setSelectedSchools((prev) => prev.filter((s) => s.urn !== urn));
|
setSelectedSchools((prev) => prev.filter((s) => s.urn !== urn));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Replace the whole selection — used when a shared /compare?urns=… link
|
||||||
|
// must take precedence over whatever this visitor had stored.
|
||||||
|
const replaceSchools = useCallback((schools: School[]) => {
|
||||||
|
setSelectedSchools(schools.slice(0, MAX_SCHOOLS));
|
||||||
|
}, []);
|
||||||
|
|
||||||
const clearAll = useCallback(() => {
|
const clearAll = useCallback(() => {
|
||||||
setSelectedSchools([]);
|
setSelectedSchools([]);
|
||||||
}, []);
|
}, []);
|
||||||
@@ -86,6 +92,7 @@ export function ComparisonProvider({ children }: { children: React.ReactNode })
|
|||||||
error: null,
|
error: null,
|
||||||
addSchool,
|
addSchool,
|
||||||
removeSchool,
|
removeSchool,
|
||||||
|
replaceSchools,
|
||||||
clearAll,
|
clearAll,
|
||||||
isSelected,
|
isSelected,
|
||||||
canAddMore: selectedSchools.length < MAX_SCHOOLS,
|
canAddMore: selectedSchools.length < MAX_SCHOOLS,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export function useComparison() {
|
|||||||
selectedSchools,
|
selectedSchools,
|
||||||
addSchool,
|
addSchool,
|
||||||
removeSchool,
|
removeSchool,
|
||||||
|
replaceSchools,
|
||||||
clearAll,
|
clearAll,
|
||||||
isSelected,
|
isSelected,
|
||||||
canAddMore,
|
canAddMore,
|
||||||
@@ -39,6 +40,7 @@ export function useComparison() {
|
|||||||
error,
|
error,
|
||||||
addSchool,
|
addSchool,
|
||||||
removeSchool,
|
removeSchool,
|
||||||
|
replaceSchools,
|
||||||
clearAll,
|
clearAll,
|
||||||
isSelected,
|
isSelected,
|
||||||
canAddMore,
|
canAddMore,
|
||||||
|
|||||||
@@ -275,6 +275,27 @@ export function getChartColor(index: number): string {
|
|||||||
return CHART_COLORS[index % CHART_COLORS.length];
|
return CHART_COLORS[index % CHART_COLORS.length];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Darker counterparts of CHART_COLORS for use as TEXT on the site's light
|
||||||
|
* backgrounds — the raw series colours fail WCAG AA (e.g. 1.9:1 on cream).
|
||||||
|
* Same hue per index so text still keys to its chart line. All ≥4.5:1 on
|
||||||
|
* #f3ede4 and lighter.
|
||||||
|
*/
|
||||||
|
export const CHART_TEXT_COLORS = [
|
||||||
|
'#256868', // teal
|
||||||
|
'#c2255c', // pink/red
|
||||||
|
'#2069ad', // blue
|
||||||
|
'#8a5a00', // yellow → ochre
|
||||||
|
'#6d43c8', // purple
|
||||||
|
'#8f4e00', // orange → brown
|
||||||
|
'#5f5952', // grey
|
||||||
|
'#a300a3', // magenta
|
||||||
|
];
|
||||||
|
|
||||||
|
export function getChartTextColor(index: number): string {
|
||||||
|
return CHART_TEXT_COLORS[index % CHART_TEXT_COLORS.length];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert RGB color to RGBA with opacity
|
* Convert RGB color to RGBA with opacity
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user