Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2433101fa0 | ||
|
|
8c3a5cc4e9 | ||
|
|
8ab0ac0a04 | ||
|
|
c298a29b61 | ||
|
|
5f961bf7f4 |
@@ -626,3 +626,194 @@ test('sticky section nav jumps to server-rendered sections', async ({ page }) =>
|
|||||||
const after = await page.evaluate(() => window.scrollY);
|
const after = await page.evaluate(() => window.scrollY);
|
||||||
expect(after).toBeGreaterThan(before);
|
expect(after).toBeGreaterThan(before);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Brand surface. The identity work replaced a favicon-only asset set that
|
||||||
|
* broke iOS home-screen icons, Android PWA installs, and every link preview.
|
||||||
|
* These are silent failures — nothing on the page looks wrong — so they need
|
||||||
|
* a gate.
|
||||||
|
*/
|
||||||
|
test('the brand asset set is complete and served', async ({ page }) => {
|
||||||
|
const response = await page.goto('/');
|
||||||
|
expect(response?.ok()).toBe(true);
|
||||||
|
|
||||||
|
// The share card: without it, every link pasted into a chat renders bare.
|
||||||
|
const ogImage = page.locator('meta[property="og:image"]');
|
||||||
|
await expect(ogImage).toHaveCount(1);
|
||||||
|
const ogUrl = await ogImage.getAttribute('content');
|
||||||
|
expect(ogUrl).toBeTruthy();
|
||||||
|
// metadataBase pins canonical URLs to the production host, which is correct
|
||||||
|
// for prod but means the absolute URL points off-environment on staging.
|
||||||
|
// Fetch the path against whichever environment we're actually testing.
|
||||||
|
const og = await page.request.get(new URL(ogUrl!).pathname + new URL(ogUrl!).search);
|
||||||
|
expect(og.ok()).toBe(true);
|
||||||
|
expect(og.headers()['content-type']).toContain('image/png');
|
||||||
|
|
||||||
|
// iOS ignores SVG touch icons, so this must be a real raster.
|
||||||
|
const apple = await page.request.get('/apple-icon');
|
||||||
|
expect(apple.ok()).toBe(true);
|
||||||
|
expect(apple.headers()['content-type']).toContain('image/png');
|
||||||
|
|
||||||
|
// Android needs a maskable PNG or the install prompt has no icon.
|
||||||
|
for (const icon of ['/icon-192.png', '/icon-512.png', '/icon-maskable-512.png']) {
|
||||||
|
const res = await page.request.get(icon);
|
||||||
|
expect(res.ok(), `${icon} should be served`).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('theme colour matches the page background in both themes', async ({ browser }) => {
|
||||||
|
// A mismatch here paints a stripe of the wrong colour across the top of the
|
||||||
|
// screen on mobile. Previously the dark themeColor was declared with no dark
|
||||||
|
// styling behind it at all.
|
||||||
|
for (const colorScheme of ['light', 'dark'] as const) {
|
||||||
|
const context = await browser.newContext({ colorScheme });
|
||||||
|
const page = await context.newPage();
|
||||||
|
await page.goto('/');
|
||||||
|
|
||||||
|
const declared = await page
|
||||||
|
.locator(`meta[name="theme-color"][media*="${colorScheme}"]`)
|
||||||
|
.getAttribute('content');
|
||||||
|
expect(declared, `theme-color declared for ${colorScheme}`).toBeTruthy();
|
||||||
|
|
||||||
|
const painted = await page.evaluate(() =>
|
||||||
|
getComputedStyle(document.documentElement).getPropertyValue('--bg-primary').trim()
|
||||||
|
);
|
||||||
|
expect(painted.toLowerCase()).toBe(declared!.toLowerCase());
|
||||||
|
|
||||||
|
await context.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the dark theme actually repaints the page', async ({ browser }) => {
|
||||||
|
// Guards the token layer: if a component reintroduces a hardcoded colour,
|
||||||
|
// the surface below stays light while everything around it flips.
|
||||||
|
const read = async (colorScheme: 'light' | 'dark') => {
|
||||||
|
const context = await browser.newContext({ colorScheme });
|
||||||
|
const page = await context.newPage();
|
||||||
|
await page.goto('/');
|
||||||
|
await expect(page.locator('h1').first()).toBeVisible({ timeout: 15_000 });
|
||||||
|
const values = await page.evaluate(() => {
|
||||||
|
const s = getComputedStyle(document.body);
|
||||||
|
return { bg: s.backgroundColor, fg: s.color };
|
||||||
|
});
|
||||||
|
await context.close();
|
||||||
|
return values;
|
||||||
|
};
|
||||||
|
|
||||||
|
const light = await read('light');
|
||||||
|
const dark = await read('dark');
|
||||||
|
expect(dark.bg).not.toBe(light.bg);
|
||||||
|
expect(dark.fg).not.toBe(light.fg);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Typography and palette integrity.
|
||||||
|
*
|
||||||
|
* The identity PR shipped with every font-family silently falling back to
|
||||||
|
* Times: the font variables landed on <body> while the tokens referencing
|
||||||
|
* them were declared on :root, so --font-display computed to the
|
||||||
|
* guaranteed-invalid value. Nothing threw, no test failed, and the build was
|
||||||
|
* green — the only symptom was visual. These assertions make that class of
|
||||||
|
* failure loud.
|
||||||
|
*/
|
||||||
|
test('the brand typefaces actually load and apply', async ({ page }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
await expect(page.locator('h1').first()).toBeVisible({ timeout: 15_000 });
|
||||||
|
|
||||||
|
const fonts = await page.evaluate(() => {
|
||||||
|
const root = getComputedStyle(document.documentElement);
|
||||||
|
return {
|
||||||
|
body: getComputedStyle(document.body).fontFamily,
|
||||||
|
heading: getComputedStyle(document.querySelector('h1')!).fontFamily,
|
||||||
|
displayToken: root.getPropertyValue('--font-display').trim(),
|
||||||
|
uiToken: root.getPropertyValue('--font-ui').trim(),
|
||||||
|
proseToken: root.getPropertyValue('--font-prose').trim(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// An empty token means the var() chain broke, which is the exact failure
|
||||||
|
// mode above — the computed font-family would look plausible either way.
|
||||||
|
expect(fonts.displayToken, '--font-display resolved').not.toBe('');
|
||||||
|
expect(fonts.uiToken, '--font-ui resolved').not.toBe('');
|
||||||
|
expect(fonts.proseToken, '--font-prose resolved').not.toBe('');
|
||||||
|
|
||||||
|
expect(fonts.body).toContain('Schibsted');
|
||||||
|
expect(fonts.heading).toContain('Schibsted');
|
||||||
|
// Times/serif anywhere in the interface means we fell back.
|
||||||
|
expect(fonts.body).not.toMatch(/Times|serif$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('no visible text falls back to the browser default black', async ({ page }) => {
|
||||||
|
// Form controls don't inherit colour from their parent, so a missing
|
||||||
|
// declaration renders pure black — subtle in light mode, invisible in dark.
|
||||||
|
await page.goto('/');
|
||||||
|
await expect(page.locator('h1').first()).toBeVisible({ timeout: 15_000 });
|
||||||
|
|
||||||
|
const blacks = await page.evaluate(() =>
|
||||||
|
[...document.querySelectorAll('body *')]
|
||||||
|
.filter((el) => {
|
||||||
|
const r = el.getBoundingClientRect();
|
||||||
|
if (r.width < 2 || r.height < 2) return false;
|
||||||
|
if (el.closest('.leaflet-container')) return false;
|
||||||
|
return getComputedStyle(el).color === 'rgb(0, 0, 0)';
|
||||||
|
})
|
||||||
|
.map((el) => el.tagName.toLowerCase() + '.' + (el.getAttribute('class') || '').split(' ')[0])
|
||||||
|
.slice(0, 10)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(blacks, `elements rendering pure black: ${blacks.join(', ')}`).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('rendered colours all come from the token palette', async ({ page }) => {
|
||||||
|
// Turns the manual design audit into a gate: anything painted with a colour
|
||||||
|
// the token layer doesn't define has escaped the system, and will not
|
||||||
|
// follow the dark theme.
|
||||||
|
await page.goto('/rankings');
|
||||||
|
await expect(page.locator('table, [class*="rankings"]').first()).toBeVisible({ timeout: 15_000 });
|
||||||
|
|
||||||
|
const strays = await page.evaluate(() => {
|
||||||
|
const root = getComputedStyle(document.documentElement);
|
||||||
|
const palette = new Set<string>();
|
||||||
|
for (const sheet of document.styleSheets) {
|
||||||
|
let rules: CSSRuleList;
|
||||||
|
try { rules = sheet.cssRules; } catch { continue; }
|
||||||
|
for (const rule of rules) {
|
||||||
|
const r = rule as CSSStyleRule;
|
||||||
|
if (r.selectorText !== ':root' || !r.style) continue;
|
||||||
|
for (const prop of r.style) {
|
||||||
|
if (!prop.startsWith('--')) continue;
|
||||||
|
const v = root.getPropertyValue(prop).trim();
|
||||||
|
if (v) palette.add(v.toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const norm = (c: string) => {
|
||||||
|
const d = document.createElement('div');
|
||||||
|
d.style.color = c;
|
||||||
|
document.body.appendChild(d);
|
||||||
|
const v = getComputedStyle(d).color;
|
||||||
|
d.remove();
|
||||||
|
return v;
|
||||||
|
};
|
||||||
|
const allowed = new Set([...palette].filter((v) => /^#|^rgb/.test(v)).map(norm));
|
||||||
|
|
||||||
|
const found: string[] = [];
|
||||||
|
for (const el of document.querySelectorAll('body *')) {
|
||||||
|
const box = el.getBoundingClientRect();
|
||||||
|
if (box.width < 2 || box.height < 2) continue;
|
||||||
|
if (el.closest('.leaflet-container')) continue; // OSM tiles are imagery
|
||||||
|
const s = getComputedStyle(el);
|
||||||
|
const checks: Array<[string, string]> = [['color', s.color]];
|
||||||
|
if (s.backgroundColor !== 'rgba(0, 0, 0, 0)') checks.push(['background', s.backgroundColor]);
|
||||||
|
for (const [prop, value] of checks) {
|
||||||
|
if (!value || value.startsWith('rgba(') || allowed.has(value)) continue;
|
||||||
|
const cls = (el.getAttribute('class') || '(none)').split(' ')[0];
|
||||||
|
const entry = `${value} as ${prop} on ${cls}`;
|
||||||
|
if (!found.includes(entry)) found.push(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found.slice(0, 12);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(strays, `off-palette colours: ${strays.join('; ')}`).toEqual([]);
|
||||||
|
});
|
||||||
|
|||||||
@@ -47,6 +47,12 @@ COPY --from=builder /app/public ./public
|
|||||||
COPY --from=builder /app/.next/standalone ./
|
COPY --from=builder /app/.next/standalone ./
|
||||||
COPY --from=builder /app/.next/static ./.next/static
|
COPY --from=builder /app/.next/static ./.next/static
|
||||||
|
|
||||||
|
# Fonts for the generated share card. File tracing already places these in
|
||||||
|
# .next/standalone/assets, so the COPY above carries them — this makes the
|
||||||
|
# dependency explicit rather than implicit in the tracer's behaviour, because
|
||||||
|
# a miss here is a silent 500 on /opengraph-image, not a build failure.
|
||||||
|
COPY --from=builder /app/assets ./assets
|
||||||
|
|
||||||
# Set correct permissions
|
# Set correct permissions
|
||||||
RUN chown -R nextjs:nodejs /app
|
RUN chown -R nextjs:nodejs /app
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { ImageResponse } from 'next/og';
|
||||||
|
import { BARS } from '@/components/Logo';
|
||||||
|
|
||||||
|
// iOS ignores SVG touch icons — it needs a real raster, on an opaque ground,
|
||||||
|
// with no transparency (it composites its own rounded mask). Previously this
|
||||||
|
// pointed at favicon.svg, so add-to-home-screen produced a blank tile.
|
||||||
|
export const size = { width: 180, height: 180 };
|
||||||
|
export const contentType = 'image/png';
|
||||||
|
|
||||||
|
const COHORT = ['rgba(22,32,42,0.22)', 'rgba(22,32,42,0.38)', 'rgba(22,32,42,0.55)', '', 'rgba(22,32,42,0.22)'];
|
||||||
|
const SCALE = 3.6; // 40 → 144, leaving a 18px margin inside 180
|
||||||
|
|
||||||
|
export default function AppleIcon() {
|
||||||
|
return new ImageResponse(
|
||||||
|
(
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
background: '#f2f1ed',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ position: 'relative', width: 40 * SCALE, height: 40 * SCALE, display: 'flex' }}>
|
||||||
|
{BARS.map(([x, y, w, h, isSchool], i) => (
|
||||||
|
<div
|
||||||
|
key={x}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
left: x * SCALE,
|
||||||
|
top: y * SCALE,
|
||||||
|
width: w * SCALE,
|
||||||
|
height: h * SCALE,
|
||||||
|
borderRadius: 3,
|
||||||
|
background: isSchool ? '#584a9b' : COHORT[i],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
size
|
||||||
|
);
|
||||||
|
}
|
||||||
+323
-1914
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
|||||||
|
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="2" y="26" width="6" height="12" rx="1" fill="#16202a" fill-opacity="0.22"/>
|
||||||
|
<rect x="10" y="16" width="6" height="22" rx="1" fill="#16202a" fill-opacity="0.38"/>
|
||||||
|
<rect x="18" y="8" width="6" height="30" rx="1" fill="#16202a" fill-opacity="0.55"/>
|
||||||
|
<rect x="26" y="14" width="6" height="24" rx="1" fill="#584a9b"/>
|
||||||
|
<rect x="34" y="28" width="4" height="10" rx="1" fill="#16202a" fill-opacity="0.22"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 521 B |
+31
-17
@@ -1,5 +1,5 @@
|
|||||||
import type { Metadata, Viewport } from 'next';
|
import type { Metadata, Viewport } from 'next';
|
||||||
import { DM_Sans, Playfair_Display } from 'next/font/google';
|
import { Schibsted_Grotesk, Literata } from 'next/font/google';
|
||||||
import Script from 'next/script';
|
import Script from 'next/script';
|
||||||
import { Navigation } from '@/components/Navigation';
|
import { Navigation } from '@/components/Navigation';
|
||||||
import { Footer } from '@/components/Footer';
|
import { Footer } from '@/components/Footer';
|
||||||
@@ -7,17 +7,23 @@ import { ComparisonToast } from '@/components/ComparisonToast';
|
|||||||
import { ComparisonProvider } from '@/context/ComparisonProvider';
|
import { ComparisonProvider } from '@/context/ComparisonProvider';
|
||||||
import './globals.css';
|
import './globals.css';
|
||||||
|
|
||||||
const dmSans = DM_Sans({
|
// Schibsted Grotesk carries the whole interface — headings, labels, and every
|
||||||
|
// figure. It was drawn for news brands, so its tabular numerals hold a column
|
||||||
|
// properly, which matters on a page that is mostly percentages.
|
||||||
|
const schibsted = Schibsted_Grotesk({
|
||||||
subsets: ['latin'],
|
subsets: ['latin'],
|
||||||
weight: ['400', '500', '600', '700'],
|
weight: ['400', '500', '600', '700'],
|
||||||
variable: '--font-dm-sans',
|
variable: '--font-schibsted',
|
||||||
display: 'swap',
|
display: 'swap',
|
||||||
});
|
});
|
||||||
|
|
||||||
const playfairDisplay = Playfair_Display({
|
// Literata is for prose only — the admissions guide, methodology notes, the
|
||||||
|
// editorial sections. It never touches a number or a control.
|
||||||
|
const literata = Literata({
|
||||||
subsets: ['latin'],
|
subsets: ['latin'],
|
||||||
weight: ['600', '700'],
|
weight: ['400', '600'],
|
||||||
variable: '--font-playfair',
|
style: ['normal', 'italic'],
|
||||||
|
variable: '--font-literata',
|
||||||
display: 'swap',
|
display: 'swap',
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -27,9 +33,11 @@ export const viewport: Viewport = {
|
|||||||
// viewport-fit=cover lets us paint behind the notch / Dynamic Island so
|
// viewport-fit=cover lets us paint behind the notch / Dynamic Island so
|
||||||
// env(safe-area-inset-*) values resolve to real numbers on iPhone.
|
// env(safe-area-inset-*) values resolve to real numbers on iPhone.
|
||||||
viewportFit: 'cover',
|
viewportFit: 'cover',
|
||||||
|
// These must match --bg-primary in globals.css for each theme, or the
|
||||||
|
// browser chrome and the page disagree at the top edge of the screen.
|
||||||
themeColor: [
|
themeColor: [
|
||||||
{ media: '(prefers-color-scheme: light)', color: '#faf7f2' },
|
{ media: '(prefers-color-scheme: light)', color: '#f2f1ed' },
|
||||||
{ media: '(prefers-color-scheme: dark)', color: '#1a1612' },
|
{ media: '(prefers-color-scheme: dark)', color: '#10151b' },
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -47,11 +55,10 @@ export const metadata: Metadata = {
|
|||||||
keywords: 'school comparison, KS2 results, KS4 results, primary school, secondary school, England schools, SATs results, GCSE results',
|
keywords: 'school comparison, KS2 results, KS4 results, primary school, secondary school, England schools, SATs results, GCSE results',
|
||||||
authors: [{ name: 'SchoolCompare' }],
|
authors: [{ name: 'SchoolCompare' }],
|
||||||
manifest: '/manifest.json',
|
manifest: '/manifest.json',
|
||||||
icons: {
|
// No `icons` key on purpose: setting it here would override the file
|
||||||
icon: '/favicon.svg',
|
// conventions. app/icon.svg and app/apple-icon.tsx are the source, and
|
||||||
shortcut: '/favicon.svg',
|
// app/opengraph-image.tsx supplies og:image and twitter:image.
|
||||||
apple: '/favicon.svg',
|
metadataBase: new URL('https://schoolcompare.co.uk'),
|
||||||
},
|
|
||||||
openGraph: {
|
openGraph: {
|
||||||
type: 'website',
|
type: 'website',
|
||||||
title: 'SchoolCompare | Compare School Performance',
|
title: 'SchoolCompare | Compare School Performance',
|
||||||
@@ -60,7 +67,8 @@ export const metadata: Metadata = {
|
|||||||
siteName: 'SchoolCompare',
|
siteName: 'SchoolCompare',
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: 'summary',
|
// summary_large_image now that there is an image worth showing.
|
||||||
|
card: 'summary_large_image',
|
||||||
title: 'SchoolCompare | Compare School Performance',
|
title: 'SchoolCompare | Compare School Performance',
|
||||||
description: 'Compare primary and secondary school SATs and GCSE performance across England',
|
description: 'Compare primary and secondary school SATs and GCSE performance across England',
|
||||||
},
|
},
|
||||||
@@ -72,7 +80,14 @@ export default function RootLayout({
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
// The font variable classes must sit on <html>, not <body>. globals.css
|
||||||
|
// declares --font-display/--font-ui on :root as var(--font-schibsted),
|
||||||
|
// and a custom property's var() references resolve on the element that
|
||||||
|
// declares it. With the classes on <body>, --font-schibsted was undefined
|
||||||
|
// at :root, so --font-display computed to the guaranteed-invalid value and
|
||||||
|
// every font-family that referenced it silently fell back — the whole site
|
||||||
|
// rendered in Times.
|
||||||
|
<html lang="en" className={`${schibsted.variable} ${literata.variable}`}>
|
||||||
<head>
|
<head>
|
||||||
<link rel="preconnect" href="https://analytics.schoolcompare.co.uk" />
|
<link rel="preconnect" href="https://analytics.schoolcompare.co.uk" />
|
||||||
<link rel="preconnect" href="https://api.postcodes.io" />
|
<link rel="preconnect" href="https://api.postcodes.io" />
|
||||||
@@ -94,8 +109,7 @@ export default function RootLayout({
|
|||||||
strategy="afterInteractive"
|
strategy="afterInteractive"
|
||||||
/>
|
/>
|
||||||
</head>
|
</head>
|
||||||
<body className={`${dmSans.variable} ${playfairDisplay.variable}`}>
|
<body>
|
||||||
<div className="noise-overlay" />
|
|
||||||
<ComparisonProvider>
|
<ComparisonProvider>
|
||||||
<a href="#main-content" className="skip-link">Skip to main content</a>
|
<a href="#main-content" className="skip-link">Skip to main content</a>
|
||||||
<Navigation />
|
<Navigation />
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
import { readFile } from 'node:fs/promises';
|
||||||
|
import { join } from 'node:path';
|
||||||
|
import { ImageResponse } from 'next/og';
|
||||||
|
import { BARS } from '@/components/Logo';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The site had no og:image at all, so every link pasted into a class WhatsApp
|
||||||
|
* group or a Slack channel rendered as a bare grey text card — on the highest
|
||||||
|
* intent channel this product has.
|
||||||
|
*
|
||||||
|
* The card is the mark at poster scale: the cohort as a wide distribution with
|
||||||
|
* one school lit up. It states the proposition rather than decorating it.
|
||||||
|
*/
|
||||||
|
export const alt = 'SchoolCompare — compare every school in England against the national picture';
|
||||||
|
export const size = { width: 1200, height: 630 };
|
||||||
|
export const contentType = 'image/png';
|
||||||
|
|
||||||
|
const PAPER = '#f2f1ed';
|
||||||
|
const INK = '#16202a';
|
||||||
|
const MUTED = '#5c6570';
|
||||||
|
const BRAND = '#584a9b';
|
||||||
|
|
||||||
|
// A plausible national distribution, drawn once at poster scale. The lit bar
|
||||||
|
// is the same position the mark uses.
|
||||||
|
const SPREAD = [8, 12, 17, 24, 33, 44, 57, 70, 82, 92, 98, 100, 96, 88, 77, 65, 53, 41, 31, 22, 15, 10, 7, 5];
|
||||||
|
// Right of the peak: score runs left to right, so the lit school reads as
|
||||||
|
// above the national average. At index 9 it sat on the low side, which quietly
|
||||||
|
// said the opposite.
|
||||||
|
const LIT = 14;
|
||||||
|
|
||||||
|
async function font(file: string) {
|
||||||
|
return readFile(join(process.cwd(), 'assets', file));
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function OpengraphImage() {
|
||||||
|
const [regular, bold] = await Promise.all([
|
||||||
|
font('SchibstedGrotesk-Regular.ttf'),
|
||||||
|
font('SchibstedGrotesk-Bold.ttf'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return new ImageResponse(
|
||||||
|
(
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
background: PAPER,
|
||||||
|
padding: '58px 72px 52px',
|
||||||
|
fontFamily: 'Schibsted',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Lockup */}
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
|
||||||
|
<div style={{ position: 'relative', width: 40, height: 40, display: 'flex' }}>
|
||||||
|
{BARS.map(([x, y, w, h, isSchool], i) => (
|
||||||
|
<div
|
||||||
|
key={x}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
left: x,
|
||||||
|
top: y,
|
||||||
|
width: w,
|
||||||
|
height: h,
|
||||||
|
borderRadius: 1.5,
|
||||||
|
background: isSchool ? BRAND : INK,
|
||||||
|
opacity: isSchool ? 1 : [0.22, 0.38, 0.55, 1, 0.22][i],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', fontSize: 29, fontWeight: 700, letterSpacing: '-0.028em' }}>
|
||||||
|
<span style={{ color: INK }}>School</span>
|
||||||
|
<span style={{ color: BRAND }}>Compare</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Proposition. Sized so the headline holds two lines and the subhead
|
||||||
|
one — an orphaned word reads as an accident at this size. */}
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
fontSize: 66,
|
||||||
|
fontWeight: 700,
|
||||||
|
letterSpacing: '-0.036em',
|
||||||
|
lineHeight: 1.03,
|
||||||
|
color: INK,
|
||||||
|
maxWidth: 1010,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
A score means nothing until you see the spread.
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', fontSize: 26, color: MUTED, letterSpacing: '-0.005em' }}>
|
||||||
|
24,000+ schools in England · SATs, GCSEs, Ofsted and admissions
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* The device, at poster scale. Same object as the mark above. */}
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'flex-end', gap: 7, height: 120 }}>
|
||||||
|
{SPREAD.map((h, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
height: `${h}%`,
|
||||||
|
borderRadius: 2,
|
||||||
|
background: i === LIT ? BRAND : INK,
|
||||||
|
opacity: i === LIT ? 1 : 0.15,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 18, color: MUTED, letterSpacing: '0.09em' }}>
|
||||||
|
<span>NATIONAL SPREAD</span>
|
||||||
|
<span style={{ letterSpacing: '-0.005em' }}>schoolcompare.co.uk</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
{
|
||||||
|
...size,
|
||||||
|
fonts: [
|
||||||
|
{ name: 'Schibsted', data: regular, weight: 400, style: 'normal' },
|
||||||
|
{ name: 'Schibsted', data: bold, weight: 700, style: 'normal' },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
@@ -9,6 +9,7 @@
|
|||||||
import { Line } from 'react-chartjs-2';
|
import { Line } from 'react-chartjs-2';
|
||||||
import { ChartOptions } from 'chart.js';
|
import { ChartOptions } from 'chart.js';
|
||||||
import '@/lib/chartSetup';
|
import '@/lib/chartSetup';
|
||||||
|
import { useThemeTokens, alpha } from '@/lib/theme';
|
||||||
import { formatAcademicYear } from '@/lib/utils';
|
import { formatAcademicYear } from '@/lib/utils';
|
||||||
import { fillAcademicYears } from '@/lib/compareChartData';
|
import { fillAcademicYears } from '@/lib/compareChartData';
|
||||||
import type { SchoolAdmissions } from '@/lib/types';
|
import type { SchoolAdmissions } from '@/lib/types';
|
||||||
@@ -38,6 +39,11 @@ export default function AdmissionsTrendChart({ history }: { history: SchoolAdmis
|
|||||||
const yMin = Math.max(0, Math.floor((lo - padded) / 5) * 5);
|
const yMin = Math.max(0, Math.floor((lo - padded) / 5) * 5);
|
||||||
const yMax = Math.min(100, Math.ceil((hi + padded) / 5) * 5);
|
const yMax = Math.min(100, Math.ceil((hi + padded) / 5) * 5);
|
||||||
|
|
||||||
|
// Canvas can't read var(), so pull the resolved tokens through the bridge.
|
||||||
|
const [cBrand, cGrid, cInverse, cInverseText, cCard] = useThemeTokens(
|
||||||
|
'--brand', '--chart-grid', '--surface-inverse', '--text-inverse', '--bg-card'
|
||||||
|
);
|
||||||
|
|
||||||
const options: ChartOptions<'line'> = {
|
const options: ChartOptions<'line'> = {
|
||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: false,
|
maintainAspectRatio: false,
|
||||||
@@ -49,7 +55,9 @@ export default function AdmissionsTrendChart({ history }: { history: SchoolAdmis
|
|||||||
legend: { display: false },
|
legend: { display: false },
|
||||||
title: { display: false },
|
title: { display: false },
|
||||||
tooltip: {
|
tooltip: {
|
||||||
backgroundColor: 'rgba(26,22,18,0.92)',
|
backgroundColor: cInverse,
|
||||||
|
titleColor: cInverseText,
|
||||||
|
bodyColor: cInverseText,
|
||||||
padding: 10,
|
padding: 10,
|
||||||
titleFont: { size: 12 },
|
titleFont: { size: 12 },
|
||||||
bodyFont: { size: 12 },
|
bodyFont: { size: 12 },
|
||||||
@@ -62,7 +70,7 @@ export default function AdmissionsTrendChart({ history }: { history: SchoolAdmis
|
|||||||
y: {
|
y: {
|
||||||
min: yMin,
|
min: yMin,
|
||||||
max: yMax,
|
max: yMax,
|
||||||
grid: { color: 'rgba(0,0,0,0.05)' },
|
grid: { color: cGrid },
|
||||||
ticks: { font: { size: 11 }, maxTicksLimit: 5, callback: (v) => `${v}%` },
|
ticks: { font: { size: 11 }, maxTicksLimit: 5, callback: (v) => `${v}%` },
|
||||||
},
|
},
|
||||||
x: {
|
x: {
|
||||||
@@ -80,14 +88,14 @@ export default function AdmissionsTrendChart({ history }: { history: SchoolAdmis
|
|||||||
data: values,
|
data: values,
|
||||||
clip: false as const,
|
clip: false as const,
|
||||||
spanGaps: false,
|
spanGaps: false,
|
||||||
borderColor: '#e07256',
|
borderColor: cBrand,
|
||||||
backgroundColor: 'rgba(224,114,86,0.10)',
|
backgroundColor: alpha('--brand', 0.10),
|
||||||
borderWidth: 2.5,
|
borderWidth: 2.5,
|
||||||
tension: 0.3,
|
tension: 0.3,
|
||||||
fill: true,
|
fill: true,
|
||||||
pointRadius: values.map((_, i) => (i === lastIdx ? 5 : 3)),
|
pointRadius: values.map((_, i) => (i === lastIdx ? 5 : 3)),
|
||||||
pointBackgroundColor: '#e07256',
|
pointBackgroundColor: cBrand,
|
||||||
pointBorderColor: '#fff',
|
pointBorderColor: cCard,
|
||||||
pointBorderWidth: values.map((_, i) => (i === lastIdx ? 2 : 0)),
|
pointBorderWidth: values.map((_, i) => (i === lastIdx ? 2 : 0)),
|
||||||
pointHoverRadius: 6,
|
pointHoverRadius: 6,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
margin-bottom: 0.85rem;
|
margin-bottom: 0.85rem;
|
||||||
padding-left: 0.85rem;
|
padding-left: 0.85rem;
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.1rem;
|
gap: 0.1rem;
|
||||||
border-left: 2px solid var(--border-color, #e5dfd5);
|
border-left: 2px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.navLink {
|
.navLink {
|
||||||
@@ -51,33 +51,33 @@
|
|||||||
border-left: 2px solid transparent;
|
border-left: 2px solid transparent;
|
||||||
font-size: 0.88rem;
|
font-size: 0.88rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: color 0.15s ease, border-color 0.15s ease;
|
transition: color 0.15s ease, border-color 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navLink:hover {
|
.navLink:hover {
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.navLinkActive {
|
.navLinkActive {
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--brand);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
border-left-color: var(--accent-teal, #2d7d7d);
|
border-left-color: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.navDot {
|
.navDot {
|
||||||
width: 6px;
|
width: 6px;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: var(--border-color, #e5dfd5);
|
background: var(--border);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
transition: background 0.15s ease;
|
transition: background 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navLinkActive .navDot {
|
.navLinkActive .navDot {
|
||||||
background: var(--accent-teal, #2d7d7d);
|
background: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ─── Hero ───────────────────────────────────────────── */
|
/* ─── Hero ───────────────────────────────────────────── */
|
||||||
@@ -95,8 +95,8 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--brand);
|
||||||
background: rgba(45, 125, 125, 0.1);
|
background: rgba(var(--brand-rgb), 0.1);
|
||||||
padding: 0.3rem 0.7rem;
|
padding: 0.3rem 0.7rem;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
@@ -107,22 +107,22 @@
|
|||||||
width: 6px;
|
width: 6px;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: var(--accent-teal, #2d7d7d);
|
background: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.heroTitle {
|
.heroTitle {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
font-size: 2.75rem;
|
font-size: 2.75rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1.1;
|
line-height: 1.1;
|
||||||
letter-spacing: -0.015em;
|
letter-spacing: -0.015em;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
margin-bottom: 0.85rem;
|
margin-bottom: 0.85rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.heroSub {
|
.heroSub {
|
||||||
font-size: 1.05rem;
|
font-size: 1.05rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
max-width: 640px;
|
max-width: 640px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
line-height: 1.55;
|
line-height: 1.55;
|
||||||
@@ -132,7 +132,7 @@
|
|||||||
|
|
||||||
.countdownSection {
|
.countdownSection {
|
||||||
padding: 0 0 2.5rem;
|
padding: 0 0 2.5rem;
|
||||||
border-bottom: 1px solid var(--border-color, #e5dfd5);
|
border-bottom: 1px solid var(--border);
|
||||||
margin-bottom: 2.5rem;
|
margin-bottom: 2.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.countdownRail {
|
.countdownRail {
|
||||||
@@ -155,11 +155,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chip {
|
.chip {
|
||||||
background: var(--bg-card, #fff);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 1rem 1.1rem 0.9rem;
|
padding: 1rem 1.1rem 0.9rem;
|
||||||
box-shadow: 0 2px 8px rgba(26, 22, 18, 0.06);
|
box-shadow: 0 2px 8px rgba(var(--shadow-rgb), 0.06);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.2rem;
|
gap: 0.2rem;
|
||||||
@@ -177,12 +177,12 @@
|
|||||||
border-radius: 12px 12px 0 0;
|
border-radius: 12px 12px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipDeadline::before { background: var(--accent-coral, #e07256); }
|
.chipDeadline::before { background: var(--brand); }
|
||||||
.chipOffer::before { background: var(--accent-teal, #2d7d7d); }
|
.chipOffer::before { background: var(--status-above); }
|
||||||
|
|
||||||
.chipUrgent {
|
.chipUrgent {
|
||||||
border-color: rgba(224, 114, 86, 0.4);
|
border-color: rgba(var(--status-below-rgb), 0.4);
|
||||||
background: rgba(224, 114, 86, 0.04);
|
background: rgba(var(--status-below-rgb), 0.04);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipTrack {
|
.chipTrack {
|
||||||
@@ -196,8 +196,8 @@
|
|||||||
margin-bottom: 0.15rem;
|
margin-bottom: 0.15rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipTrackDeadline { color: var(--accent-coral-dark, #b04a2e); }
|
.chipTrackDeadline { color: var(--brand-strong); }
|
||||||
.chipTrackOffer { color: var(--accent-teal, #2d7d7d); }
|
.chipTrackOffer { color: var(--status-above); }
|
||||||
|
|
||||||
.chipTrackDot {
|
.chipTrackDot {
|
||||||
width: 5px;
|
width: 5px;
|
||||||
@@ -208,7 +208,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chipDays {
|
.chipDays {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-variant-numeric: tabular-nums;
|
||||||
|
font-family: var(--font-display);
|
||||||
font-size: 2.6rem;
|
font-size: 2.6rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
@@ -217,17 +218,17 @@
|
|||||||
|
|
||||||
.chipDeadline .chipDays,
|
.chipDeadline .chipDays,
|
||||||
.chipUrgent .chipDays {
|
.chipUrgent .chipDays {
|
||||||
color: var(--accent-coral-dark, #c45a3f);
|
color: var(--status-below);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipOffer .chipDays {
|
.chipOffer .chipDays {
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--status-above);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipDaysUnit {
|
.chipDaysUnit {
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
margin-left: 0.2rem;
|
margin-left: 0.2rem;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
line-height: 2;
|
line-height: 2;
|
||||||
@@ -236,14 +237,14 @@
|
|||||||
.chipMilestone {
|
.chipMilestone {
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
margin-top: 0.1rem;
|
margin-top: 0.1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipDate {
|
.chipDate {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
margin-top: 0.05rem;
|
margin-top: 0.05rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,8 +252,8 @@
|
|||||||
|
|
||||||
.track {
|
.track {
|
||||||
margin-bottom: 3rem;
|
margin-bottom: 3rem;
|
||||||
background: var(--bg-card, #fff);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -263,7 +264,7 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
padding: 1.75rem 2rem 1.5rem;
|
padding: 1.75rem 2rem 1.5rem;
|
||||||
border-bottom: 1px solid var(--border-color, #e5dfd5);
|
border-bottom: 1px solid var(--border);
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,22 +279,22 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
margin-bottom: 0.35rem;
|
margin-bottom: 0.35rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.trackTitle {
|
.trackTitle {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
margin-bottom: 0.4rem;
|
margin-bottom: 0.4rem;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.trackSub {
|
.trackSub {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
@@ -317,13 +318,13 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.trackDateVal {
|
.trackDateVal {
|
||||||
font-size: 0.88rem;
|
font-size: 0.88rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ─── Timeline ───────────────────────────────────────── */
|
/* ─── Timeline ───────────────────────────────────────── */
|
||||||
@@ -356,27 +357,27 @@
|
|||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: var(--bg-card, #fff);
|
background: var(--bg-card);
|
||||||
border: 2px solid var(--border-color, #e5dfd5);
|
border: 2px solid var(--border);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
transition: border-color 0.2s ease, background 0.2s ease;
|
transition: border-color 0.2s ease, background 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stepDeadline .stepDot {
|
.stepDeadline .stepDot {
|
||||||
background: rgba(224, 114, 86, 0.15);
|
background: rgba(var(--brand-rgb), 0.15);
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stepOffer .stepDot {
|
.stepOffer .stepDot {
|
||||||
background: rgba(45, 125, 125, 0.15);
|
background: rgba(var(--status-above-rgb), 0.15);
|
||||||
border-color: var(--accent-teal, #2d7d7d);
|
border-color: var(--status-above);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stepLine {
|
.stepLine {
|
||||||
width: 2px;
|
width: 2px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 24px;
|
min-height: 24px;
|
||||||
background: var(--border-color, #e5dfd5);
|
background: var(--border);
|
||||||
margin: 4px 0;
|
margin: 4px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,27 +396,28 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.06em;
|
letter-spacing: 0.06em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
margin-bottom: 0.2rem;
|
margin-bottom: 0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stepDeadline .stepDate { color: var(--accent-coral-dark, #b04a2e); }
|
.stepDeadline .stepDate { color: var(--brand-strong); }
|
||||||
.stepOffer .stepDate { color: var(--accent-teal, #2d7d7d); }
|
.stepOffer .stepDate { color: var(--status-above); }
|
||||||
|
|
||||||
.stepTitle {
|
.stepTitle {
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
margin-bottom: 0.3rem;
|
margin-bottom: 0.3rem;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stepDeadline .stepTitle { color: var(--accent-coral-dark, #c45a3f); }
|
.stepDeadline .stepTitle { color: var(--brand-strong); }
|
||||||
.stepOffer .stepTitle { color: var(--accent-teal, #2d7d7d); }
|
.stepOffer .stepTitle { color: var(--status-above); }
|
||||||
|
|
||||||
.stepBody {
|
.stepBody {
|
||||||
|
font-family: var(--font-prose);
|
||||||
font-size: 0.88rem;
|
font-size: 0.88rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
line-height: 1.55;
|
line-height: 1.55;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
@@ -427,13 +429,13 @@
|
|||||||
margin-top: 0.6rem;
|
margin-top: 0.6rem;
|
||||||
font-size: 0.82rem;
|
font-size: 0.82rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--status-above);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: gap 0.2s ease, color 0.2s ease;
|
transition: gap 0.2s ease, color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stepTool:hover {
|
.stepTool:hover {
|
||||||
color: var(--accent-coral-dark, #c45a3f);
|
color: var(--brand-strong);
|
||||||
gap: 0.6rem;
|
gap: 0.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,9 +457,9 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.55rem;
|
gap: 0.55rem;
|
||||||
padding: 0.6rem 0.75rem;
|
padding: 0.6rem 0.75rem;
|
||||||
background: var(--accent-gold-bg, rgba(201, 162, 39, 0.12));
|
background: var(--status-below-bg);
|
||||||
border: 1px solid rgba(201, 162, 39, 0.28);
|
border: 1px solid rgba(var(--status-below-rgb), 0.28);
|
||||||
border-left: 3px solid var(--accent-gold, #c9a227);
|
border-left: 3px solid var(--status-below);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,8 +469,8 @@
|
|||||||
height: 1.05rem;
|
height: 1.05rem;
|
||||||
margin-top: 0.1rem;
|
margin-top: 0.1rem;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: var(--accent-gold, #c9a227);
|
background: var(--status-below);
|
||||||
color: #fff;
|
color: var(--text-inverse);
|
||||||
font-size: 0.72rem;
|
font-size: 0.72rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
line-height: 1.05rem;
|
line-height: 1.05rem;
|
||||||
@@ -482,14 +484,15 @@
|
|||||||
.calloutTitle {
|
.calloutTitle {
|
||||||
font-size: 0.82rem;
|
font-size: 0.82rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--accent-gold-text, #7a6800);
|
color: var(--status-below);
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
margin-bottom: 0.15rem;
|
margin-bottom: 0.15rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calloutBody {
|
.calloutBody {
|
||||||
|
font-family: var(--font-prose);
|
||||||
font-size: 0.82rem;
|
font-size: 0.82rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
@@ -501,10 +504,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tipsHeading {
|
.tipsHeading {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
font-size: 1.35rem;
|
font-size: 1.35rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
margin-bottom: 1.25rem;
|
margin-bottom: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,16 +518,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tipCard {
|
.tipCard {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 1.25rem;
|
padding: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tipNumber {
|
.tipNumber {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-variant-numeric: tabular-nums;
|
||||||
|
font-family: var(--font-display);
|
||||||
font-size: 1.75rem;
|
font-size: 1.75rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #7d766b; /* 3.8:1 on cream — AA large-text for this 28px numeral */
|
color: var(--text-muted); /* 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;
|
||||||
}
|
}
|
||||||
@@ -532,14 +536,15 @@
|
|||||||
.tipHeading {
|
.tipHeading {
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
margin-bottom: 0.4rem;
|
margin-bottom: 0.4rem;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tipBody {
|
.tipBody {
|
||||||
|
font-family: var(--font-prose);
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
line-height: 1.55;
|
line-height: 1.55;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
@@ -557,8 +562,8 @@
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
background: var(--bg-primary, #faf8f3);
|
background: var(--bg-primary);
|
||||||
border-bottom: 1px solid var(--border-color, #e5dfd5);
|
border-bottom: 1px solid var(--border);
|
||||||
margin: 0 -1.25rem 1rem;
|
margin: 0 -1.25rem 1rem;
|
||||||
padding: 0.6rem 1.25rem;
|
padding: 0.6rem 1.25rem;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
@@ -590,8 +595,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.navLinkActive {
|
.navLinkActive {
|
||||||
background: var(--text-primary, #1a1612);
|
background: var(--text-primary);
|
||||||
color: #fff;
|
color: var(--text-inverse);
|
||||||
border-left: none;
|
border-left: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding: 4px 10px;
|
padding: 4px 10px;
|
||||||
border: 1px solid rgba(0, 0, 0, .12);
|
border: 1px solid var(--border);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -52,8 +52,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chip[aria-pressed="true"] {
|
.chip[aria-pressed="true"] {
|
||||||
background: rgba(0, 0, 0, .06);
|
background: var(--bg-secondary);
|
||||||
border-color: rgba(0, 0, 0, .35);
|
border-color: var(--border-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipDot {
|
.chipDot {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { Line } from 'react-chartjs-2';
|
import { Line } from 'react-chartjs-2';
|
||||||
import { ChartOptions, ChartDataset, PointStyle } from 'chart.js';
|
import { ChartOptions, ChartDataset, PointStyle } from 'chart.js';
|
||||||
import '@/lib/chartSetup';
|
import '@/lib/chartSetup';
|
||||||
|
import { useSeriesColors, useThemeTokens } from '@/lib/theme';
|
||||||
import { buildCompareChart } from '@/lib/compareChartData';
|
import { buildCompareChart } from '@/lib/compareChartData';
|
||||||
import type { ComparisonData } from '@/lib/types';
|
import type { ComparisonData } from '@/lib/types';
|
||||||
import {
|
import {
|
||||||
@@ -48,6 +49,13 @@ const POINT_STYLES: PointStyle[] = ['circle', 'triangle', 'rect', 'rectRot', 'st
|
|||||||
|
|
||||||
export function ComparisonChart({ comparisonData, schools, metric, metricLabel, nationalByYear, isSecondary = false }: ComparisonChartProps) {
|
export function ComparisonChart({ comparisonData, schools, metric, metricLabel, nationalByYear, isSecondary = false }: ComparisonChartProps) {
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
|
// Canvas can't resolve var(), so the series come through the token bridge.
|
||||||
|
// Same index order as CHART_COLORS, so a school's line and its DOM swatch
|
||||||
|
// stay the same colour.
|
||||||
|
const seriesColors = useSeriesColors();
|
||||||
|
const [cRef, cGrid, cInverse, cInverseText] = useThemeTokens(
|
||||||
|
'--chart-reference', '--chart-grid', '--surface-inverse', '--text-inverse'
|
||||||
|
);
|
||||||
const [focusedUrn, setFocusedUrn] = useState<number | null>(null);
|
const [focusedUrn, setFocusedUrn] = useState<number | null>(null);
|
||||||
|
|
||||||
// A focused school that leaves the basket must not linger.
|
// A focused school that leaves the basket must not linger.
|
||||||
@@ -67,7 +75,7 @@ export function ComparisonChart({ comparisonData, schools, metric, metricLabel,
|
|||||||
|
|
||||||
const datasets: ChartDataset<'line'>[] = built.schoolDatasets.map((series) => {
|
const datasets: ChartDataset<'line'>[] = built.schoolDatasets.map((series) => {
|
||||||
const school = schools[series.schoolIndex];
|
const school = schools[series.schoolIndex];
|
||||||
const color = CHART_COLORS[series.schoolIndex % CHART_COLORS.length];
|
const color = seriesColors[series.schoolIndex % seriesColors.length];
|
||||||
const dimmed = focusedUrn !== null && focusedUrn !== school.urn;
|
const dimmed = focusedUrn !== null && focusedUrn !== school.urn;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -90,7 +98,7 @@ export function ComparisonChart({ comparisonData, schools, metric, metricLabel,
|
|||||||
datasets.push({
|
datasets.push({
|
||||||
label: built.englandDataset.label,
|
label: built.englandDataset.label,
|
||||||
data: built.englandDataset.data,
|
data: built.englandDataset.data,
|
||||||
borderColor: 'rgba(109, 104, 95, 0.9)',
|
borderColor: cRef,
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
borderWidth: 1.5,
|
borderWidth: 1.5,
|
||||||
borderDash: built.englandDataset.borderDash,
|
borderDash: built.englandDataset.borderDash,
|
||||||
@@ -138,7 +146,9 @@ export function ComparisonChart({ comparisonData, schools, metric, metricLabel,
|
|||||||
display: false,
|
display: false,
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
backgroundColor: cInverse,
|
||||||
|
titleColor: cInverseText,
|
||||||
|
bodyColor: cInverseText,
|
||||||
padding: isMobile ? 10 : 12,
|
padding: isMobile ? 10 : 12,
|
||||||
titleFont: {
|
titleFont: {
|
||||||
size: isMobile ? 12 : 14,
|
size: isMobile ? 12 : 14,
|
||||||
@@ -182,7 +192,7 @@ export function ComparisonChart({ comparisonData, schools, metric, metricLabel,
|
|||||||
...(isMobile && { maxTicksLimit: 5 }),
|
...(isMobile && { maxTicksLimit: 5 }),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
color: 'rgba(0, 0, 0, 0.05)',
|
color: cGrid,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
x: {
|
x: {
|
||||||
|
|||||||
@@ -23,11 +23,11 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0;
|
gap: 0;
|
||||||
padding: 1rem 1.25rem;
|
padding: 1rem 1.25rem;
|
||||||
background: var(--bg-primary, #faf7f2);
|
background: var(--bg-primary);
|
||||||
color: var(--text-primary, #2c2420);
|
color: var(--text-primary);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: 0 8px 32px rgba(44, 36, 32, 0.18), 0 2px 8px rgba(44, 36, 32, 0.08);
|
box-shadow: 0 8px 32px rgba(var(--shadow-rgb), 0.18), 0 2px 8px rgba(var(--shadow-rgb), 0.08);
|
||||||
border: 1px solid var(--border-color, #e8ddd4);
|
border: 1px solid var(--border);
|
||||||
min-width: 280px;
|
min-width: 280px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,8 +37,8 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--brand);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
@@ -62,13 +62,13 @@
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: var(--text-primary, #2c2420);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.collapseBtn {
|
.collapseBtn {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
color: var(--text-muted, #8a7a72);
|
color: var(--text-muted);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 0.25rem;
|
padding: 0.25rem;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.collapseBtn:hover {
|
.collapseBtn:hover {
|
||||||
color: var(--text-primary, #2c2420);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.schoolList {
|
.schoolList {
|
||||||
@@ -95,13 +95,13 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
padding: 0.3rem 0.5rem;
|
padding: 0.3rem 0.5rem;
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-radius: var(--radius-sm, 4px);
|
border-radius: var(--radius-sm, 4px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.schoolName {
|
.schoolName {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
color: var(--text-primary, #2c2420);
|
color: var(--text-primary);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
.removeSchoolBtn {
|
.removeSchoolBtn {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
color: var(--text-muted, #8a7a72);
|
color: var(--text-muted);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
padding: 0 0.25rem;
|
padding: 0 0.25rem;
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.removeSchoolBtn:hover {
|
.removeSchoolBtn:hover {
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.toastActions {
|
.toastActions {
|
||||||
@@ -129,13 +129,13 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
padding-top: 0.625rem;
|
padding-top: 0.625rem;
|
||||||
border-top: 1px solid var(--border-color, #e8ddd4);
|
border-top: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btnClearAll {
|
.btnClearAll {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
color: var(--text-muted, #8a7a72);
|
color: var(--text-muted);
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -145,13 +145,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btnClearAll:hover {
|
.btnClearAll:hover {
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btnCompare {
|
.btnCompare {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--brand);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
padding: 0.6rem 1.25rem;
|
padding: 0.6rem 1.25rem;
|
||||||
border-radius: 25px;
|
border-radius: 25px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -164,7 +164,7 @@
|
|||||||
|
|
||||||
.btnCompare:hover {
|
.btnCompare:hover {
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
background: var(--accent-coral-dark, #c9614a);
|
background: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hidden on phones — the bottom tab bar's Compare badge already
|
/* Hidden on phones — the bottom tab bar's Compare badge already
|
||||||
|
|||||||
@@ -18,14 +18,14 @@
|
|||||||
.header h1 {
|
.header h1 {
|
||||||
font-size: 2.25rem;
|
font-size: 2.25rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
max-width: 60ch;
|
max-width: 60ch;
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 0;
|
gap: 0;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
@@ -53,8 +53,8 @@
|
|||||||
padding: 0.625rem 1.5rem;
|
padding: 0.625rem 1.5rem;
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.15s ease;
|
transition: all 0.15s ease;
|
||||||
@@ -62,21 +62,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.phaseTab:not(:last-child) {
|
.phaseTab:not(:last-child) {
|
||||||
border-right: 1px solid var(--border-color, #e5dfd5);
|
border-right: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.phaseTab:hover {
|
.phaseTab:hover {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.phaseTabActive {
|
.phaseTabActive {
|
||||||
background: var(--accent-coral-dark, #b04a2e);
|
background: var(--brand-strong);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phaseTabActive:hover {
|
.phaseTabActive:hover {
|
||||||
background: var(--accent-coral-darker, #9c3f26);
|
background: var(--brand-stronger);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sticky school bar — column identity while scrolling; horizontal scroll on
|
/* Sticky school bar — column identity while scrolling; horizontal scroll on
|
||||||
@@ -87,23 +87,23 @@
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 65px;
|
top: 65px;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
background: var(--bg-primary, #faf7f2);
|
background: var(--bg-primary);
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
padding: 0.75rem 0;
|
padding: 0.75rem 0;
|
||||||
border-bottom: 1px solid var(--border-light, #e5dfd5);
|
border-bottom: 1px solid var(--border);
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.schoolChip {
|
.schoolChip {
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
min-width: 180px;
|
min-width: 180px;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-light, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-top: 3px solid var(--accent-coral, #e07256);
|
border-top: 3px solid var(--brand);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: var(--shadow-soft, 0 2px 8px rgba(26, 22, 18, 0.06));
|
box-shadow: var(--shadow-soft, 0 2px 8px rgba(var(--shadow-rgb), 0.06));
|
||||||
padding: 0.55rem 0.75rem;
|
padding: 0.55rem 0.75rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.55rem;
|
gap: 0.55rem;
|
||||||
@@ -126,12 +126,12 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 0.92rem;
|
font-size: 0.92rem;
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipName:hover {
|
.chipName:hover {
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Full name on desktop, short name on the compact mobile pills. */
|
/* Full name on desktop, short name on the compact mobile pills. */
|
||||||
@@ -142,7 +142,7 @@
|
|||||||
.chipMeta {
|
.chipMeta {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@@ -185,22 +185,22 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
letter-spacing: 0.06em;
|
letter-spacing: 0.06em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.barCaptionCount {
|
.barCaptionCount {
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipRemove {
|
.chipRemove {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
border: none;
|
border: none;
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
@@ -212,9 +212,9 @@
|
|||||||
|
|
||||||
.footnote {
|
.footnote {
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
margin-top: 2.5rem;
|
margin-top: 2.5rem;
|
||||||
border-top: 1px solid var(--border-light, #e5dfd5);
|
border-top: 1px solid var(--border);
|
||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
max-width: 75ch;
|
max-width: 75ch;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,16 +23,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.good {
|
.good {
|
||||||
background: var(--accent-teal-bg, rgba(45, 125, 125, 0.12));
|
background: var(--status-above-bg);
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--status-above);
|
||||||
}
|
}
|
||||||
|
|
||||||
.bad {
|
.bad {
|
||||||
background: var(--accent-coral-bg, rgba(224, 114, 86, 0.12));
|
background: var(--status-below-bg);
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--status-below);
|
||||||
}
|
}
|
||||||
|
|
||||||
.neutral {
|
.neutral {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
border: 2px solid var(--bg-card);
|
border: 2px solid var(--bg-card);
|
||||||
box-shadow: 0 0 0 1px rgba(26, 22, 18, 0.08);
|
box-shadow: 0 0 0 1px rgba(var(--shadow-rgb), 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pointLabel {
|
.pointLabel {
|
||||||
|
|||||||
@@ -5,15 +5,15 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 4rem 2rem;
|
padding: 4rem 2rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 2px solid var(--border-color, #e5dfd5);
|
border: 2px solid var(--border);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
min-height: 400px;
|
min-height: 400px;
|
||||||
box-shadow: var(--shadow-soft, 0 2px 8px rgba(26, 22, 18, 0.06));
|
box-shadow: var(--shadow-soft, 0 2px 8px rgba(var(--shadow-rgb), 0.06));
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
@@ -22,14 +22,14 @@
|
|||||||
margin: 0 0 0.75rem 0;
|
margin: 0 0 0.75rem 0;
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
}
|
}
|
||||||
|
|
||||||
.message {
|
.message {
|
||||||
margin: 0 0 2rem 0;
|
margin: 0 0 2rem 0;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
@@ -38,8 +38,8 @@
|
|||||||
padding: 0.875rem 2rem;
|
padding: 0.875rem 2rem;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--brand);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -47,9 +47,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.button:hover {
|
.button:hover {
|
||||||
background: var(--accent-coral-dark, #c45a3f);
|
background: var(--brand-strong);
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
box-shadow: 0 4px 12px rgba(224, 114, 86, 0.3);
|
box-shadow: 0 4px 12px rgba(var(--brand-rgb), 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:active {
|
.button:active {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
.filterBar {
|
.filterBar {
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
box-shadow: var(--shadow-soft, 0 2px 8px rgba(26, 22, 18, 0.06));
|
box-shadow: var(--shadow-soft, 0 2px 8px rgba(var(--shadow-rgb), 0.06));
|
||||||
transition: opacity 0.2s ease;
|
transition: opacity 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,9 +17,9 @@
|
|||||||
padding: 2.5rem;
|
padding: 2.5rem;
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
margin: 0 auto 3rem auto;
|
margin: 0 auto 3rem auto;
|
||||||
box-shadow: 0 8px 24px rgba(26, 22, 18, 0.08);
|
box-shadow: 0 8px 24px rgba(var(--shadow-rgb), 0.08);
|
||||||
border-width: 2px;
|
border-width: 2px;
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.heroMode .omniInput {
|
.heroMode .omniInput {
|
||||||
@@ -39,12 +39,12 @@
|
|||||||
.searchHint {
|
.searchHint {
|
||||||
margin: 0.875rem 0 0;
|
margin: 0.875rem 0 0;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
color: var(--text-secondary, #5a554d);
|
color: var(--text-secondary);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchHint strong {
|
.searchHint strong {
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,8 +68,8 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
padding: 0.625rem 1.375rem;
|
padding: 0.625rem 1.375rem;
|
||||||
background: var(--accent-teal, #2d7d7d);
|
background: var(--brand);
|
||||||
color: #fff;
|
color: var(--brand-on);
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nearMeBtn:hover:not(:disabled) {
|
.nearMeBtn:hover:not(:disabled) {
|
||||||
background: #235f5f;
|
background: var(--status-above);
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,8 +93,8 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
border: 2px solid rgba(255, 255, 255, 0.35);
|
border: 2px solid rgba(var(--text-inverse-rgb), 0.35);
|
||||||
border-top-color: #fff;
|
border-top-color: var(--brand-on);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
animation: nearMeSpin 0.7s linear infinite;
|
animation: nearMeSpin 0.7s linear infinite;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
@@ -108,7 +108,7 @@
|
|||||||
|
|
||||||
.geoError {
|
.geoError {
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
max-width: 340px;
|
max-width: 340px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -134,21 +134,21 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 0.875rem 1.25rem;
|
padding: 0.875rem 1.25rem;
|
||||||
font-size: 1.05rem;
|
font-size: 1.05rem;
|
||||||
border: 2px solid var(--border-color, #e5dfd5);
|
border: 2px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
outline: none;
|
outline: none;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.omniInput:focus {
|
.omniInput:focus {
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
box-shadow: 0 0 0 3px var(--accent-coral-bg);
|
box-shadow: 0 0 0 3px var(--brand-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.omniInput::placeholder {
|
.omniInput::placeholder {
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchButton {
|
.searchButton {
|
||||||
@@ -161,9 +161,9 @@
|
|||||||
.spinner {
|
.spinner {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
border: 2px solid rgba(var(--text-inverse-rgb), 0.3);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
border-top-color: white;
|
border-top-color: var(--brand-on);
|
||||||
animation: spin 0.8s linear infinite;
|
animation: spin 0.8s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin-top: 0.625rem;
|
margin-top: 0.625rem;
|
||||||
padding-top: 0.625rem;
|
padding-top: 0.625rem;
|
||||||
border-top: 1px solid var(--border-color, #e5dfd5);
|
border-top: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.filterSelect {
|
.filterSelect {
|
||||||
@@ -189,26 +189,26 @@
|
|||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
border: 1.5px solid var(--border-color, #e5dfd5);
|
border: 1.5px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background-color: var(--bg-card, white);
|
background-color: var(--bg-card);
|
||||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238a847a' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238a847a' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: right 0.875rem center;
|
background-position: right 0.875rem center;
|
||||||
background-size: 10px 6px;
|
background-size: 10px 6px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
outline: none;
|
outline: none;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filterSelect:hover {
|
.filterSelect:hover {
|
||||||
border-color: var(--text-muted, #8a847a);
|
border-color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.filterSelect:focus {
|
.filterSelect:focus {
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
box-shadow: 0 0 0 3px rgba(224, 114, 86, 0.12);
|
box-shadow: 0 0 0 3px rgba(var(--brand-rgb), 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.clearButton {
|
.clearButton {
|
||||||
@@ -263,7 +263,7 @@
|
|||||||
.radiusLabel {
|
.radiusLabel {
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-secondary, #5a554d);
|
color: var(--text-secondary);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,7 +275,7 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin-top: 0.875rem;
|
margin-top: 0.875rem;
|
||||||
padding-top: 0.875rem;
|
padding-top: 0.875rem;
|
||||||
border-top: 1px solid var(--border-color, #e5dfd5);
|
border-top: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.controlsRow .advancedToggle {
|
.controlsRow .advancedToggle {
|
||||||
@@ -297,14 +297,14 @@
|
|||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
border: 1.5px solid var(--border-color, #e5dfd5);
|
border: 1.5px solid var(--border);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background-color: var(--bg-card, white);
|
background-color: var(--bg-card);
|
||||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238a847a' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238a847a' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: right 0.65rem center;
|
background-position: right 0.65rem center;
|
||||||
background-size: 10px 6px;
|
background-size: 10px 6px;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
outline: none;
|
outline: none;
|
||||||
transition: border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
|
transition: border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
|
||||||
@@ -312,13 +312,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.controlSelect:hover {
|
.controlSelect:hover {
|
||||||
border-color: var(--text-muted, #8a847a);
|
border-color: var(--text-muted);
|
||||||
background-color: var(--bg-secondary, #f8f4ef);
|
background-color: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.controlSelect:focus {
|
.controlSelect:focus {
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
box-shadow: 0 0 0 3px rgba(224, 114, 86, 0.12);
|
box-shadow: 0 0 0 3px rgba(var(--brand-rgb), 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Advanced filters toggle ─────────────────────────── */
|
/* ── Advanced filters toggle ─────────────────────────── */
|
||||||
@@ -328,12 +328,12 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.375rem;
|
gap: 0.375rem;
|
||||||
background: none;
|
background: none;
|
||||||
border: 1.5px solid var(--border-color, #e5dfd5);
|
border: 1.5px solid var(--border);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
padding: 0.4rem 0.875rem;
|
padding: 0.4rem 0.875rem;
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-secondary, #5a554d);
|
color: var(--text-secondary);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
transition: all 0.15s ease;
|
transition: all 0.15s ease;
|
||||||
@@ -341,24 +341,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.advancedToggle:hover {
|
.advancedToggle:hover {
|
||||||
border-color: var(--text-muted, #8a847a);
|
border-color: var(--text-muted);
|
||||||
background-color: var(--bg-secondary, #f8f4ef);
|
background-color: var(--bg-secondary);
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When filters are applied, promote the toggle to a coral pill so users
|
/* When filters are applied, promote the toggle to a coral pill so users
|
||||||
can see at a glance that the result list is being narrowed. */
|
can see at a glance that the result list is being narrowed. */
|
||||||
.advancedToggleActive {
|
.advancedToggleActive {
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
background: var(--accent-coral-bg, rgba(224, 114, 86, 0.12));
|
background: var(--brand-bg);
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--brand);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.advancedToggleActive:hover {
|
.advancedToggleActive:hover {
|
||||||
border-color: var(--accent-coral-dark, #c45a3f);
|
border-color: var(--brand-strong);
|
||||||
background: var(--accent-coral-bg, rgba(224, 114, 86, 0.18));
|
background: var(--brand-bg);
|
||||||
color: var(--accent-coral-dark, #c45a3f);
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chevronDown,
|
.chevronDown,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.footer {
|
.footer {
|
||||||
background: var(--accent-navy, #2c3e50);
|
background: var(--text-primary);
|
||||||
color: var(--bg-secondary, #f3ede4);
|
color: var(--bg-secondary);
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,22 +27,22 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--bg-primary, #faf7f2);
|
color: var(--bg-primary);
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
}
|
}
|
||||||
|
|
||||||
.description {
|
.description {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
color: rgba(250, 247, 242, 0.7);
|
color: rgba(var(--text-inverse-rgb), 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sectionTitle {
|
.sectionTitle {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--accent-gold, #c9a227);
|
color: var(--status-below);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.05em;
|
||||||
}
|
}
|
||||||
@@ -58,24 +58,24 @@
|
|||||||
|
|
||||||
.link {
|
.link {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: rgba(250, 247, 242, 0.7);
|
color: rgba(var(--text-inverse-rgb), 0.7);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: color 0.2s ease;
|
transition: color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link:hover {
|
.link:hover {
|
||||||
color: var(--accent-gold, #c9a227);
|
color: var(--status-below);
|
||||||
}
|
}
|
||||||
|
|
||||||
.linkDisabled {
|
.linkDisabled {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: rgba(250, 247, 242, 0.4);
|
color: rgba(var(--text-inverse-rgb), 0.4);
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottom {
|
.bottom {
|
||||||
padding-top: 2rem;
|
padding-top: 2rem;
|
||||||
border-top: 1px solid rgba(250, 247, 242, 0.15);
|
border-top: 1px solid rgba(var(--text-inverse-rgb), 0.15);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
@@ -85,15 +85,15 @@
|
|||||||
.disclaimer {
|
.disclaimer {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: rgba(250, 247, 242, 0.6);
|
color: rgba(var(--text-inverse-rgb), 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.disclaimer .link {
|
.disclaimer .link {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.disclaimer .link:hover {
|
.disclaimer .link:hover {
|
||||||
color: var(--accent-gold, #c9a227);
|
color: var(--status-below);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--brand);
|
||||||
background: rgba(45, 125, 125, 0.1);
|
background: rgba(var(--brand-rgb), 0.1);
|
||||||
padding: 0.3rem 0.7rem;
|
padding: 0.3rem 0.7rem;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
@@ -28,37 +28,37 @@
|
|||||||
width: 6px;
|
width: 6px;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: var(--accent-teal, #2d7d7d);
|
background: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.heroTitle {
|
.heroTitle {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
margin-bottom: 0.85rem;
|
margin-bottom: 0.85rem;
|
||||||
line-height: 1.08;
|
line-height: 1.08;
|
||||||
letter-spacing: -0.015em;
|
letter-spacing: -0.015em;
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
max-width: 840px;
|
max-width: 840px;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.heroEmph {
|
.heroEmph {
|
||||||
color: var(--accent-coral-dark, #c45a3f);
|
color: var(--brand-strong);
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
.heroDescription {
|
.heroDescription {
|
||||||
font-size: 1.05rem;
|
font-size: 1.05rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
margin: 0 auto 0.5rem;
|
margin: 0 auto 0.5rem;
|
||||||
max-width: 680px;
|
max-width: 680px;
|
||||||
line-height: 1.55;
|
line-height: 1.55;
|
||||||
}
|
}
|
||||||
|
|
||||||
.heroDescription strong {
|
.heroDescription strong {
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
.viewToggle {
|
.viewToggle {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.2rem;
|
gap: 0.2rem;
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
padding: 0.2rem;
|
padding: 0.2rem;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
@@ -127,18 +127,18 @@
|
|||||||
border: none;
|
border: none;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.viewToggleBtn:hover {
|
.viewToggleBtn:hover {
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.viewToggleBtn.active {
|
.viewToggleBtn.active {
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
box-shadow: 0 2px 4px rgba(26, 22, 18, 0.08);
|
box-shadow: 0 2px 4px rgba(var(--shadow-rgb), 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
.viewToggleBtn svg {
|
.viewToggleBtn svg {
|
||||||
@@ -166,7 +166,7 @@
|
|||||||
.mapContainer {
|
.mapContainer {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,17 +184,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.compactList::-webkit-scrollbar-track {
|
.compactList::-webkit-scrollbar-track {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compactList::-webkit-scrollbar-thumb {
|
.compactList::-webkit-scrollbar-thumb {
|
||||||
background: var(--border-color, #e5dfd5);
|
background: var(--border);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compactList::-webkit-scrollbar-thumb:hover {
|
.compactList::-webkit-scrollbar-thumb:hover {
|
||||||
background: var(--text-muted, #8a847a);
|
background: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compact School Item */
|
/* Compact School Item */
|
||||||
@@ -204,15 +204,15 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
padding: 0.625rem 0.75rem;
|
padding: 0.625rem 0.75rem;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compactItem:hover {
|
.compactItem:hover {
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
box-shadow: 0 2px 6px rgba(26, 22, 18, 0.05);
|
box-shadow: 0 2px 6px rgba(var(--shadow-rgb), 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.compactItemContent {
|
.compactItemContent {
|
||||||
@@ -230,7 +230,7 @@
|
|||||||
.compactItemName {
|
.compactItemName {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -238,7 +238,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.compactItemName:hover {
|
.compactItemName:hover {
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.distanceBadge {
|
.distanceBadge {
|
||||||
@@ -246,8 +246,8 @@
|
|||||||
padding: 0.0625rem 0.375rem;
|
padding: 0.0625rem 0.375rem;
|
||||||
font-size: 0.6875rem;
|
font-size: 0.6875rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background: var(--accent-teal, #2d7d7d);
|
background: var(--brand);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,25 +255,25 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.375rem;
|
gap: 0.375rem;
|
||||||
font-size: 0.6875rem;
|
font-size: 0.6875rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compactItemMeta span:not(:last-child)::after {
|
.compactItemMeta span:not(:last-child)::after {
|
||||||
content: '·';
|
content: '·';
|
||||||
margin-left: 0.375rem;
|
margin-left: 0.375rem;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.compactItemStats {
|
.compactItemStats {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
font-size: 0.6875rem;
|
font-size: 0.6875rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.compactStat strong {
|
.compactStat strong {
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.compactItemActions {
|
.compactItemActions {
|
||||||
@@ -292,8 +292,8 @@
|
|||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decorative coral bar under section headings */
|
/* Decorative coral bar under section headings */
|
||||||
@@ -302,14 +302,14 @@
|
|||||||
display: block;
|
display: block;
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 2px;
|
height: 2px;
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--brand);
|
||||||
border-radius: 1px;
|
border-radius: 1px;
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sectionDescription {
|
.sectionDescription {
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
@@ -336,22 +336,22 @@
|
|||||||
.emptyState {
|
.emptyState {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 2.5rem 1.5rem;
|
padding: 2.5rem 1.5rem;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emptyStateTitle {
|
.emptyStateTitle {
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
margin-bottom: 0.375rem;
|
margin-bottom: 0.375rem;
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
}
|
}
|
||||||
|
|
||||||
.emptyStateDescription {
|
.emptyStateDescription {
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
max-width: 380px;
|
max-width: 380px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
@@ -419,9 +419,9 @@
|
|||||||
|
|
||||||
/* Highlighted List Item */
|
/* Highlighted List Item */
|
||||||
.highlightedItem .compactItem {
|
.highlightedItem .compactItem {
|
||||||
border-color: var(--accent-teal, #2d7d7d);
|
border-color: var(--brand);
|
||||||
box-shadow: 0 0 0 1px var(--accent-teal, #2d7d7d);
|
box-shadow: 0 0 0 1px var(--brand);
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mobile Bottom Sheet */
|
/* Mobile Bottom Sheet */
|
||||||
@@ -443,9 +443,9 @@
|
|||||||
|
|
||||||
.bottomSheet {
|
.bottomSheet {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
box-shadow: 0 -4px 24px rgba(26, 22, 18, 0.15);
|
box-shadow: 0 -4px 24px rgba(var(--shadow-rgb), 0.15);
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
animation: slideUpSheet 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
animation: slideUpSheet 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
||||||
}
|
}
|
||||||
@@ -467,16 +467,16 @@
|
|||||||
right: -12px;
|
right: -12px;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-shadow: 0 2px 8px rgba(26, 22, 18, 0.1);
|
box-shadow: 0 2px 8px rgba(var(--shadow-rgb), 0.1);
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,7 +522,7 @@
|
|||||||
.quickSearchChip {
|
.quickSearchChip {
|
||||||
padding: 0.375rem 0.875rem;
|
padding: 0.375rem 0.875rem;
|
||||||
background: var(--bg-card);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e0ddd8);
|
border: 1px solid var(--border);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
@@ -531,9 +531,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.quickSearchChip:hover {
|
.quickSearchChip:hover {
|
||||||
background: var(--accent-coral-dark);
|
background: var(--brand-strong);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
border-color: var(--accent-coral-dark);
|
border-color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.exploringRow {
|
.exploringRow {
|
||||||
@@ -546,7 +546,7 @@
|
|||||||
|
|
||||||
.exploringLabel {
|
.exploringLabel {
|
||||||
font-size: 0.72rem;
|
font-size: 0.72rem;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
@@ -564,19 +564,19 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.4rem;
|
gap: 0.4rem;
|
||||||
padding: 0.5rem 0.95rem;
|
padding: 0.5rem 0.95rem;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
font-size: 0.82rem;
|
font-size: 0.82rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: all 0.15s ease;
|
transition: all 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.exploringChip:hover {
|
.exploringChip:hover {
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
color: var(--accent-coral-dark, #c45a3f);
|
color: var(--brand-strong);
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -606,16 +606,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hiwHeading {
|
.hiwHeading {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
font-size: 1.75rem;
|
font-size: 1.75rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hiwSub {
|
.hiwSub {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hiwGrid {
|
.hiwGrid {
|
||||||
@@ -625,18 +625,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hiwCard {
|
.hiwCard {
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
padding: 1.25rem;
|
padding: 1.25rem;
|
||||||
box-shadow: 0 2px 8px rgba(26, 22, 18, 0.06);
|
box-shadow: 0 2px 8px rgba(var(--shadow-rgb), 0.06);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.9rem;
|
gap: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hiwVisual {
|
.hiwVisual {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 0.9rem;
|
padding: 0.9rem;
|
||||||
min-height: 180px;
|
min-height: 180px;
|
||||||
@@ -657,11 +657,11 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hiwPhaseLabel strong {
|
.hiwPhaseLabel strong {
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--brand);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,20 +676,20 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hiwTitle {
|
.hiwTitle {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hiwDesc {
|
.hiwDesc {
|
||||||
font-size: 0.86rem;
|
font-size: 0.86rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
line-height: 1.45;
|
line-height: 1.45;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
@@ -713,7 +713,7 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
margin-bottom: 0.1rem;
|
margin-bottom: 0.1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -723,16 +723,16 @@
|
|||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
gap: 0.2rem;
|
gap: 0.2rem;
|
||||||
font-size: 0.44rem;
|
font-size: 0.44rem;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.01em;
|
letter-spacing: 0.01em;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.miniRowHead strong {
|
.miniRowHead strong {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
font-size: 0.62rem;
|
font-size: 0.62rem;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0;
|
letter-spacing: 0;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
@@ -741,7 +741,7 @@
|
|||||||
.miniTrack {
|
.miniTrack {
|
||||||
height: 5px;
|
height: 5px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background: rgba(45, 125, 125, 0.08);
|
background: rgba(var(--status-above-rgb), 0.08);
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
@@ -749,21 +749,21 @@
|
|||||||
.miniBarExp {
|
.miniBarExp {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background: var(--accent-teal-light, #3a9e9e);
|
background: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.miniBarExc {
|
.miniBarExc {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background: var(--accent-teal, #2d7d7d);
|
background: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.miniNatPill {
|
.miniNatPill {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -9px;
|
top: -9px;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--brand);
|
||||||
color: #fff;
|
color: var(--text-inverse);
|
||||||
font-size: 0.4rem;
|
font-size: 0.4rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
padding: 0.05rem 0.2rem;
|
padding: 0.05rem 0.2rem;
|
||||||
@@ -791,21 +791,21 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
font-size: 0.5rem;
|
font-size: 0.5rem;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.05em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.att8Track {
|
.att8Track {
|
||||||
height: 7px;
|
height: 7px;
|
||||||
background: rgba(45, 125, 125, 0.08);
|
background: rgba(var(--status-above-rgb), 0.08);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.att8Fill {
|
.att8Fill {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: var(--accent-teal, #2d7d7d);
|
background: var(--brand);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,25 +814,28 @@
|
|||||||
top: -2px;
|
top: -2px;
|
||||||
bottom: -2px;
|
bottom: -2px;
|
||||||
width: 1.5px;
|
width: 1.5px;
|
||||||
background: rgba(224, 114, 86, 0.6);
|
background: rgba(var(--brand-rgb), 0.6);
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.att8Score {
|
.att8Score {
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.att8Value {
|
.att8Value {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-variant-numeric: tabular-nums;
|
||||||
|
font-family: var(--font-display);
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--status-above);
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.att8Delta {
|
.att8Delta {
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
font-size: 0.55rem;
|
font-size: 0.55rem;
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--status-above);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
@@ -853,31 +856,31 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
padding-bottom: 0.4rem;
|
padding-bottom: 0.4rem;
|
||||||
border-bottom: 1.5px solid var(--border-color, #e5dfd5);
|
border-bottom: 1.5px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ofstedBullet {
|
.ofstedBullet {
|
||||||
display: block;
|
display: block;
|
||||||
width: 3px;
|
width: 3px;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--brand);
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ofstedTitle {
|
.ofstedTitle {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ofstedFramework {
|
.ofstedFramework {
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
padding: 0.15rem 0.5rem;
|
padding: 0.15rem 0.5rem;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: rgba(90, 58, 110, 0.12);
|
background: rgba(var(--phase-secondary-rgb), 0.12);
|
||||||
color: #5a3a6e;
|
color: var(--phase-secondary-text);
|
||||||
font-size: 0.5rem;
|
font-size: 0.5rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.05em;
|
||||||
@@ -899,7 +902,7 @@
|
|||||||
|
|
||||||
.rcArea {
|
.rcArea {
|
||||||
font-size: 0.62rem;
|
font-size: 0.62rem;
|
||||||
color: var(--text-secondary, #4a453d);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rcChip {
|
.rcChip {
|
||||||
@@ -913,13 +916,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.rcChipGood {
|
.rcChipGood {
|
||||||
background: rgba(45, 125, 125, 0.12);
|
background: rgba(var(--status-above-rgb), 0.12);
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--status-above);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rcChipNeutral {
|
.rcChipNeutral {
|
||||||
background: var(--accent-gold-bg, rgba(180, 150, 40, 0.12));
|
background: var(--status-below-bg);
|
||||||
color: var(--accent-gold-text, #7a6800);
|
color: var(--status-below);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Safeguarding is a separate binary met/not-met judgement, not a graded area,
|
/* Safeguarding is a separate binary met/not-met judgement, not a graded area,
|
||||||
@@ -931,30 +934,30 @@
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
margin-top: 0.05rem;
|
margin-top: 0.05rem;
|
||||||
padding-top: 0.35rem;
|
padding-top: 0.35rem;
|
||||||
border-top: 1px dashed var(--border-color, #e5dfd5);
|
border-top: 1px dashed var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rcSep {
|
.rcSep {
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rcChipMet {
|
.rcChipMet {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--status-above);
|
||||||
border: 1px solid rgba(45, 125, 125, 0.4);
|
border: 1px solid rgba(var(--status-above-rgb), 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ofstedMeta {
|
.ofstedMeta {
|
||||||
font-size: 0.6rem;
|
font-size: 0.6rem;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compare preview */
|
/* Compare preview */
|
||||||
.comparePreview {
|
.comparePreview {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 0.6rem;
|
font-size: 0.6rem;
|
||||||
@@ -963,23 +966,23 @@
|
|||||||
.compareHead {
|
.compareHead {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr repeat(2, 1fr);
|
grid-template-columns: 1fr repeat(2, 1fr);
|
||||||
background: rgba(45, 125, 125, 0.1);
|
background: rgba(var(--status-above-rgb), 0.1);
|
||||||
padding: 0.35rem 0.5rem;
|
padding: 0.35rem 0.5rem;
|
||||||
gap: 0.35rem;
|
gap: 0.35rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compareHeadCell {
|
.compareHeadCell {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
font-size: 0.62rem;
|
font-size: 0.62rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--status-above);
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compareHeadLabel {
|
.compareHeadLabel {
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: 0.48rem;
|
font-size: 0.48rem;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
@@ -990,37 +993,37 @@
|
|||||||
grid-template-columns: 1fr repeat(2, 1fr);
|
grid-template-columns: 1fr repeat(2, 1fr);
|
||||||
padding: 0.3rem 0.5rem;
|
padding: 0.3rem 0.5rem;
|
||||||
gap: 0.35rem;
|
gap: 0.35rem;
|
||||||
border-top: 1px solid var(--border-color, #e5dfd5);
|
border-top: 1px solid var(--border);
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compareRowLabel {
|
.compareRowLabel {
|
||||||
font-size: 0.55rem;
|
font-size: 0.55rem;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.05em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compareRowVal {
|
.compareRowVal {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
font-size: 0.72rem;
|
font-size: 0.72rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.compareRowValHi {
|
.compareRowValHi {
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--status-above);
|
||||||
}
|
}
|
||||||
|
|
||||||
.compareFoot {
|
.compareFoot {
|
||||||
font-size: 0.52rem;
|
font-size: 0.52rem;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
padding: 0.35rem 0.5rem;
|
padding: 0.35rem 0.5rem;
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.06em;
|
letter-spacing: 0.06em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-top: 1px solid var(--border-color, #e5dfd5);
|
border-top: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
@@ -1065,8 +1068,8 @@
|
|||||||
grid-template-columns: 1.4fr 1fr;
|
grid-template-columns: 1.4fr 1fr;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
padding: 1.75rem;
|
padding: 1.75rem;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1078,30 +1081,34 @@
|
|||||||
|
|
||||||
.editorialKicker {
|
.editorialKicker {
|
||||||
font-size: 0.68rem;
|
font-size: 0.68rem;
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editorialHeading {
|
.editorialHeading {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
font-size: 1.35rem;
|
font-size: 1.35rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Running prose is the one place the serif appears. Slightly larger than the
|
||||||
|
UI around it because Literata's x-height sits lower than the grotesque's. */
|
||||||
.editorialText p {
|
.editorialText p {
|
||||||
font-size: 0.92rem;
|
font-family: var(--font-prose);
|
||||||
color: var(--text-secondary, #5c564d);
|
font-size: 0.97rem;
|
||||||
line-height: 1.6;
|
color: var(--text-secondary);
|
||||||
|
line-height: 1.65;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
max-width: 62ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.factbox {
|
.factbox {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 1.25rem;
|
padding: 1.25rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -1110,10 +1117,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.factboxHeading {
|
.factboxHeading {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
margin: 0 0 0.85rem;
|
margin: 0 0 0.85rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1122,7 +1129,7 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
padding: 0.5rem 0;
|
padding: 0.5rem 0;
|
||||||
border-bottom: 1px solid var(--border-color, #e5dfd5);
|
border-bottom: 1px solid var(--border);
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
@@ -1132,13 +1139,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.factKey {
|
.factKey {
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.factVal {
|
.factVal {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1168,7 +1175,7 @@
|
|||||||
|
|
||||||
.sortSelect {
|
.sortSelect {
|
||||||
padding: 0.375rem 0.75rem;
|
padding: 0.375rem 0.75rem;
|
||||||
border: 1px solid var(--border-color, #e0ddd8);
|
border: 1px solid var(--border);
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
background: var(--bg-card);
|
background: var(--bg-card);
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
@@ -1189,7 +1196,7 @@
|
|||||||
gap: 0.375rem;
|
gap: 0.375rem;
|
||||||
padding: 0.25rem 0.625rem;
|
padding: 0.25rem 0.625rem;
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
border: 1px solid var(--border-color, #e0ddd8);
|
border: 1px solid var(--border);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
@@ -1216,8 +1223,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.loadMoreCount {
|
.loadMoreCount {
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1231,7 +1239,7 @@
|
|||||||
|
|
||||||
.admissionsStrip {
|
.admissionsStrip {
|
||||||
padding: 1.5rem 0 2rem;
|
padding: 1.5rem 0 2rem;
|
||||||
border-top: 1px solid var(--border-color, #e5dfd5);
|
border-top: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stripHeader {
|
.stripHeader {
|
||||||
@@ -1248,12 +1256,12 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stripCta {
|
.stripCta {
|
||||||
font-size: 0.82rem;
|
font-size: 0.82rem;
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--brand);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
@@ -1269,11 +1277,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.countdownChip {
|
.countdownChip {
|
||||||
background: var(--bg-card, #fff);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 1rem 1.1rem 0.9rem;
|
padding: 1rem 1.1rem 0.9rem;
|
||||||
box-shadow: 0 2px 8px rgba(26, 22, 18, 0.06);
|
box-shadow: 0 2px 8px rgba(var(--shadow-rgb), 0.06);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.2rem;
|
gap: 0.2rem;
|
||||||
@@ -1292,16 +1300,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.countdownChipDeadline::before {
|
.countdownChipDeadline::before {
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.countdownChipOffer::before {
|
.countdownChipOffer::before {
|
||||||
background: var(--accent-teal, #2d7d7d);
|
background: var(--status-above);
|
||||||
}
|
}
|
||||||
|
|
||||||
.countdownChipUrgent {
|
.countdownChipUrgent {
|
||||||
border-color: rgba(224, 114, 86, 0.4);
|
border-color: rgba(var(--status-below-rgb), 0.4);
|
||||||
background: rgba(224, 114, 86, 0.04);
|
background: rgba(var(--status-below-rgb), 0.04);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipTrack {
|
.chipTrack {
|
||||||
@@ -1316,11 +1324,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chipTrackDeadline {
|
.chipTrackDeadline {
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipTrackOffer {
|
.chipTrackOffer {
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--status-above);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipTrackDot {
|
.chipTrackDot {
|
||||||
@@ -1332,7 +1340,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chipDays {
|
.chipDays {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-variant-numeric: tabular-nums;
|
||||||
|
font-family: var(--font-display);
|
||||||
font-size: 2.6rem;
|
font-size: 2.6rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
@@ -1341,18 +1350,18 @@
|
|||||||
|
|
||||||
.countdownChipDeadline .chipDays,
|
.countdownChipDeadline .chipDays,
|
||||||
.countdownChipUrgent .chipDays {
|
.countdownChipUrgent .chipDays {
|
||||||
color: var(--accent-coral-dark, #c45a3f);
|
color: var(--status-below);
|
||||||
}
|
}
|
||||||
|
|
||||||
.countdownChipOffer .chipDays {
|
.countdownChipOffer .chipDays {
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--status-above);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipDaysUnit {
|
.chipDaysUnit {
|
||||||
font-family: 'DM Sans', sans-serif;
|
font-family: var(--font-ui);
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
margin-left: 0.2rem;
|
margin-left: 0.2rem;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
line-height: 2;
|
line-height: 2;
|
||||||
@@ -1361,14 +1370,14 @@
|
|||||||
.chipMilestone {
|
.chipMilestone {
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
margin-top: 0.1rem;
|
margin-top: 0.1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipDate {
|
.chipDate {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
margin-top: 0.05rem;
|
margin-top: 0.05rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -573,10 +573,10 @@ function CompactSchoolItem({ school, onAddToCompare, isInCompare, nationalAvgRwm
|
|||||||
rwmDelta == null
|
rwmDelta == null
|
||||||
? {}
|
? {}
|
||||||
: rwmDelta >= 2
|
: rwmDelta >= 2
|
||||||
? { fontSize: '0.7rem', color: 'var(--accent-teal, #2d7d7d)', fontWeight: 600 }
|
? { fontSize: '0.7rem', color: 'var(--status-above)', fontWeight: 600 }
|
||||||
: rwmDelta <= -2
|
: rwmDelta <= -2
|
||||||
? { fontSize: '0.7rem', color: 'var(--accent-coral, #e07256)', fontWeight: 600 }
|
? { fontSize: '0.7rem', color: 'var(--brand)', fontWeight: 600 }
|
||||||
: { fontSize: '0.7rem', color: 'var(--text-muted, #8a847a)' };
|
: { fontSize: '0.7rem', color: 'var(--text-muted)' };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.compactItem}>
|
<div className={styles.compactItem}>
|
||||||
@@ -601,13 +601,13 @@ function CompactSchoolItem({ school, onAddToCompare, isInCompare, nationalAvgRwm
|
|||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
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(--status-above-bg)', color: 'var(--status-above)' } :
|
||||||
ofstedBadge.cssClass === 'ofsted2' ? { background: 'rgba(60,140,60,0.12)', color: '#2f7a2f' } :
|
ofstedBadge.cssClass === 'ofsted2' ? { background: 'var(--status-above-bg)', color: 'var(--status-above)' } :
|
||||||
ofstedBadge.cssClass === 'ofsted3' ? { background: 'var(--accent-gold-bg)', color: 'var(--accent-gold-text, #7a6800)' } :
|
ofstedBadge.cssClass === 'ofsted3' ? { background: 'var(--status-below-bg)', color: 'var(--status-below)' } :
|
||||||
ofstedBadge.cssClass === 'ofsted4' ? { background: 'var(--accent-coral-bg)', color: 'var(--accent-coral, #e07256)' } :
|
ofstedBadge.cssClass === 'ofsted4' ? { background: 'var(--status-below)', color: 'var(--text-inverse)' } :
|
||||||
ofstedBadge.cssClass === 'ofstedRc' ? { background: '#5a3a6e', color: '#fff' } :
|
ofstedBadge.cssClass === 'ofstedRc' ? { background: 'var(--phase-secondary-text)', color: 'var(--text-inverse)' } :
|
||||||
ofstedBadge.cssClass === 'ofstedPending' ? { background: '#e0e0e0', color: '#666' } :
|
ofstedBadge.cssClass === 'ofstedPending' ? { background: 'var(--bg-secondary)', color: 'var(--text-muted)' } :
|
||||||
{ background: '#e0e0e0', color: '#666' }),
|
{ background: 'var(--bg-secondary)', color: 'var(--text-muted)' }),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{ofstedBadge.label}
|
{ofstedBadge.label}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
/* font-size:0 hides the button's own "?" text node; the ::before glyph
|
/* font-size:0 hides the button's own "?" text node; the ::before glyph
|
||||||
below carries the visible circled "?" at its own explicit size. */
|
below carries the visible circled "?" at its own explicit size. */
|
||||||
font-size: 0;
|
font-size: 0;
|
||||||
color: var(--text-muted, #8a7a72);
|
color: var(--text-muted);
|
||||||
cursor: help;
|
cursor: help;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@@ -34,17 +34,17 @@
|
|||||||
.icon:hover,
|
.icon:hover,
|
||||||
.icon[aria-expanded='true'],
|
.icon[aria-expanded='true'],
|
||||||
.icon:focus-visible {
|
.icon:focus-visible {
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip {
|
.tooltip {
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
max-width: min(260px, calc(100vw - 24px));
|
max-width: min(260px, calc(100vw - 24px));
|
||||||
background: var(--bg-primary, #faf7f2);
|
background: var(--bg-primary);
|
||||||
border: 1px solid var(--border-color, #e8ddd4);
|
border: 1px solid var(--border);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
box-shadow: 0 4px 16px rgba(44, 36, 32, 0.15);
|
box-shadow: 0 4px 16px rgba(var(--shadow-rgb), 0.15);
|
||||||
padding: 0.6rem 0.75rem;
|
padding: 0.6rem 0.75rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -52,26 +52,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.arrow {
|
.arrow {
|
||||||
fill: var(--bg-primary, #faf7f2);
|
fill: var(--bg-primary);
|
||||||
stroke: var(--border-color, #e8ddd4);
|
stroke: var(--border);
|
||||||
stroke-width: 1px;
|
stroke-width: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
color: var(--text-primary, #2c2420);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.plain {
|
.plain {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
color: var(--text-secondary, #5a4a44);
|
color: var(--text-secondary);
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail {
|
.detail {
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
color: var(--text-muted, #8a7a72);
|
color: var(--text-muted);
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
margin-top: 0.1rem;
|
margin-top: 0.1rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ interface LeafletHeroMapInnerProps {
|
|||||||
// reliably inside Leaflet's divIcon HTML string (no CSS-module dependency).
|
// reliably inside Leaflet's divIcon HTML string (no CSS-module dependency).
|
||||||
const PIN_HTML = `
|
const PIN_HTML = `
|
||||||
<div style="position:relative;width:26px;height:26px">
|
<div style="position:relative;width:26px;height:26px">
|
||||||
<span style="position:absolute;left:50%;top:74%;width:32px;height:32px;transform:translate(-50%,-50%);border-radius:50%;background:rgba(224,114,86,.25)"></span>
|
<span style="position:absolute;left:50%;top:74%;width:32px;height:32px;transform:translate(-50%,-50%);border-radius:50%;background:var(--brand-bg)"></span>
|
||||||
<svg width="26" height="34" viewBox="0 0 26 34" style="filter:drop-shadow(0 3px 4px rgba(0,0,0,.35))">
|
<svg width="26" height="34" viewBox="0 0 26 34" style="filter:drop-shadow(0 3px 4px rgba(0,0,0,.35))">
|
||||||
<path d="M13 0C5.8 0 0 5.8 0 13c0 9.2 13 21 13 21s13-11.8 13-21C26 5.8 20.2 0 13 0Z" fill="#e07256"/>
|
<path d="M13 0C5.8 0 0 5.8 0 13c0 9.2 13 21 13 21s13-11.8 13-21C26 5.8 20.2 0 13 0Z" fill="var(--brand)"/>
|
||||||
<circle cx="13" cy="13" r="5" fill="#fff"/>
|
<circle cx="13" cy="13" r="5" fill="var(--text-inverse)"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
|||||||
@@ -48,21 +48,21 @@ function buildPopupBadge(school: School): PopupBadge {
|
|||||||
// ofsted_framework is the raw event grouping, never "ReportCard").
|
// ofsted_framework is the raw event grouping, never "ReportCard").
|
||||||
if (school.ofsted_rc_date) {
|
if (school.ofsted_rc_date) {
|
||||||
const rcYear = new Date(school.ofsted_rc_date).getFullYear();
|
const rcYear = new Date(school.ofsted_rc_date).getFullYear();
|
||||||
return { label: `Report Card · ${rcYear}`, style: 'background:#5a3a6e;color:#fff' };
|
return { label: `Report Card · ${rcYear}`, style: 'background:var(--phase-secondary-text);color:var(--text-inverse)' };
|
||||||
}
|
}
|
||||||
const year = school.ofsted_date ? new Date(school.ofsted_date).getFullYear() : null;
|
const year = school.ofsted_date ? new Date(school.ofsted_date).getFullYear() : null;
|
||||||
const yearStr = year ? ` · ${year}` : '';
|
const yearStr = year ? ` · ${year}` : '';
|
||||||
if (school.ofsted_grade) {
|
if (school.ofsted_grade) {
|
||||||
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:var(--status-above-bg);color:var(--status-above)',
|
||||||
2: 'background:rgba(60,140,60,0.12);color:#2f7a2f',
|
2: 'background:var(--status-above-bg);color:var(--status-above)',
|
||||||
3: 'background:#fef3cd;color:#7a6800',
|
3: 'background:var(--status-below-bg);color:var(--status-below)',
|
||||||
4: 'background:#fde8e0;color:#e07256',
|
4: 'background:var(--status-below);color:var(--text-inverse)',
|
||||||
};
|
};
|
||||||
return { label: `${labels[school.ofsted_grade]}${yearStr}`, style: colours[school.ofsted_grade] };
|
return { label: `${labels[school.ofsted_grade]}${yearStr}`, style: colours[school.ofsted_grade] };
|
||||||
}
|
}
|
||||||
return { label: 'Not yet inspected', style: 'background:#e0e0e0;color:#666' };
|
return { label: 'Not yet inspected', style: 'background:var(--bg-secondary);color:var(--text-muted)' };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function LeafletMapInner({ schools, center, zoom, referencePoint, onMarkerClick, nationalAvgRwm, laAverages }: LeafletMapInnerProps) {
|
export default function LeafletMapInner({ schools, center, zoom, referencePoint, onMarkerClick, nationalAvgRwm, laAverages }: LeafletMapInnerProps) {
|
||||||
@@ -99,7 +99,7 @@ export default function LeafletMapInner({ schools, center, zoom, referencePoint,
|
|||||||
const refIcon = L.divIcon({
|
const refIcon = L.divIcon({
|
||||||
html: `<div style="
|
html: `<div style="
|
||||||
width: 20px; height: 20px;
|
width: 20px; height: 20px;
|
||||||
background: #e07256;
|
background: var(--brand);
|
||||||
border: 3px solid white;
|
border: 3px solid white;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
box-shadow: 0 2px 8px rgba(0,0,0,0.35);
|
box-shadow: 0 2px 8px rgba(0,0,0,0.35);
|
||||||
@@ -145,13 +145,13 @@ export default function LeafletMapInner({ schools, center, zoom, referencePoint,
|
|||||||
const sign = diff >= 0 ? '+' : '';
|
const sign = diff >= 0 ? '+' : '';
|
||||||
// Att8 scores range 0–90 in 0.1 increments; ±0.5 is meaningful here
|
// Att8 scores range 0–90 in 0.1 increments; ±0.5 is meaningful here
|
||||||
// vs primary RWM % where ±2 pts is the threshold
|
// vs primary RWM % where ±2 pts is the threshold
|
||||||
const colour = diff >= 0.5 ? '#2d7d7d' : diff <= -0.5 ? '#e07256' : '#8a847a';
|
const colour = diff >= 0.5 ? 'var(--status-above)' : diff <= -0.5 ? 'var(--brand)' : 'var(--text-muted)';
|
||||||
const laName = escapeHtml(school.local_authority ?? 'LA');
|
const laName = escapeHtml(school.local_authority ?? 'LA');
|
||||||
deltaLine = `<div style="font-size:11px;font-weight:600;color:${colour}">${sign}${diff} vs ${laName} avg</div>`;
|
deltaLine = `<div style="font-size:11px;font-weight:600;color:${colour}">${sign}${diff} vs ${laName} avg</div>`;
|
||||||
}
|
}
|
||||||
metricHtml = `<div style="margin-bottom:4px">
|
metricHtml = `<div style="margin-bottom:4px">
|
||||||
<span style="font-size:20px;font-weight:700;color:#1a1612;font-family:Georgia,serif">${score.toFixed(1)}</span>
|
<span style="font-size:20px;font-weight:700;color:var(--text-primary);font-family:Georgia,serif">${score.toFixed(1)}</span>
|
||||||
<span style="font-size:11px;color:#8a847a;margin-left:4px">Attainment 8</span>
|
<span style="font-size:11px;color:var(--text-muted);margin-left:4px">Attainment 8</span>
|
||||||
${deltaLine}
|
${deltaLine}
|
||||||
</div>`;
|
</div>`;
|
||||||
} else if (school.rwm_expected_pct != null) {
|
} else if (school.rwm_expected_pct != null) {
|
||||||
@@ -159,7 +159,7 @@ export default function LeafletMapInner({ schools, center, zoom, referencePoint,
|
|||||||
let deltaLine = '';
|
let deltaLine = '';
|
||||||
if (nationalAvgRwm != null) {
|
if (nationalAvgRwm != null) {
|
||||||
const diff = Math.round(rwm - nationalAvgRwm);
|
const diff = Math.round(rwm - nationalAvgRwm);
|
||||||
const colour = diff >= 2 ? '#2d7d7d' : diff <= -2 ? '#e07256' : '#8a847a';
|
const colour = diff >= 2 ? 'var(--status-above)' : diff <= -2 ? 'var(--brand)' : 'var(--text-muted)';
|
||||||
const text =
|
const text =
|
||||||
diff >= 2 ? `+${diff} pts vs national` :
|
diff >= 2 ? `+${diff} pts vs national` :
|
||||||
diff <= -2 ? `${diff} pts vs national` :
|
diff <= -2 ? `${diff} pts vs national` :
|
||||||
@@ -167,8 +167,8 @@ export default function LeafletMapInner({ schools, center, zoom, referencePoint,
|
|||||||
deltaLine = `<div style="font-size:11px;font-weight:600;color:${colour}">${text}</div>`;
|
deltaLine = `<div style="font-size:11px;font-weight:600;color:${colour}">${text}</div>`;
|
||||||
}
|
}
|
||||||
metricHtml = `<div style="margin-bottom:4px">
|
metricHtml = `<div style="margin-bottom:4px">
|
||||||
<span style="font-size:20px;font-weight:700;color:#1a1612;font-family:Georgia,serif">${rwm}%</span>
|
<span style="font-size:20px;font-weight:700;color:var(--text-primary);font-family:Georgia,serif">${rwm}%</span>
|
||||||
<span style="font-size:11px;color:#8a847a;margin-left:4px">Reading, Writing & Maths</span>
|
<span style="font-size:11px;color:var(--text-muted);margin-left:4px">Reading, Writing & Maths</span>
|
||||||
${deltaLine}
|
${deltaLine}
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
@@ -177,14 +177,14 @@ export default function LeafletMapInner({ schools, center, zoom, referencePoint,
|
|||||||
|
|
||||||
const popupContent = `<div style="font-family:system-ui,sans-serif;min-width:240px;max-width:280px;padding:0">
|
const popupContent = `<div style="font-family:system-ui,sans-serif;min-width:240px;max-width:280px;padding:0">
|
||||||
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:8px;margin-bottom:6px">
|
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:8px;margin-bottom:6px">
|
||||||
<strong style="font-size:13px;color:#1a1612;line-height:1.3">${escapeHtml(school.school_name)}</strong>
|
<strong style="font-size:13px;color:var(--text-primary);line-height:1.3">${escapeHtml(school.school_name)}</strong>
|
||||||
<span style="font-size:10px;font-weight:700;padding:2px 6px;border-radius:3px;white-space:nowrap;flex-shrink:0;${badge.style}">${badge.label}</span>
|
<span style="font-size:10px;font-weight:700;padding:2px 6px;border-radius:3px;white-space:nowrap;flex-shrink:0;${badge.style}">${badge.label}</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="font-size:11px;color:#8a847a;margin-bottom:8px">
|
<div style="font-size:11px;color:var(--text-muted);margin-bottom:8px">
|
||||||
${phaseLabel}${school.local_authority ? ` · ${escapeHtml(school.local_authority)}` : ''}${distanceStr}
|
${phaseLabel}${school.local_authority ? ` · ${escapeHtml(school.local_authority)}` : ''}${distanceStr}
|
||||||
</div>
|
</div>
|
||||||
${metricHtml}
|
${metricHtml}
|
||||||
<a href="${slug}" style="display:block;text-align:center;padding:6px;background:#2d7d7d;color:white;border-radius:5px;text-decoration:none;font-size:12px;font-weight:600;margin-top:8px">View Details →</a>
|
<a href="${slug}" style="display:block;text-align:center;padding:6px;background:var(--status-above);color:white;border-radius:5px;text-decoration:none;font-size:12px;font-weight:600;margin-top:8px">View Details →</a>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
marker.bindPopup(popupContent);
|
marker.bindPopup(popupContent);
|
||||||
|
|||||||
@@ -5,19 +5,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.skeletonCard {
|
.skeletonCard {
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
box-shadow: var(--shadow-soft, 0 2px 8px rgba(26, 22, 18, 0.06));
|
box-shadow: var(--shadow-soft, 0 2px 8px rgba(var(--shadow-rgb), 0.06));
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeleton {
|
.skeleton {
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
90deg,
|
90deg,
|
||||||
var(--bg-secondary, #f3ede4) 25%,
|
var(--bg-secondary) 25%,
|
||||||
rgba(224, 114, 86, 0.08) 50%,
|
rgba(var(--brand-rgb), 0.08) 50%,
|
||||||
var(--bg-secondary, #f3ede4) 75%
|
var(--bg-secondary) 75%
|
||||||
);
|
);
|
||||||
background-size: 200% 100%;
|
background-size: 200% 100%;
|
||||||
animation: shimmer 1.5s ease-in-out infinite;
|
animation: shimmer 1.5s ease-in-out infinite;
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,11 +82,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.skeletonListItem {
|
.skeletonListItem {
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
box-shadow: var(--shadow-soft, 0 2px 8px rgba(26, 22, 18, 0.06));
|
box-shadow: var(--shadow-soft, 0 2px 8px rgba(var(--shadow-rgb), 0.06));
|
||||||
}
|
}
|
||||||
|
|
||||||
.listTitle {
|
.listTitle {
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* The SchoolCompare mark.
|
||||||
|
*
|
||||||
|
* Five bars: a cohort, with one school picked out. It is the same object as
|
||||||
|
* the distribution strip inside a school row, at a different size — the logo
|
||||||
|
* teaches the chart and the chart reinforces the logo.
|
||||||
|
*
|
||||||
|
* Built from opacity steps over `currentColor` rather than fixed greys, so it
|
||||||
|
* inverts cleanly on any ground without a second artwork. The highlighted bar
|
||||||
|
* is the only element that takes the brand hue.
|
||||||
|
*
|
||||||
|
* This is the single source for the mark. The favicon and the generated icons
|
||||||
|
* derive from the same geometry (see BARS) — previously the header and the
|
||||||
|
* favicon had drifted into two different logos.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** x, y, width, height, and whether this bar is the highlighted school. */
|
||||||
|
export const BARS: ReadonlyArray<[number, number, number, number, boolean]> = [
|
||||||
|
[2, 26, 6, 12, false],
|
||||||
|
[10, 16, 6, 22, false],
|
||||||
|
[18, 8, 6, 30, false],
|
||||||
|
[26, 14, 6, 24, true],
|
||||||
|
[34, 28, 4, 10, false],
|
||||||
|
];
|
||||||
|
|
||||||
|
const COHORT_OPACITY = [0.22, 0.38, 0.55, 1, 0.22];
|
||||||
|
|
||||||
|
interface LogoMarkProps {
|
||||||
|
className?: string;
|
||||||
|
/** Rendered size in px. Defaults to inheriting via CSS. */
|
||||||
|
size?: number;
|
||||||
|
/** Colour of the highlighted bar. Defaults to the brand token. */
|
||||||
|
accent?: string;
|
||||||
|
title?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LogoMark({ className, size, accent = 'var(--brand)', title }: LogoMarkProps) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
className={className}
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
viewBox="0 0 40 40"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
role={title ? 'img' : undefined}
|
||||||
|
aria-hidden={title ? undefined : true}
|
||||||
|
aria-label={title}
|
||||||
|
>
|
||||||
|
{title ? <title>{title}</title> : null}
|
||||||
|
{BARS.map(([x, y, w, h, isSchool], i) => (
|
||||||
|
<rect
|
||||||
|
key={x}
|
||||||
|
x={x}
|
||||||
|
y={y}
|
||||||
|
width={w}
|
||||||
|
height={h}
|
||||||
|
rx={1}
|
||||||
|
fill={isSchool ? accent : 'currentColor'}
|
||||||
|
opacity={isSchool ? 1 : COHORT_OPACITY[i]}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
.overlay {
|
.overlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
background: rgba(26, 22, 18, 0.6);
|
background: rgba(var(--shadow-rgb), 0.6);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -20,15 +20,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: 0 20px 40px rgba(26, 22, 18, 0.2);
|
box-shadow: 0 20px 40px rgba(var(--shadow-rgb), 0.2);
|
||||||
max-height: 90vh;
|
max-height: 90vh;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
animation: slideIn 0.3s ease;
|
animation: slideIn 0.3s ease;
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes slideIn {
|
@keyframes slideIn {
|
||||||
@@ -62,22 +62,22 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
border-bottom: 1px solid var(--border-color, #e5dfd5);
|
border-bottom: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
}
|
}
|
||||||
|
|
||||||
.closeButton {
|
.closeButton {
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
@@ -87,8 +87,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.closeButton:hover {
|
.closeButton:hover {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@@ -102,16 +102,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content::-webkit-scrollbar-track {
|
.content::-webkit-scrollbar-track {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content::-webkit-scrollbar-thumb {
|
.content::-webkit-scrollbar-thumb {
|
||||||
background: var(--border-color, #e5dfd5);
|
background: var(--border);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content::-webkit-scrollbar-thumb:hover {
|
.content::-webkit-scrollbar-thumb:hover {
|
||||||
background: var(--text-muted, #8a847a);
|
background: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border-bottom: 1px solid var(--border-color, #e5dfd5);
|
border-bottom: 1px solid var(--border);
|
||||||
box-shadow: 0 2px 8px rgba(26, 22, 18, 0.06);
|
box-shadow: 0 2px 8px rgba(var(--shadow-rgb), 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
margin: -0.375rem -0.5rem;
|
margin: -0.375rem -0.5rem;
|
||||||
padding: 0.375rem 0.5rem;
|
padding: 0.375rem 0.5rem;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
transition: color 0.2s ease;
|
transition: color 0.2s ease;
|
||||||
@@ -35,14 +35,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.logo:hover {
|
.logo:hover {
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* currentColor paints the four cohort bars; the mark supplies the brand hue
|
||||||
|
for the highlighted one itself. So this is ink, not brand. */
|
||||||
.logoIcon {
|
.logoIcon {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
width: 36px;
|
width: 32px;
|
||||||
height: 36px;
|
height: 32px;
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.logoIcon svg {
|
.logoIcon svg {
|
||||||
@@ -51,9 +53,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.logoText {
|
.logoText {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: -0.01em;
|
letter-spacing: -0.022em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logoTextAccent {
|
||||||
|
color: var(--brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo:hover .logoTextAccent {
|
||||||
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav {
|
.nav {
|
||||||
@@ -69,7 +79,7 @@
|
|||||||
padding: 0.625rem 1rem;
|
padding: 0.625rem 1rem;
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
@@ -83,7 +93,7 @@
|
|||||||
left: 1rem;
|
left: 1rem;
|
||||||
right: 1rem;
|
right: 1rem;
|
||||||
height: 2px;
|
height: 2px;
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--brand);
|
||||||
transform: scaleX(0);
|
transform: scaleX(0);
|
||||||
transform-origin: left;
|
transform-origin: left;
|
||||||
transition: transform 0.25s ease;
|
transition: transform 0.25s ease;
|
||||||
@@ -91,8 +101,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.navLink:hover {
|
.navLink:hover {
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.navLink:hover::after {
|
.navLink:hover::after {
|
||||||
@@ -100,8 +110,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.navLink.active {
|
.navLink.active {
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
background: var(--accent-coral-bg);
|
background: var(--brand-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.navLink.active::after {
|
.navLink.active::after {
|
||||||
@@ -117,11 +127,11 @@
|
|||||||
padding: 0 0.375rem;
|
padding: 0 0.375rem;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--brand);
|
||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
animation: badgePop 0.3s ease-out;
|
animation: badgePop 0.3s ease-out;
|
||||||
box-shadow: 0 2px 6px rgba(224, 114, 86, 0.4);
|
box-shadow: 0 2px 6px rgba(var(--brand-rgb), 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes badgePop {
|
@keyframes badgePop {
|
||||||
@@ -153,7 +163,7 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 56px;
|
min-height: 56px;
|
||||||
padding: 0.375rem 0.25rem;
|
padding: 0.375rem 0.25rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-size: 0.6875rem;
|
font-size: 0.6875rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -163,11 +173,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tab:active {
|
.tab:active {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabActive {
|
.tabActive {
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabIconWrap {
|
.tabIconWrap {
|
||||||
@@ -200,9 +210,9 @@
|
|||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
font-size: 0.6875rem;
|
font-size: 0.6875rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--brand);
|
||||||
border: 2px solid var(--bg-card, white);
|
border: 2px solid var(--bg-card);
|
||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
animation: badgePop 0.3s ease-out;
|
animation: badgePop 0.3s ease-out;
|
||||||
}
|
}
|
||||||
@@ -230,9 +240,9 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border-top: 1px solid var(--border-color, #e5dfd5);
|
border-top: 1px solid var(--border);
|
||||||
box-shadow: 0 -2px 12px rgba(26, 22, 18, 0.06);
|
box-shadow: 0 -2px 12px rgba(var(--shadow-rgb), 0.06);
|
||||||
/* Respect iPhone home-indicator (bottom) and notch (left/right in
|
/* Respect iPhone home-indicator (bottom) and notch (left/right in
|
||||||
landscape) insets so the tab content never sits under system UI. */
|
landscape) insets so the tab content never sits under system UI. */
|
||||||
padding-bottom: env(safe-area-inset-bottom, 0);
|
padding-bottom: env(safe-area-inset-bottom, 0);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { useEffect } from 'react';
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { usePathname } from 'next/navigation';
|
import { usePathname } from 'next/navigation';
|
||||||
import { useComparison } from '@/hooks/useComparison';
|
import { useComparison } from '@/hooks/useComparison';
|
||||||
|
import { LogoMark } from './Logo';
|
||||||
import styles from './Navigation.module.css';
|
import styles from './Navigation.module.css';
|
||||||
|
|
||||||
type IconProps = { className?: string };
|
type IconProps = { className?: string };
|
||||||
@@ -91,13 +92,11 @@ export function Navigation() {
|
|||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<Link href="/" className={styles.logo} aria-label="SchoolCompare home">
|
<Link href="/" className={styles.logo} aria-label="SchoolCompare home">
|
||||||
<span className={styles.logoIcon}>
|
<span className={styles.logoIcon}>
|
||||||
<svg viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
<LogoMark />
|
||||||
<circle cx="20" cy="20" r="18" stroke="currentColor" strokeWidth="2" />
|
</span>
|
||||||
<path d="M20 6L20 34M8 14L32 14M6 20L34 20M8 26L32 26" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
|
<span className={styles.logoText}>
|
||||||
<circle cx="20" cy="20" r="3" fill="currentColor" />
|
School<span className={styles.logoTextAccent}>Compare</span>
|
||||||
</svg>
|
|
||||||
</span>
|
</span>
|
||||||
<span className={styles.logoText}>SchoolCompare</span>
|
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<nav className={styles.nav} aria-label="Main navigation">
|
<nav className={styles.nav} aria-label="Main navigation">
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
.info {
|
.info {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
@@ -21,18 +21,18 @@
|
|||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navButton:hover:not(:disabled) {
|
.navButton:hover:not(:disabled) {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.navButton:disabled {
|
.navButton:disabled {
|
||||||
@@ -51,32 +51,32 @@
|
|||||||
padding: 0.5rem 0.75rem;
|
padding: 0.5rem 0.75rem;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pageButton {
|
.pageButton {
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pageButton:hover {
|
.pageButton:hover {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pageButtonActive {
|
.pageButtonActive {
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--brand);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pageButtonActive:hover {
|
.pageButtonActive:hover {
|
||||||
background: var(--accent-coral-dark, #c45a3f);
|
background: var(--brand-strong);
|
||||||
border-color: var(--accent-coral-dark, #c45a3f);
|
border-color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ellipsis {
|
.ellipsis {
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0.5rem 0.75rem;
|
padding: 0.5rem 0.75rem;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
.trendSummary {
|
.trendSummary {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
padding: 0.5rem 0.875rem;
|
padding: 0.5rem 0.875rem;
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-left: 3px solid var(--accent-teal, #2d7d7d);
|
border-left: 3px solid var(--brand);
|
||||||
border-radius: 0 4px 4px 0;
|
border-radius: 0 4px 4px 0;
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
.covidNote,
|
.covidNote,
|
||||||
.chartHint {
|
.chartHint {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
margin-bottom: 0.4rem;
|
margin-bottom: 0.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,9 +63,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chip {
|
.chip {
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
background: var(--bg-card, #fff);
|
background: var(--bg-card);
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
padding: 0.4rem 0.75rem;
|
padding: 0.4rem 0.75rem;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chip:active {
|
.chip:active {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chip:disabled {
|
.chip:disabled {
|
||||||
@@ -87,21 +87,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chipActive {
|
.chipActive {
|
||||||
background: var(--accent-coral-dark, #b04a2e);
|
background: var(--brand-strong);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipActive:active {
|
.chipActive:active {
|
||||||
background: var(--accent-coral-dark, #c45a3f);
|
background: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.miniLegend {
|
.miniLegend {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.875rem;
|
gap: 0.875rem;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
margin-top: -0.25rem;
|
margin-top: -0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
|
import { useThemeTokens, alpha } from '@/lib/theme';
|
||||||
import { Line } from 'react-chartjs-2';
|
import { Line } from 'react-chartjs-2';
|
||||||
import { ChartOptions, ChartDataset } from 'chart.js';
|
import { ChartOptions, ChartDataset } from 'chart.js';
|
||||||
import '@/lib/chartSetup';
|
import '@/lib/chartSetup';
|
||||||
@@ -124,9 +125,17 @@ export function PerformanceChart({
|
|||||||
const gapYears = axisYears.filter(y => !byYear.has(y));
|
const gapYears = axisYears.filter(y => !byYear.has(y));
|
||||||
const hasGap = gapYears.length > 0;
|
const hasGap = gapYears.length > 0;
|
||||||
|
|
||||||
|
// Chart.js paints to a canvas, so it needs resolved colours rather than
|
||||||
|
// var(). Reading them through the token bridge keeps the series on the
|
||||||
|
// brand palette and lets them follow the theme.
|
||||||
|
const [c1, c2, c3, c4, c5, c6, cGrid, cRef, cInverse, cInverseText] = useThemeTokens(
|
||||||
|
'--chart-1', '--chart-2', '--chart-3', '--chart-4', '--chart-5', '--chart-6',
|
||||||
|
'--chart-grid', '--chart-reference', '--surface-inverse', '--text-inverse'
|
||||||
|
);
|
||||||
|
|
||||||
// ── Datasets (full set; mobile filters them via the active chip) ─────
|
// ── Datasets (full set; mobile filters them via the active chip) ─────
|
||||||
const refLineStyle = {
|
const refLineStyle = {
|
||||||
borderColor: 'rgba(90,80,70,0.35)',
|
borderColor: cRef,
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
borderWidth: 1.5,
|
borderWidth: 1.5,
|
||||||
borderDash: [6, 4] as number[],
|
borderDash: [6, 4] as number[],
|
||||||
@@ -140,8 +149,8 @@ export function PerformanceChart({
|
|||||||
{
|
{
|
||||||
label: 'Attainment 8',
|
label: 'Attainment 8',
|
||||||
data: col('attainment_8_score'),
|
data: col('attainment_8_score'),
|
||||||
borderColor: '#2d7d7d',
|
borderColor: c1,
|
||||||
backgroundColor: 'rgba(45,125,125,0.08)',
|
backgroundColor: alpha('--chart-1', 0.08),
|
||||||
borderWidth: 2.5,
|
borderWidth: 2.5,
|
||||||
tension: 0.3,
|
tension: 0.3,
|
||||||
pointRadius: 4,
|
pointRadius: 4,
|
||||||
@@ -151,8 +160,8 @@ export function PerformanceChart({
|
|||||||
{
|
{
|
||||||
label: 'English & Maths Grade 4+',
|
label: 'English & Maths Grade 4+',
|
||||||
data: col('english_maths_standard_pass_pct'),
|
data: col('english_maths_standard_pass_pct'),
|
||||||
borderColor: '#c9a227',
|
borderColor: c2,
|
||||||
backgroundColor: 'rgba(201,162,39,0.08)',
|
backgroundColor: alpha('--chart-2', 0.08),
|
||||||
borderWidth: 1.5,
|
borderWidth: 1.5,
|
||||||
tension: 0.3,
|
tension: 0.3,
|
||||||
pointRadius: 3,
|
pointRadius: 3,
|
||||||
@@ -161,8 +170,8 @@ export function PerformanceChart({
|
|||||||
{
|
{
|
||||||
label: 'Progress 8',
|
label: 'Progress 8',
|
||||||
data: col('progress_8_score'),
|
data: col('progress_8_score'),
|
||||||
borderColor: 'rgb(139,92,246)',
|
borderColor: c3,
|
||||||
backgroundColor: 'rgba(139,92,246,0.08)',
|
backgroundColor: alpha('--chart-3', 0.08),
|
||||||
borderWidth: 1.5,
|
borderWidth: 1.5,
|
||||||
tension: 0.3,
|
tension: 0.3,
|
||||||
pointRadius: 3,
|
pointRadius: 3,
|
||||||
@@ -179,8 +188,8 @@ export function PerformanceChart({
|
|||||||
{
|
{
|
||||||
label: 'Reading, Writing & Maths expected %',
|
label: 'Reading, Writing & Maths expected %',
|
||||||
data: col('rwm_expected_pct'),
|
data: col('rwm_expected_pct'),
|
||||||
borderColor: '#2d7d7d',
|
borderColor: c1,
|
||||||
backgroundColor: 'rgba(45,125,125,0.08)',
|
backgroundColor: alpha('--chart-1', 0.08),
|
||||||
borderWidth: 2.5,
|
borderWidth: 2.5,
|
||||||
tension: 0.3,
|
tension: 0.3,
|
||||||
pointRadius: 4,
|
pointRadius: 4,
|
||||||
@@ -190,8 +199,8 @@ export function PerformanceChart({
|
|||||||
{
|
{
|
||||||
label: 'Exceeding expected level',
|
label: 'Exceeding expected level',
|
||||||
data: col('rwm_high_pct'),
|
data: col('rwm_high_pct'),
|
||||||
borderColor: '#c9a227',
|
borderColor: c2,
|
||||||
backgroundColor: 'rgba(201,162,39,0.08)',
|
backgroundColor: alpha('--chart-2', 0.08),
|
||||||
borderWidth: 1.5,
|
borderWidth: 1.5,
|
||||||
tension: 0.3,
|
tension: 0.3,
|
||||||
pointRadius: 3,
|
pointRadius: 3,
|
||||||
@@ -206,8 +215,8 @@ export function PerformanceChart({
|
|||||||
{
|
{
|
||||||
label: 'Reading progress',
|
label: 'Reading progress',
|
||||||
data: col('reading_progress'),
|
data: col('reading_progress'),
|
||||||
borderColor: 'rgb(59,130,246)',
|
borderColor: c4,
|
||||||
backgroundColor: 'rgba(59,130,246,0.08)',
|
backgroundColor: alpha('--chart-4', 0.08),
|
||||||
borderWidth: 1.5,
|
borderWidth: 1.5,
|
||||||
tension: 0.3,
|
tension: 0.3,
|
||||||
pointRadius: 3,
|
pointRadius: 3,
|
||||||
@@ -217,8 +226,8 @@ export function PerformanceChart({
|
|||||||
{
|
{
|
||||||
label: 'Writing progress',
|
label: 'Writing progress',
|
||||||
data: col('writing_progress'),
|
data: col('writing_progress'),
|
||||||
borderColor: 'rgb(139,92,246)',
|
borderColor: c3,
|
||||||
backgroundColor: 'rgba(139,92,246,0.08)',
|
backgroundColor: alpha('--chart-3', 0.08),
|
||||||
borderWidth: 1.5,
|
borderWidth: 1.5,
|
||||||
tension: 0.3,
|
tension: 0.3,
|
||||||
pointRadius: 3,
|
pointRadius: 3,
|
||||||
@@ -228,8 +237,8 @@ export function PerformanceChart({
|
|||||||
{
|
{
|
||||||
label: 'Maths progress',
|
label: 'Maths progress',
|
||||||
data: col('maths_progress'),
|
data: col('maths_progress'),
|
||||||
borderColor: 'rgb(236,72,153)',
|
borderColor: c5,
|
||||||
backgroundColor: 'rgba(236,72,153,0.08)',
|
backgroundColor: alpha('--chart-5', 0.08),
|
||||||
borderWidth: 1.5,
|
borderWidth: 1.5,
|
||||||
tension: 0.3,
|
tension: 0.3,
|
||||||
pointRadius: 3,
|
pointRadius: 3,
|
||||||
@@ -301,7 +310,9 @@ export function PerformanceChart({
|
|||||||
},
|
},
|
||||||
title: { display: false },
|
title: { display: false },
|
||||||
tooltip: {
|
tooltip: {
|
||||||
backgroundColor: 'rgba(26,22,18,0.92)',
|
backgroundColor: cInverse,
|
||||||
|
titleColor: cInverseText,
|
||||||
|
bodyColor: cInverseText,
|
||||||
padding: 12,
|
padding: 12,
|
||||||
titleFont: { size: 13 },
|
titleFont: { size: 13 },
|
||||||
bodyFont: { size: 12 },
|
bodyFont: { size: 12 },
|
||||||
@@ -321,7 +332,7 @@ export function PerformanceChart({
|
|||||||
type: 'linear', display: true, position: 'left',
|
type: 'linear', display: true, position: 'left',
|
||||||
title: { display: true, text: isSecondary ? 'Score / %' : 'Percentage (%)', font: { size: 11 } },
|
title: { display: true, text: isSecondary ? 'Score / %' : 'Percentage (%)', font: { size: 11 } },
|
||||||
min: 0, max: isSecondary ? undefined : 100,
|
min: 0, max: isSecondary ? undefined : 100,
|
||||||
grid: { color: 'rgba(0,0,0,0.05)' },
|
grid: { color: cGrid },
|
||||||
ticks: { font: { size: 11 } },
|
ticks: { font: { size: 11 } },
|
||||||
},
|
},
|
||||||
y1: {
|
y1: {
|
||||||
@@ -346,7 +357,9 @@ export function PerformanceChart({
|
|||||||
legend: { display: false },
|
legend: { display: false },
|
||||||
title: { display: false },
|
title: { display: false },
|
||||||
tooltip: {
|
tooltip: {
|
||||||
backgroundColor: 'rgba(26,22,18,0.92)',
|
backgroundColor: cInverse,
|
||||||
|
titleColor: cInverseText,
|
||||||
|
bodyColor: cInverseText,
|
||||||
padding: 10,
|
padding: 10,
|
||||||
titleFont: { size: 12 },
|
titleFont: { size: 12 },
|
||||||
bodyFont: { size: 11 },
|
bodyFont: { size: 11 },
|
||||||
@@ -364,7 +377,7 @@ export function PerformanceChart({
|
|||||||
y: {
|
y: {
|
||||||
type: 'linear', display: true, position: 'left',
|
type: 'linear', display: true, position: 'left',
|
||||||
min: mobileYBounds.min, max: mobileYBounds.max,
|
min: mobileYBounds.min, max: mobileYBounds.max,
|
||||||
grid: { color: 'rgba(0,0,0,0.05)' },
|
grid: { color: cGrid },
|
||||||
ticks: { font: { size: 10 }, maxTicksLimit: 5 },
|
ticks: { font: { size: 10 }, maxTicksLimit: 5 },
|
||||||
},
|
},
|
||||||
x: {
|
x: {
|
||||||
@@ -429,9 +442,9 @@ export function PerformanceChart({
|
|||||||
belong together. */}
|
belong together. */}
|
||||||
{isMobile && activeChip === 'progress' && (
|
{isMobile && activeChip === 'progress' && (
|
||||||
<div className={styles.miniLegend}>
|
<div className={styles.miniLegend}>
|
||||||
<span><span className={styles.miniDot} style={{ background: 'rgb(59,130,246)' }} />Reading</span>
|
<span><span className={styles.miniDot} style={{ background: c4 }} />Reading</span>
|
||||||
<span><span className={styles.miniDot} style={{ background: 'rgb(139,92,246)' }} />Writing</span>
|
<span><span className={styles.miniDot} style={{ background: c3 }} />Writing</span>
|
||||||
<span><span className={styles.miniDot} style={{ background: 'rgb(236,72,153)' }} />Maths</span>
|
<span><span className={styles.miniDot} style={{ background: c5 }} />Maths</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,14 @@
|
|||||||
.header h1 {
|
.header h1 {
|
||||||
font-size: 2.25rem;
|
font-size: 2.25rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 0;
|
gap: 0;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
@@ -38,8 +38,8 @@
|
|||||||
padding: 0.625rem 1.5rem;
|
padding: 0.625rem 1.5rem;
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.15s ease;
|
transition: all 0.15s ease;
|
||||||
@@ -47,34 +47,34 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.phaseTab:not(:last-child) {
|
.phaseTab:not(:last-child) {
|
||||||
border-right: 1px solid var(--border-color, #e5dfd5);
|
border-right: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.phaseTab:hover {
|
.phaseTab:hover {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.phaseTabActive {
|
.phaseTabActive {
|
||||||
background: var(--accent-coral-dark, #b04a2e);
|
background: var(--brand-strong);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phaseTabActive:hover {
|
.phaseTabActive:hover {
|
||||||
background: var(--accent-coral-darker, #9c3f26);
|
background: var(--brand-stronger);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Filters */
|
/* Filters */
|
||||||
.filters {
|
.filters {
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
box-shadow: var(--shadow-soft, 0 2px 8px rgba(26, 22, 18, 0.06));
|
box-shadow: var(--shadow-soft, 0 2px 8px rgba(var(--shadow-rgb), 0.06));
|
||||||
}
|
}
|
||||||
|
|
||||||
.filterGroup {
|
.filterGroup {
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
.filterLabel {
|
.filterLabel {
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,44 +98,44 @@
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
padding: 0.625rem 1rem;
|
padding: 0.625rem 1rem;
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filterSelect:hover {
|
.filterSelect:hover {
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.filterSelect:focus {
|
.filterSelect:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
box-shadow: 0 0 0 3px var(--accent-coral-bg);
|
box-shadow: 0 0 0 3px var(--brand-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.filterSelect optgroup {
|
.filterSelect optgroup {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
padding: 0.5rem 0;
|
padding: 0.5rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filterSelect option {
|
.filterSelect option {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
padding: 0.375rem 1rem;
|
padding: 0.375rem 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rankings Section */
|
/* Rankings Section */
|
||||||
.rankingsSection {
|
.rankingsSection {
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
box-shadow: var(--shadow-soft, 0 2px 8px rgba(26, 22, 18, 0.06));
|
box-shadow: var(--shadow-soft, 0 2px 8px rgba(var(--shadow-rgb), 0.06));
|
||||||
}
|
}
|
||||||
|
|
||||||
.tableWrapper {
|
.tableWrapper {
|
||||||
@@ -151,15 +151,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.rankingsTable thead {
|
.rankingsTable thead {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rankingsTable th {
|
.rankingsTable th {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
border-bottom: 2px solid var(--border-color, #e5dfd5);
|
border-bottom: 2px solid var(--border);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
@@ -206,8 +206,8 @@
|
|||||||
|
|
||||||
.rankingsTable td {
|
.rankingsTable td {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
border-bottom: 1px solid var(--border-color, #e5dfd5);
|
border-bottom: 1px solid var(--border);
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rankingsTable tbody tr:last-child td {
|
.rankingsTable tbody tr:last-child td {
|
||||||
@@ -216,24 +216,24 @@
|
|||||||
|
|
||||||
/* Alternating row backgrounds for visual rhythm */
|
/* Alternating row backgrounds for visual rhythm */
|
||||||
.rankingsTable tbody tr:nth-child(even) {
|
.rankingsTable tbody tr:nth-child(even) {
|
||||||
background: rgba(243, 237, 228, 0.5);
|
background: rgba(var(--text-inverse-rgb), 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rankingsTable tbody tr:hover {
|
.rankingsTable tbody tr:hover {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Top 3 Highlighting with Gold */
|
/* Top 3 Highlighting with Gold */
|
||||||
.rank1 {
|
.rank1 {
|
||||||
background: linear-gradient(90deg, rgba(201, 162, 39, 0.15) 0%, transparent 100%) !important;
|
background: linear-gradient(90deg, rgba(var(--status-below-rgb), 0.15) 0%, transparent 100%) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rank2 {
|
.rank2 {
|
||||||
background: linear-gradient(90deg, rgba(192, 192, 192, 0.15) 0%, transparent 100%) !important;
|
background: linear-gradient(90deg, rgba(var(--medal-silver-rgb), 0.15) 0%, transparent 100%) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rank3 {
|
.rank3 {
|
||||||
background: linear-gradient(90deg, rgba(205, 127, 50, 0.15) 0%, transparent 100%) !important;
|
background: linear-gradient(90deg, rgba(var(--medal-bronze-rgb), 0.15) 0%, transparent 100%) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rankCell {
|
.rankCell {
|
||||||
@@ -241,7 +241,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Styled rank badges for top 3 */
|
/* Styled rank badges for top 3 */
|
||||||
@@ -254,8 +254,8 @@
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
box-shadow: 0 2px 8px rgba(var(--shadow-rgb), 0.15);
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,30 +265,31 @@
|
|||||||
inset: -2px;
|
inset: -2px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
border: 2px solid transparent;
|
border: 2px solid transparent;
|
||||||
background: linear-gradient(135deg, rgba(255, 255, 255, 0.4), transparent) border-box;
|
background: linear-gradient(135deg, rgba(var(--text-inverse-rgb), 0.4), transparent) border-box;
|
||||||
mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
|
mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
|
||||||
mask-composite: exclude;
|
mask-composite: exclude;
|
||||||
-webkit-mask-composite: xor;
|
-webkit-mask-composite: xor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rankBadge1 {
|
.rankBadge1 {
|
||||||
background: linear-gradient(135deg, #c9a227 0%, #e8c547 50%, #c9a227 100%);
|
background: linear-gradient(135deg, var(--status-below) 0%, var(--medal-gold) 50%, var(--status-below) 100%);
|
||||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
text-shadow: 0 1px 2px rgba(var(--shadow-rgb), 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rankBadge2 {
|
.rankBadge2 {
|
||||||
background: linear-gradient(135deg, #8c8c8c 0%, #c0c0c0 50%, #8c8c8c 100%);
|
background: linear-gradient(135deg, var(--text-muted) 0%, var(--medal-silver) 50%, var(--text-muted) 100%);
|
||||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
text-shadow: 0 1px 2px rgba(var(--shadow-rgb), 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rankBadge3 {
|
.rankBadge3 {
|
||||||
background: linear-gradient(135deg, #a5673f 0%, #cd7f32 50%, #a5673f 100%);
|
background: linear-gradient(135deg, var(--status-below) 0%, var(--medal-bronze) 50%, var(--status-below) 100%);
|
||||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
text-shadow: 0 1px 2px rgba(var(--shadow-rgb), 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rankNumber {
|
.rankNumber {
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.schoolCell {
|
.schoolCell {
|
||||||
@@ -296,18 +297,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.schoolLink {
|
.schoolLink {
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: color 0.2s ease;
|
transition: color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.schoolLink:hover {
|
.schoolLink:hover {
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.areaCell,
|
.areaCell,
|
||||||
.typeCell {
|
.typeCell {
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* LA subline under the school name — mobile only (Area column hidden there). */
|
/* LA subline under the school name — mobile only (Area column hidden there). */
|
||||||
@@ -315,7 +316,7 @@
|
|||||||
display: none;
|
display: none;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.valueCell {
|
.valueCell {
|
||||||
@@ -324,7 +325,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.valueCell strong {
|
.valueCell strong {
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--status-above);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,7 +347,7 @@
|
|||||||
.noResults {
|
.noResults {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 4rem 2rem;
|
padding: 4rem 2rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.noResults p {
|
.noResults p {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Per-bar national average marker ──
|
/* ── Per-bar national average marker ──
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
bottom: -3px;
|
bottom: -3px;
|
||||||
width: 2px;
|
width: 2px;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--brand);
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
width: 5px;
|
width: 5px;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: var(--accent-coral, #e07256);
|
background: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.barHeaderRight {
|
.barHeaderRight {
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
.natLabel {
|
.natLabel {
|
||||||
font-size: 0.55rem;
|
font-size: 0.55rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.03em;
|
letter-spacing: 0.03em;
|
||||||
}
|
}
|
||||||
@@ -123,18 +123,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.barExpected {
|
.barExpected {
|
||||||
background: var(--accent-teal-light, #3a9e9e);
|
background: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.barExceeding {
|
.barExceeding {
|
||||||
background: var(--accent-teal, #2d7d7d);
|
background: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.barLabel {
|
.barLabel {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', Georgia, serif;
|
font-family: var(--font-display);
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
@@ -142,7 +142,7 @@
|
|||||||
|
|
||||||
.barLabelSuffix {
|
.barLabelSuffix {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
font-size: 0.6rem;
|
font-size: 0.6rem;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.06em;
|
letter-spacing: 0.06em;
|
||||||
@@ -153,7 +153,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
margin-top: 0.3rem;
|
margin-top: 0.3rem;
|
||||||
border-top: 1px solid var(--border-color, #e5dfd5);
|
border-top: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rulerTick {
|
.rulerTick {
|
||||||
@@ -161,7 +161,7 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
height: 3px;
|
height: 3px;
|
||||||
background: var(--border-color, #e5dfd5);
|
background: var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rulerLabel {
|
.rulerLabel {
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
top: 5px;
|
top: 5px;
|
||||||
font-size: 0.5rem;
|
font-size: 0.5rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
letter-spacing: 0.01em;
|
letter-spacing: 0.01em;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
@@ -198,7 +198,7 @@
|
|||||||
gap: 0.35rem;
|
gap: 0.35rem;
|
||||||
font-size: 0.65rem;
|
font-size: 0.65rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.legendSwatch {
|
.legendSwatch {
|
||||||
|
|||||||
@@ -145,15 +145,15 @@ export default function SatsChart({ subjects }: SatsChartProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles.legend}>
|
<div className={styles.legend}>
|
||||||
<div className={styles.legendItem}>
|
<div className={styles.legendItem}>
|
||||||
<div className={styles.legendSwatch} style={{ background: 'var(--accent-teal-light, #3a9e9e)' }} />
|
<div className={styles.legendSwatch} style={{ background: 'var(--status-above)' }} />
|
||||||
Expected standard
|
Expected standard
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.legendItem}>
|
<div className={styles.legendItem}>
|
||||||
<div className={styles.legendSwatch} style={{ background: 'var(--accent-teal, #2d7d7d)' }} />
|
<div className={styles.legendSwatch} style={{ background: 'var(--status-above)' }} />
|
||||||
Exceeding / high score
|
Exceeding / high score
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.legendItem}>
|
<div className={styles.legendItem}>
|
||||||
<div className={styles.legendSwatch} style={{ background: 'var(--accent-coral, #e07256)', width: '3px', height: '12px', borderRadius: '2px' }} />
|
<div className={styles.legendSwatch} style={{ background: 'var(--brand)', width: '3px', height: '12px', borderRadius: '2px' }} />
|
||||||
National average
|
National average
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.card {
|
.card {
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-left: 3px solid transparent;
|
border-left: 3px solid transparent;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 1rem 1.125rem;
|
padding: 1rem 1.125rem;
|
||||||
@@ -8,13 +8,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.card.cardInCompare {
|
.card.cardInCompare {
|
||||||
border-color: var(--accent-teal, #2d7d7d);
|
border-color: var(--brand);
|
||||||
box-shadow: 0 0 0 1px var(--accent-teal, #2d7d7d);
|
box-shadow: 0 0 0 1px var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card:hover {
|
.card:hover {
|
||||||
border-left-color: var(--accent-coral, #e07256);
|
border-left-color: var(--brand);
|
||||||
box-shadow: var(--shadow-medium, 0 4px 20px rgba(26, 22, 18, 0.1));
|
box-shadow: var(--shadow-medium, 0 4px 20px rgba(var(--shadow-rgb), 0.1));
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,24 +31,24 @@
|
|||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
}
|
}
|
||||||
|
|
||||||
.title a {
|
.title a {
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: color 0.2s ease;
|
transition: color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title a:hover {
|
.title a:hover {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.distance {
|
.distance {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--brand);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
background: var(--accent-teal-bg);
|
background: var(--brand-bg);
|
||||||
padding: 0.125rem 0.5rem;
|
padding: 0.125rem 0.5rem;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -63,9 +63,9 @@
|
|||||||
|
|
||||||
.metaItem {
|
.metaItem {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
padding: 0.125rem 0.5rem;
|
padding: 0.125rem 0.5rem;
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,9 +75,9 @@
|
|||||||
gap: 0.625rem;
|
gap: 0.625rem;
|
||||||
margin-bottom: 0.875rem;
|
margin-bottom: 0.875rem;
|
||||||
padding: 0.625rem 0.75rem;
|
padding: 0.625rem 0.75rem;
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.metric {
|
.metric {
|
||||||
@@ -88,12 +88,13 @@
|
|||||||
|
|
||||||
.metricLabel {
|
.metricLabel {
|
||||||
font-size: 0.6875rem;
|
font-size: 0.6875rem;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.05em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.metricValue {
|
.metricValue {
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.375rem;
|
gap: 0.375rem;
|
||||||
@@ -101,7 +102,7 @@
|
|||||||
|
|
||||||
.metricValue strong {
|
.metricValue strong {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,18 +127,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.trendUp {
|
.trendUp {
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--status-above);
|
||||||
background: var(--accent-teal-bg);
|
background: var(--status-above-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.trendDown {
|
.trendDown {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--status-below);
|
||||||
background: var(--accent-coral-bg);
|
background: var(--status-below-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.trendStable {
|
.trendStable {
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
background: rgba(138, 132, 122, 0.15);
|
background: rgba(var(--muted-rgb), 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
@@ -156,7 +157,7 @@
|
|||||||
|
|
||||||
.metricHint {
|
.metricHint {
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 1px;
|
margin-top: 1px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 210px;
|
height: 210px;
|
||||||
background: #dfe6e2;
|
background: var(--bg-secondary);
|
||||||
isolation: isolate;
|
isolation: isolate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background:
|
background:
|
||||||
linear-gradient(100deg, rgba(255, 255, 255, 0) 40%, rgba(255, 255, 255, .5) 50%, rgba(255, 255, 255, 0) 60%) #e7e2da;
|
linear-gradient(100deg, rgba(255, 255, 255, 0) 40%, rgba(255, 255, 255, .5) 50%, rgba(255, 255, 255, 0) 60%) var(--bg-secondary);
|
||||||
background-size: 200% 100%;
|
background-size: 200% 100%;
|
||||||
animation: shimmer 1.4s infinite;
|
animation: shimmer 1.4s infinite;
|
||||||
}
|
}
|
||||||
@@ -85,11 +85,11 @@
|
|||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
background: rgba(255, 255, 255, .85);
|
background: rgba(255, 255, 255, .85);
|
||||||
-webkit-backdrop-filter: blur(6px);
|
-webkit-backdrop-filter: blur(6px);
|
||||||
backdrop-filter: blur(6px);
|
backdrop-filter: blur(6px);
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, .16);
|
box-shadow: 0 2px 10px rgba(var(--shadow-rgb), .16);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(4px);
|
transform: translateY(4px);
|
||||||
transition: opacity .16s ease, transform .16s ease;
|
transition: opacity .16s ease, transform .16s ease;
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
rgba(255, 255, 255, .35) 35%,
|
rgba(255, 255, 255, .35) 35%,
|
||||||
rgba(255, 255, 255, .75) 62%,
|
rgba(255, 255, 255, .75) 62%,
|
||||||
rgba(255, 255, 255, .95) 82%,
|
rgba(255, 255, 255, .95) 82%,
|
||||||
var(--bg-card, #fff) 100%);
|
var(--bg-card) 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.closeBtn {
|
.closeBtn {
|
||||||
@@ -134,9 +134,9 @@
|
|||||||
border: none;
|
border: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: rgba(255, 255, 255, .92);
|
background: rgba(255, 255, 255, .92);
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, .2);
|
box-shadow: 0 2px 10px rgba(var(--shadow-rgb), .2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.closeBtn:hover {
|
.closeBtn:hover {
|
||||||
|
|||||||
@@ -33,12 +33,12 @@
|
|||||||
border: 2px solid rgba(0, 0, 0, 0.2);
|
border: 2px solid rgba(0, 0, 0, 0.2);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #333;
|
color: var(--text-primary);
|
||||||
transition: background 0.15s ease, color 0.15s ease;
|
transition: background 0.15s ease, color 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fullscreenBtn:hover {
|
.fullscreenBtn:hover {
|
||||||
background: #f4f4f4;
|
background: var(--bg-secondary);
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,9 +57,9 @@
|
|||||||
.spinner {
|
.spinner {
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
border: 3px solid rgba(224, 114, 86, 0.3);
|
border: 3px solid rgba(var(--brand-rgb), 0.3);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
border-top-color: var(--accent-coral, #e07256);
|
border-top-color: var(--brand);
|
||||||
animation: spin 0.8s linear infinite;
|
animation: spin 0.8s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-left: 3px solid transparent;
|
border-left: 3px solid transparent;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 1rem 1.25rem;
|
padding: 1rem 1.25rem;
|
||||||
@@ -12,17 +12,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.row:hover {
|
.row:hover {
|
||||||
box-shadow: 0 2px 8px rgba(26, 22, 18, 0.06);
|
box-shadow: 0 2px 8px rgba(var(--shadow-rgb), 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Phase border colours */
|
/* Phase border colours */
|
||||||
.phasePrimary { border-left-color: var(--phase-primary, #5b8cbf); }
|
.phasePrimary { border-left-color: var(--phase-primary); }
|
||||||
.phaseAllThrough { border-left-color: var(--phase-all-through, #7a9a6d); }
|
.phaseAllThrough { border-left-color: var(--phase-all-through); }
|
||||||
.phaseNursery { border-left-color: var(--phase-nursery, #e0a0b0); }
|
.phaseNursery { border-left-color: var(--phase-nursery); }
|
||||||
|
|
||||||
.rowInCompare {
|
.rowInCompare {
|
||||||
border-left-color: var(--accent-teal, #2d7d7d);
|
border-left-color: var(--brand);
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes rowFadeIn {
|
@keyframes rowFadeIn {
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
.schoolName {
|
.schoolName {
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.schoolName:hover {
|
.schoolName:hover {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Phase label pill */
|
/* Phase label pill */
|
||||||
@@ -96,8 +96,8 @@
|
|||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
background: rgba(26, 22, 18, 0.05);
|
background: rgba(var(--shadow-rgb), 0.05);
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Line 3: stats */
|
/* Line 3: stats */
|
||||||
@@ -115,10 +115,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.statValue {
|
.statValue {
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.2rem;
|
gap: 0.2rem;
|
||||||
@@ -126,7 +127,7 @@
|
|||||||
|
|
||||||
.statLabel {
|
.statLabel {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,9 +138,9 @@
|
|||||||
margin-left: 1px;
|
margin-left: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.trendUp { color: var(--accent-teal, #2d7d7d); }
|
.trendUp { color: var(--status-above); }
|
||||||
.trendDown { color: var(--accent-coral, #e07256); }
|
.trendDown { color: var(--status-below); }
|
||||||
.trendStable { color: var(--text-muted, #8a847a); }
|
.trendStable { color: var(--text-muted); }
|
||||||
|
|
||||||
/* Line 4: location */
|
/* Line 4: location */
|
||||||
.line4 {
|
.line4 {
|
||||||
@@ -148,13 +149,13 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 0;
|
gap: 0;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.line4 span:not(:last-child)::after {
|
.line4 span:not(:last-child)::after {
|
||||||
content: '·';
|
content: '·';
|
||||||
margin: 0 0.4rem;
|
margin: 0 0.4rem;
|
||||||
color: var(--border-color, #e5dfd5);
|
color: var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.distanceBadge {
|
.distanceBadge {
|
||||||
@@ -162,8 +163,8 @@
|
|||||||
padding: 0.0625rem 0.375rem;
|
padding: 0.0625rem 0.375rem;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background: var(--accent-teal, #2d7d7d);
|
background: var(--brand);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,23 +201,23 @@
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ofsted1 { background: var(--accent-teal-bg); color: var(--accent-teal, #2d7d7d); }
|
.ofsted1 { background: var(--status-above-bg); color: var(--status-above); }
|
||||||
.ofsted2 { background: rgba(60, 140, 60, 0.12); color: #2f7a2f; }
|
.ofsted2 { background: rgba(var(--status-above-rgb), 0.12); color: var(--status-above); }
|
||||||
.ofsted3 { background: var(--accent-gold-bg); color: var(--accent-gold-text, #7a6800); }
|
.ofsted3 { background: var(--status-below-bg); color: var(--status-below); }
|
||||||
.ofsted4 { background: var(--accent-coral-bg); color: var(--accent-coral, #e07256); }
|
.ofsted4 { background: var(--status-below); color: var(--text-inverse); }
|
||||||
|
|
||||||
/* ── Ofsted badge variants ──────────────────────────────────────────────── */
|
/* ── Ofsted badge variants ──────────────────────────────────────────────── */
|
||||||
/* ofsted1–4 already defined above; these cover the two new framework states */
|
/* ofsted1–4 already defined above; these cover the two new framework states */
|
||||||
.ofstedRc { background: #5a3a6e; color: #fff; }
|
.ofstedRc { background: var(--phase-secondary-text); color: var(--text-inverse); }
|
||||||
/* Inspected but with no overall grade (OEIF post-Sept-2024) — neutral slate,
|
/* Inspected but with no overall grade (OEIF post-Sept-2024) — neutral slate,
|
||||||
distinct from the grey "Not yet inspected" pending state. */
|
distinct from the grey "Not yet inspected" pending state. */
|
||||||
.ofstedInspected { background: #e6ecf2; color: #45586b; }
|
.ofstedInspected { background: var(--phase-primary-bg); color: var(--phase-primary-text); }
|
||||||
.ofstedPending { background: #e0e0e0; color: #666; }
|
.ofstedPending { background: var(--border); color: var(--text-muted); }
|
||||||
|
|
||||||
/* ── vs-national delta line (under RWM metric) ──────────────────────────── */
|
/* ── vs-national delta line (under RWM metric) ──────────────────────────── */
|
||||||
.vsNational { font-size: 0.7rem; color: var(--accent-teal, #2d7d7d); font-weight: 600; }
|
.vsNational { font-size: 0.7rem; color: var(--status-above); font-weight: 600; }
|
||||||
.vsNationalNeg { font-size: 0.7rem; color: var(--accent-coral, #e07256); font-weight: 600; }
|
.vsNationalNeg { font-size: 0.7rem; color: var(--brand); font-weight: 600; }
|
||||||
.vsNationalFlat { font-size: 0.7rem; color: var(--text-muted, #8a847a); }
|
.vsNationalFlat { font-size: 0.7rem; color: var(--text-muted); }
|
||||||
|
|
||||||
/* ── Mobile ──────────────────────────────────────────── */
|
/* ── Mobile ──────────────────────────────────────────── */
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
@@ -257,7 +258,7 @@
|
|||||||
|
|
||||||
/* GIAS "Open, but proposed to close" marker */
|
/* GIAS "Open, but proposed to close" marker */
|
||||||
.attrClosing {
|
.attrClosing {
|
||||||
background: #fdf6e3;
|
background: var(--status-below-bg);
|
||||||
color: #8a6200;
|
color: var(--status-below);
|
||||||
border: 1px solid #e2c96f;
|
border: 1px solid var(--status-below-bg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.warning {
|
.warning {
|
||||||
background: var(--accent-gold-bg);
|
background: var(--status-below-bg);
|
||||||
border: 1px solid var(--accent-gold, #c9a227);
|
border: 1px solid var(--status-below);
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
@@ -21,21 +21,21 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.875rem 1rem;
|
padding: 0.875rem 1rem;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
border: 2px solid var(--border-color, #e5dfd5);
|
border: 2px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchInput::placeholder {
|
.searchInput::placeholder {
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchInput:focus {
|
.searchInput:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
box-shadow: 0 0 0 3px var(--accent-coral-bg);
|
box-shadow: 0 0 0 3px var(--brand-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchSpinner {
|
.searchSpinner {
|
||||||
@@ -45,9 +45,9 @@
|
|||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
width: 1.25rem;
|
width: 1.25rem;
|
||||||
height: 1.25rem;
|
height: 1.25rem;
|
||||||
border: 2px solid rgba(224, 114, 86, 0.3);
|
border: 2px solid rgba(var(--brand-rgb), 0.3);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
border-top-color: var(--accent-coral, #e07256);
|
border-top-color: var(--brand);
|
||||||
animation: spin 0.6s linear infinite;
|
animation: spin 0.6s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,17 +71,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.results::-webkit-scrollbar-track {
|
.results::-webkit-scrollbar-track {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.results::-webkit-scrollbar-thumb {
|
.results::-webkit-scrollbar-thumb {
|
||||||
background: var(--border-color, #e5dfd5);
|
background: var(--border);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.results::-webkit-scrollbar-thumb:hover {
|
.results::-webkit-scrollbar-thumb:hover {
|
||||||
background: var(--text-muted, #8a847a);
|
background: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.resultItem {
|
.resultItem {
|
||||||
@@ -90,16 +90,16 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.resultItem:hover {
|
.resultItem:hover {
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
box-shadow: var(--shadow-soft, 0 2px 8px rgba(26, 22, 18, 0.06));
|
box-shadow: var(--shadow-soft, 0 2px 8px rgba(var(--shadow-rgb), 0.06));
|
||||||
}
|
}
|
||||||
|
|
||||||
.schoolInfo {
|
.schoolInfo {
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
.schoolName {
|
.schoolName {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.25rem;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.schoolMeta span {
|
.schoolMeta span {
|
||||||
@@ -138,14 +138,14 @@
|
|||||||
.noResults {
|
.noResults {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hint {
|
.hint {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-left: 3px solid transparent;
|
border-left: 3px solid transparent;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 1rem 1.25rem;
|
padding: 1rem 1.25rem;
|
||||||
@@ -12,17 +12,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.row:hover {
|
.row:hover {
|
||||||
box-shadow: 0 2px 8px rgba(26, 22, 18, 0.06);
|
box-shadow: 0 2px 8px rgba(var(--shadow-rgb), 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Phase border colours */
|
/* Phase border colours */
|
||||||
.phaseSecondary { border-left-color: var(--phase-secondary, #9b6bb0); }
|
.phaseSecondary { border-left-color: var(--phase-secondary); }
|
||||||
.phaseAllThrough { border-left-color: var(--phase-all-through, #7a9a6d); }
|
.phaseAllThrough { border-left-color: var(--phase-all-through); }
|
||||||
.phasePost16 { border-left-color: var(--phase-post16, #c4915e); }
|
.phasePost16 { border-left-color: var(--phase-post16); }
|
||||||
|
|
||||||
.rowInCompare {
|
.rowInCompare {
|
||||||
border-left-color: var(--accent-teal, #2d7d7d);
|
border-left-color: var(--brand);
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes rowFadeIn {
|
@keyframes rowFadeIn {
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
.schoolName {
|
.schoolName {
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.schoolName:hover {
|
.schoolName:hover {
|
||||||
color: var(--accent-coral, #e07256);
|
color: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Line 2: context tags */
|
/* Line 2: context tags */
|
||||||
@@ -81,8 +81,8 @@
|
|||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
background: rgba(26, 22, 18, 0.05);
|
background: rgba(var(--shadow-rgb), 0.05);
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Line 3: KS4 stats */
|
/* Line 3: KS4 stats */
|
||||||
@@ -100,22 +100,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.statValueLarge {
|
.statValueLarge {
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
}
|
}
|
||||||
|
|
||||||
.statValue {
|
.statValue {
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
font-family: var(--font-playfair), 'Playfair Display', serif;
|
font-family: var(--font-display);
|
||||||
}
|
}
|
||||||
|
|
||||||
.statLabel {
|
.statLabel {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,8 +127,8 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.deltaPositive { color: #2f7a2f; }
|
.deltaPositive { color: var(--status-above); }
|
||||||
.deltaNegative { color: var(--accent-coral, #e07256); }
|
.deltaNegative { color: var(--status-below); }
|
||||||
|
|
||||||
/* Line 4: location + distance */
|
/* Line 4: location + distance */
|
||||||
.line4 {
|
.line4 {
|
||||||
@@ -135,13 +137,13 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 0;
|
gap: 0;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.line4 span:not(:last-child)::after {
|
.line4 span:not(:last-child)::after {
|
||||||
content: '·';
|
content: '·';
|
||||||
margin: 0 0.4rem;
|
margin: 0 0.4rem;
|
||||||
color: var(--border-color, #e5dfd5);
|
color: var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.distanceBadge {
|
.distanceBadge {
|
||||||
@@ -149,8 +151,8 @@
|
|||||||
padding: 0.0625rem 0.375rem;
|
padding: 0.0625rem 0.375rem;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background: var(--accent-teal, #2d7d7d);
|
background: var(--brand);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,15 +177,15 @@
|
|||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
background: rgba(26, 22, 18, 0.05);
|
background: rgba(var(--shadow-rgb), 0.05);
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selectiveTag {
|
.selectiveTag {
|
||||||
background: rgba(180, 120, 0, 0.1);
|
background: rgba(var(--status-below-rgb), 0.1);
|
||||||
color: #8a6200;
|
color: var(--status-below);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Ofsted badge ────────────────────────────────────── */
|
/* ── Ofsted badge ────────────────────────────────────── */
|
||||||
@@ -202,17 +204,17 @@
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ofsted1 { background: var(--accent-teal-bg); color: var(--accent-teal, #2d7d7d); }
|
.ofsted1 { background: var(--status-above-bg); color: var(--status-above); }
|
||||||
.ofsted2 { background: rgba(60, 140, 60, 0.12); color: #2f7a2f; }
|
.ofsted2 { background: rgba(var(--status-above-rgb), 0.12); color: var(--status-above); }
|
||||||
.ofsted3 { background: var(--accent-gold-bg); color: var(--accent-gold-text, #7a6800); }
|
.ofsted3 { background: var(--status-below-bg); color: var(--status-below); }
|
||||||
.ofsted4 { background: var(--accent-coral-bg); color: var(--accent-coral, #e07256); }
|
.ofsted4 { background: var(--status-below); color: var(--text-inverse); }
|
||||||
|
|
||||||
/* ── Ofsted badge variants ──────────────────────────────────────────────── */
|
/* ── Ofsted badge variants ──────────────────────────────────────────────── */
|
||||||
.ofstedRc { background: #5a3a6e; color: #fff; }
|
.ofstedRc { background: var(--phase-secondary-text); color: var(--text-inverse); }
|
||||||
/* Inspected but with no overall grade (OEIF post-Sept-2024) — neutral slate,
|
/* Inspected but with no overall grade (OEIF post-Sept-2024) — neutral slate,
|
||||||
distinct from the grey "Not yet inspected" pending state. */
|
distinct from the grey "Not yet inspected" pending state. */
|
||||||
.ofstedInspected { background: #e6ecf2; color: #45586b; }
|
.ofstedInspected { background: var(--phase-primary-bg); color: var(--phase-primary-text); }
|
||||||
.ofstedPending { background: #e0e0e0; color: #666; }
|
.ofstedPending { background: var(--border); color: var(--text-muted); }
|
||||||
|
|
||||||
/* ── Right actions column ────────────────────────────── */
|
/* ── Right actions column ────────────────────────────── */
|
||||||
.rowActions {
|
.rowActions {
|
||||||
@@ -268,7 +270,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.closingTag {
|
.closingTag {
|
||||||
background: #fdf6e3;
|
background: var(--status-below-bg);
|
||||||
color: #8a6200;
|
color: var(--status-below);
|
||||||
border: 1px solid #e2c96f;
|
border: 1px solid var(--status-below-bg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
/* Special-school / PRU / AP context note: soft, informational (teal), not a
|
/* Special-school / PRU / AP context note: soft, informational (teal), not a
|
||||||
warning. Shared by both detail views so the styling can't drift. */
|
warning. Shared by both detail views so the styling can't drift. */
|
||||||
.note {
|
.note {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-left: 4px solid var(--accent-teal, #2d7d7d);
|
border-left: 4px solid var(--brand);
|
||||||
border-radius: 0 6px 6px 0;
|
border-radius: 0 6px 6px 0;
|
||||||
padding: 0.7rem 1rem;
|
padding: 0.7rem 1rem;
|
||||||
margin: 0 0 1rem;
|
margin: 0 0 1rem;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
.note strong {
|
.note strong {
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.moreMeasures {
|
.moreMeasures {
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
border-top: 1px solid var(--border-light);
|
border-top: 1px solid var(--border);
|
||||||
padding-top: 0.75rem;
|
padding-top: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 0.88rem;
|
font-size: 0.88rem;
|
||||||
color: var(--accent-coral-dark);
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stripNote {
|
.stripNote {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ export function CompareAtAGlance({
|
|||||||
)}
|
)}
|
||||||
{display.kind === 'transitional' && (
|
{display.kind === 'transitional' && (
|
||||||
<>
|
<>
|
||||||
<span className={s.badge} style={{ backgroundColor: '#e2e8f0', color: '#475569' }}>
|
<span className={s.badge} style={{ backgroundColor: 'var(--bg-secondary)', color: 'var(--text-secondary)' }}>
|
||||||
No overall grade
|
No overall grade
|
||||||
</span>
|
</span>
|
||||||
<span className={s.small}>Sub-judgements only</span>
|
<span className={s.small}>Sub-judgements only</span>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ function ResultCell({ display }: { display: OfstedDisplay }) {
|
|||||||
if (display.kind === 'transitional') {
|
if (display.kind === 'transitional') {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span className={s.badge} style={{ backgroundColor: '#e2e8f0', color: '#475569' }}>
|
<span className={s.badge} style={{ backgroundColor: 'var(--bg-secondary)', color: 'var(--text-secondary)' }}>
|
||||||
No overall grade
|
No overall grade
|
||||||
</span>
|
</span>
|
||||||
<span className={s.small}>
|
<span className={s.small}>
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
.explore summary {
|
.explore summary {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--accent-coral-dark);
|
color: var(--brand-strong);
|
||||||
padding: 0.85rem 1.1rem;
|
padding: 0.85rem 1.1rem;
|
||||||
background: var(--bg-card);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-light);
|
border: 1px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.inner {
|
.inner {
|
||||||
border: 1px solid var(--border-light);
|
border: 1px solid var(--border);
|
||||||
border-top: none;
|
border-top: none;
|
||||||
border-radius: 0 0 8px 8px;
|
border-radius: 0 0 8px 8px;
|
||||||
background: var(--bg-card);
|
background: var(--bg-card);
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
padding: 0.4rem 0.6rem;
|
padding: 0.4rem 0.6rem;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 1px solid var(--border-light);
|
border: 1px solid var(--border);
|
||||||
background: var(--bg-card);
|
background: var(--bg-card);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sectionTitle {
|
.sectionTitle {
|
||||||
font-family: var(--font-playfair), 'Playfair Display', Georgia, serif;
|
font-family: var(--font-display);
|
||||||
font-size: 1.45rem;
|
font-size: 1.45rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-left: 0.75rem;
|
padding-left: 0.75rem;
|
||||||
border-left: 3px solid var(--accent-coral-dark);
|
border-left: 3px solid var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.how {
|
.how {
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
back into the shared grid. */
|
back into the shared grid. */
|
||||||
.measure {
|
.measure {
|
||||||
background: var(--bg-card);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-light);
|
border: 1px solid var(--border);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
box-shadow: var(--shadow-soft);
|
box-shadow: var(--shadow-soft);
|
||||||
padding: 0.75rem 0.85rem;
|
padding: 0.75rem 0.85rem;
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
gap: 0.35rem 0.5rem;
|
gap: 0.35rem 0.5rem;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
padding: 0.5rem 0;
|
padding: 0.5rem 0;
|
||||||
border-top: 1px solid var(--border-light);
|
border-top: 1px solid var(--border);
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
}
|
}
|
||||||
@@ -113,18 +113,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chipGood {
|
.chipGood {
|
||||||
background: rgba(45, 125, 125, 0.14);
|
background: rgba(var(--status-above-rgb), 0.14);
|
||||||
color: var(--accent-teal);
|
color: var(--status-above);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipWarn {
|
.chipWarn {
|
||||||
background: var(--accent-gold-bg);
|
background: var(--status-below-bg);
|
||||||
color: var(--accent-gold-text);
|
color: var(--status-below);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipBad {
|
.chipBad {
|
||||||
background: var(--accent-coral-bg);
|
background: var(--status-below-bg);
|
||||||
color: var(--accent-coral-dark);
|
color: var(--status-below);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipNeutral {
|
.chipNeutral {
|
||||||
@@ -141,18 +141,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.badgeGood {
|
.badgeGood {
|
||||||
background: rgba(45, 125, 125, 0.14);
|
background: rgba(var(--status-above-rgb), 0.14);
|
||||||
color: var(--accent-teal);
|
color: var(--status-above);
|
||||||
}
|
}
|
||||||
|
|
||||||
.badgeWarn {
|
.badgeWarn {
|
||||||
background: var(--accent-gold-bg);
|
background: var(--status-below-bg);
|
||||||
color: var(--accent-gold-text);
|
color: var(--status-below);
|
||||||
}
|
}
|
||||||
|
|
||||||
.badgeBad {
|
.badgeBad {
|
||||||
background: var(--accent-coral-bg);
|
background: var(--status-below-bg);
|
||||||
color: var(--accent-coral-dark);
|
color: var(--status-below);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rcList {
|
.rcList {
|
||||||
@@ -200,7 +200,7 @@
|
|||||||
|
|
||||||
.card {
|
.card {
|
||||||
background: var(--bg-card);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-light);
|
border: 1px solid var(--border);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: var(--shadow-soft);
|
box-shadow: var(--shadow-soft);
|
||||||
padding: 1.25rem 1.5rem;
|
padding: 1.25rem 1.5rem;
|
||||||
@@ -208,7 +208,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.link {
|
.link {
|
||||||
color: var(--accent-coral-dark);
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 761px) {
|
@media (min-width: 761px) {
|
||||||
@@ -230,14 +230,14 @@
|
|||||||
.rowLabel {
|
.rowLabel {
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
padding: 0.85rem 0.5rem 0.85rem 0;
|
padding: 0.85rem 0.5rem 0.85rem 0;
|
||||||
border-bottom: 1px solid var(--border-light);
|
border-bottom: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cell {
|
.cell {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 0.85rem 0.25rem;
|
padding: 0.85rem 0.25rem;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
border-bottom: 1px solid var(--border-light);
|
border-bottom: 1px solid var(--border);
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,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-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
|
|
||||||
.topBack:hover {
|
.topBack:hover {
|
||||||
color: var(--accent-coral-dark, #c85a3e);
|
color: var(--brand-strong);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
text-underline-offset: 2px;
|
text-underline-offset: 2px;
|
||||||
}
|
}
|
||||||
@@ -38,8 +38,8 @@
|
|||||||
/* Header Section */
|
/* Header Section */
|
||||||
.header {
|
.header {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
/* Padding lives on .headerContent so the map band can bleed to the edges. */
|
/* Padding lives on .headerContent so the map band can bleed to the edges. */
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -88,12 +88,13 @@
|
|||||||
|
|
||||||
|
|
||||||
.headerHasMap .actions .btnAdd {
|
.headerHasMap .actions .btnAdd {
|
||||||
|
/* Sits on the map hero, which renders light in both themes. */
|
||||||
background: rgba(255, 255, 255, 0.9);
|
background: rgba(255, 255, 255, 0.9);
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
-webkit-backdrop-filter: blur(6px);
|
-webkit-backdrop-filter: blur(6px);
|
||||||
backdrop-filter: blur(6px);
|
backdrop-filter: blur(6px);
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.16);
|
box-shadow: 0 2px 10px rgba(var(--shadow-rgb), 0.16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -116,14 +117,14 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
font: inherit;
|
font: inherit;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.mapLink:hover {
|
.mapLink:hover {
|
||||||
color: var(--accent-coral-dark, #c45a3f);
|
color: var(--brand-strong);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
text-underline-offset: 2px;
|
text-underline-offset: 2px;
|
||||||
}
|
}
|
||||||
@@ -137,11 +138,11 @@
|
|||||||
.schoolName {
|
.schoolName {
|
||||||
font-size: clamp(2rem, 5vw, 3.25rem);
|
font-size: clamp(2rem, 5vw, 3.25rem);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
line-height: 1.1;
|
line-height: 1.1;
|
||||||
letter-spacing: -0.01em;
|
letter-spacing: -0.01em;
|
||||||
font-family: var(--font-playfair), "Playfair Display", serif;
|
font-family: var(--font-display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -155,16 +156,16 @@
|
|||||||
|
|
||||||
.metaItem {
|
.metaItem {
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
padding: 0.125rem 0.5rem;
|
padding: 0.125rem 0.5rem;
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.address {
|
.address {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: var(--text-muted, #8a847a);
|
color: var(--text-muted);
|
||||||
margin: 0 0 0.75rem;
|
margin: 0 0 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,18 +181,18 @@
|
|||||||
|
|
||||||
.headerDetail {
|
.headerDetail {
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.headerDetail strong {
|
.headerDetail strong {
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.headerDetail a {
|
.headerDetail a {
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--brand);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +214,7 @@
|
|||||||
border: none;
|
border: none;
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--brand);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,25 +237,25 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
box-shadow: var(--shadow-soft, 0 2px 8px rgba(26, 22, 18, 0.08));
|
box-shadow: var(--shadow-soft, 0 2px 8px rgba(var(--shadow-rgb), 0.08));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.btnAdd {
|
.btnAdd {
|
||||||
background: var(--accent-coral-dark, #b04a2e);
|
background: var(--brand-strong);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.btnAdd:hover {
|
.btnAdd:hover {
|
||||||
background: var(--accent-coral-darker, #9c3f26);
|
background: var(--brand-stronger);
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.btnRemove {
|
.btnRemove {
|
||||||
background: var(--accent-teal, #2d7d7d);
|
background: var(--brand);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -270,13 +271,13 @@
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 64px; /* global header height on desktop */
|
top: 64px; /* global header height on desktop */
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-top: none;
|
border-top: none;
|
||||||
border-radius: 0 0 10px 10px;
|
border-radius: 0 0 10px 10px;
|
||||||
padding: 0.5rem 0.75rem;
|
padding: 0.5rem 0.75rem;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
|
box-shadow: 0 2px 4px rgba(var(--shadow-rgb), 0.04);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
@@ -291,9 +292,9 @@
|
|||||||
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-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
background: none;
|
background: none;
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -302,8 +303,8 @@
|
|||||||
|
|
||||||
|
|
||||||
.sectionNavBack:hover {
|
.sectionNavBack:hover {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-color: var(--accent-coral, #e07256);
|
border-color: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -334,7 +335,7 @@
|
|||||||
padding: 0.3rem 0.625rem;
|
padding: 0.3rem 0.625rem;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
transition: all 0.15s ease;
|
transition: all 0.15s ease;
|
||||||
@@ -344,21 +345,21 @@
|
|||||||
|
|
||||||
|
|
||||||
.sectionNavLink:hover {
|
.sectionNavLink:hover {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.sectionNavLinkActive {
|
.sectionNavLinkActive {
|
||||||
background: var(--accent-coral-dark, #b04a2e);
|
background: var(--brand-strong);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.sectionNavLinkActive:hover {
|
.sectionNavLinkActive:hover {
|
||||||
background: var(--accent-coral-dark, #c45a3f);
|
background: var(--brand-strong);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -373,12 +374,12 @@
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
padding: 0.34rem 0.7rem;
|
padding: 0.34rem 0.7rem;
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-family: var(--font-dm-sans), "DM Sans", sans-serif;
|
font-family: var(--font-ui);
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -396,7 +397,7 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -411,7 +412,7 @@
|
|||||||
|
|
||||||
.sectionNavMenuChev {
|
.sectionNavMenuChev {
|
||||||
flex: none;
|
flex: none;
|
||||||
color: var(--text-muted, #6d685f);
|
color: var(--text-muted);
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,9 +427,9 @@
|
|||||||
width: 38px;
|
width: 38px;
|
||||||
height: 38px;
|
height: 38px;
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
border: 1px solid var(--accent-coral-dark, #b04a2e);
|
border: 1px solid var(--brand-strong);
|
||||||
background: var(--accent-coral-dark, #b04a2e);
|
background: var(--brand-strong);
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.15s ease, border-color 0.15s ease;
|
transition: background 0.15s ease, border-color 0.15s ease;
|
||||||
}
|
}
|
||||||
@@ -447,9 +448,9 @@
|
|||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
color: var(--accent-coral-dark, #c45a3f);
|
color: var(--brand-strong);
|
||||||
border: 1.5px solid var(--accent-coral, #e07256);
|
border: 1.5px solid var(--brand);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -460,9 +461,9 @@
|
|||||||
|
|
||||||
|
|
||||||
.sectionNavCompareIconIn {
|
.sectionNavCompareIconIn {
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border-color: var(--accent-teal, #2d7d7d);
|
border-color: var(--brand);
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -474,9 +475,9 @@
|
|||||||
padding: 0.34rem 0.7rem;
|
padding: 0.34rem 0.7rem;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: white;
|
color: var(--brand-on);
|
||||||
background: var(--accent-coral-dark, #b04a2e);
|
background: var(--brand-strong);
|
||||||
border: 1px solid var(--accent-coral-dark, #b04a2e);
|
border: 1px solid var(--brand-strong);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -485,21 +486,21 @@
|
|||||||
|
|
||||||
|
|
||||||
.sectionNavCompare:hover {
|
.sectionNavCompare:hover {
|
||||||
background: var(--accent-coral-darker, #9c3f26);
|
background: var(--brand-stronger);
|
||||||
border-color: var(--accent-coral-darker, #9c3f26);
|
border-color: var(--brand-stronger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.sectionNavCompareIn {
|
.sectionNavCompareIn {
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
color: var(--accent-teal, #2d7d7d);
|
color: var(--brand);
|
||||||
border-color: var(--accent-teal, #2d7d7d);
|
border-color: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.sectionNavCompareIn:hover {
|
.sectionNavCompareIn:hover {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border-color: var(--accent-teal, #2d7d7d);
|
border-color: var(--brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -512,8 +513,8 @@
|
|||||||
padding: 0.34rem 0.65rem;
|
padding: 0.34rem 0.65rem;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -523,7 +524,7 @@
|
|||||||
|
|
||||||
|
|
||||||
.sectionNavAll:hover {
|
.sectionNavAll:hover {
|
||||||
background: var(--border-color, #e5dfd5);
|
background: var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -531,7 +532,7 @@
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
z-index: 1500;
|
z-index: 1500;
|
||||||
background: rgba(26, 22, 18, 0.28);
|
background: rgba(var(--shadow-rgb), 0.28);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -543,19 +544,19 @@
|
|||||||
width: 230px;
|
width: 230px;
|
||||||
max-height: min(70vh, 460px);
|
max-height: min(70vh, 460px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
background: var(--bg-card, white);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color, #e5dfd5);
|
border: 1px solid var(--border);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
box-shadow: 0 18px 44px rgba(26, 22, 18, 0.2);
|
box-shadow: 0 18px 44px rgba(var(--shadow-rgb), 0.2);
|
||||||
padding: 0.35rem;
|
padding: 0.35rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.sectionsPanelHead {
|
.sectionsPanelHead {
|
||||||
font-family: var(--font-playfair), "Playfair Display", Georgia, serif;
|
font-family: var(--font-display);
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
padding: 0.4rem 0.6rem 0.5rem;
|
padding: 0.4rem 0.6rem 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -568,44 +569,44 @@
|
|||||||
padding: 0.55rem 0.6rem;
|
padding: 0.55rem 0.6rem;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
color: var(--text-secondary, #5c564d);
|
color: var(--text-secondary);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: background 0.12s ease;
|
transition: background 0.12s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.sectionsItem:hover {
|
.sectionsItem:hover {
|
||||||
background: var(--bg-secondary, #f3ede4);
|
background: var(--bg-secondary);
|
||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.sectionsItemActive {
|
.sectionsItemActive {
|
||||||
background: var(--accent-coral-bg, rgba(224, 114, 86, 0.12));
|
background: var(--brand-bg);
|
||||||
color: var(--accent-coral-dark, #c45a3f);
|
color: var(--brand-strong);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.sectionsTick {
|
.sectionsTick {
|
||||||
color: var(--accent-coral-dark, #b04a2e);
|
color: var(--brand-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* GIAS "Open, but proposed to close" notice strip */
|
/* GIAS "Open, but proposed to close" notice strip */
|
||||||
.closingStrip {
|
.closingStrip {
|
||||||
background: #fdf6e3;
|
background: var(--status-below-bg);
|
||||||
border-left: 4px solid #e2c96f;
|
border-left: 4px solid var(--status-below-bg);
|
||||||
border-radius: 0 6px 6px 0;
|
border-radius: 0 6px 6px 0;
|
||||||
padding: 0.55rem 0.9rem;
|
padding: 0.55rem 0.9rem;
|
||||||
margin: 0.5rem 0;
|
margin: 0.5rem 0;
|
||||||
font-size: 0.88rem;
|
font-size: 0.88rem;
|
||||||
color: #6e5a00;
|
color: var(--status-below);
|
||||||
max-width: 68ch;
|
max-width: 68ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.closingStrip strong {
|
.closingStrip strong {
|
||||||
color: #8a6200;
|
color: var(--status-below);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
@@ -738,7 +739,7 @@
|
|||||||
max-height: 74vh;
|
max-height: 74vh;
|
||||||
border-radius: 16px 16px 0 0;
|
border-radius: 16px 16px 0 0;
|
||||||
padding: 0.5rem 0.6rem calc(0.8rem + env(safe-area-inset-bottom, 0));
|
padding: 0.5rem 0.6rem calc(0.8rem + env(safe-area-inset-bottom, 0));
|
||||||
box-shadow: 0 -10px 40px rgba(26, 22, 18, 0.25);
|
box-shadow: 0 -10px 40px rgba(var(--shadow-rgb), 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sectionsItem {
|
.sectionsItem {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,163 @@
|
|||||||
|
/**
|
||||||
|
* Bridge between the CSS token layer and the bits of the UI that are painted
|
||||||
|
* from JavaScript — Chart.js datasets and Leaflet markers.
|
||||||
|
*
|
||||||
|
* Those two can't use var(), so before this they carried their own hardcoded
|
||||||
|
* hexes. That is how the chart palette drifted off-brand (a stray purple and
|
||||||
|
* Flat UI's stock blue) and why charts would have ignored the dark theme
|
||||||
|
* entirely. Reading the computed custom property keeps one source of truth.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export type ThemeToken =
|
||||||
|
| '--brand'
|
||||||
|
| '--brand-strong'
|
||||||
|
| '--brand-bg'
|
||||||
|
| '--status-above'
|
||||||
|
| '--status-above-bg'
|
||||||
|
| '--status-below'
|
||||||
|
| '--status-below-bg'
|
||||||
|
| '--text-primary'
|
||||||
|
| '--text-secondary'
|
||||||
|
| '--text-muted'
|
||||||
|
| '--text-inverse'
|
||||||
|
| '--bg-card'
|
||||||
|
| '--bg-secondary'
|
||||||
|
| '--border'
|
||||||
|
| '--border-strong'
|
||||||
|
| '--surface-inverse'
|
||||||
|
| '--chart-1'
|
||||||
|
| '--chart-2'
|
||||||
|
| '--chart-3'
|
||||||
|
| '--chart-4'
|
||||||
|
| '--chart-5'
|
||||||
|
| '--chart-6'
|
||||||
|
| '--chart-grid'
|
||||||
|
| '--chart-reference'
|
||||||
|
| '--phase-primary'
|
||||||
|
| '--phase-secondary-text'
|
||||||
|
| '--medal-gold'
|
||||||
|
| '--medal-silver'
|
||||||
|
| '--medal-bronze';
|
||||||
|
|
||||||
|
/** Values used before hydration and in any non-DOM context (SSR, tests). */
|
||||||
|
const FALLBACK: Record<string, string> = {
|
||||||
|
'--brand': '#584a9b',
|
||||||
|
'--brand-strong': '#473c80',
|
||||||
|
'--brand-bg': 'rgba(88, 74, 155, 0.10)',
|
||||||
|
'--status-above': '#0e6e66',
|
||||||
|
'--status-above-bg': 'rgba(14, 110, 102, 0.10)',
|
||||||
|
'--status-below': '#9a5b00',
|
||||||
|
'--status-below-bg': 'rgba(154, 91, 0, 0.11)',
|
||||||
|
'--text-primary': '#16202a',
|
||||||
|
'--text-secondary': '#4a545f',
|
||||||
|
'--text-muted': '#5c6570',
|
||||||
|
'--text-inverse': '#f7f7f4',
|
||||||
|
'--bg-card': '#fcfcfa',
|
||||||
|
'--bg-secondary': '#e9e8e2',
|
||||||
|
'--border': '#dedcd5',
|
||||||
|
'--border-strong': '#cdcac1',
|
||||||
|
'--surface-inverse': '#16202a',
|
||||||
|
'--chart-1': '#584a9b',
|
||||||
|
'--chart-2': '#0e6e66',
|
||||||
|
'--chart-3': '#9a5b00',
|
||||||
|
'--chart-4': '#8a7cc9',
|
||||||
|
'--chart-5': '#3e9c92',
|
||||||
|
'--chart-6': '#c9903d',
|
||||||
|
'--chart-grid': '#dedcd5',
|
||||||
|
'--chart-reference': '#5c6570',
|
||||||
|
'--phase-primary': '#4a6072',
|
||||||
|
'--phase-secondary-text': '#4e4570',
|
||||||
|
'--medal-gold': '#a67c00',
|
||||||
|
'--medal-silver': '#6f7580',
|
||||||
|
'--medal-bronze': '#8a5a2b',
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Read one token. Safe to call during SSR — returns the light-theme value. */
|
||||||
|
export function token(name: ThemeToken): string {
|
||||||
|
if (typeof window === 'undefined') return FALLBACK[name];
|
||||||
|
const value = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
||||||
|
return value || FALLBACK[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `token`, but the component re-renders when the OS theme flips so
|
||||||
|
* canvas-painted colours don't get stranded in the previous theme.
|
||||||
|
*/
|
||||||
|
export function useThemeTokens<T extends readonly ThemeToken[]>(
|
||||||
|
...names: T
|
||||||
|
): { [K in keyof T]: string } {
|
||||||
|
const read = () => names.map((n) => token(n)) as { [K in keyof T]: string };
|
||||||
|
const [values, setValues] = useState(read);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Only commit when something actually changed. In the light theme the
|
||||||
|
// computed values equal the fallbacks, so this is a no-op — which matters
|
||||||
|
// because a state update here re-renders the chart and makes Chart.js
|
||||||
|
// resize a canvas that may not be laid out yet.
|
||||||
|
const sync = () => setValues((prev) => (sameValues(prev, read()) ? prev : read()));
|
||||||
|
sync();
|
||||||
|
const mq = window.matchMedia('(prefers-color-scheme: dark)');
|
||||||
|
mq.addEventListener('change', sync);
|
||||||
|
return () => mq.removeEventListener('change', sync);
|
||||||
|
// `names` is a fixed-length literal tuple at every call site.
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sameValues(a: readonly string[], b: readonly string[]): boolean {
|
||||||
|
return a.length === b.length && a.every((v, i) => v === b[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SERIES = [
|
||||||
|
'--series-1', '--series-2', '--series-3', '--series-4',
|
||||||
|
'--series-5', '--series-6', '--series-7', '--series-8',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const SERIES_FALLBACK = [
|
||||||
|
'#584a9b', '#0e6e66', '#9a5b00', '#a03a5e',
|
||||||
|
'#2f5f8f', '#4a6b2f', '#7a3f7a', '#97442a',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolved series colours for Chart.js datasets, in the same index order as
|
||||||
|
* CHART_COLORS — so a school keeps its colour between the canvas and the DOM
|
||||||
|
* swatch beside it. Re-reads when the OS theme flips.
|
||||||
|
*/
|
||||||
|
export function useSeriesColors(): string[] {
|
||||||
|
const read = () =>
|
||||||
|
typeof window === 'undefined'
|
||||||
|
? SERIES_FALLBACK
|
||||||
|
: SERIES.map((n, i) => {
|
||||||
|
const v = getComputedStyle(document.documentElement).getPropertyValue(n).trim();
|
||||||
|
return v || SERIES_FALLBACK[i];
|
||||||
|
});
|
||||||
|
|
||||||
|
const [colors, setColors] = useState(read);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// See useThemeTokens: skip the commit when nothing changed, so mounting a
|
||||||
|
// chart doesn't cost an extra render.
|
||||||
|
const sync = () => setColors((prev) => (sameValues(prev, read()) ? prev : read()));
|
||||||
|
sync();
|
||||||
|
const mq = window.matchMedia('(prefers-color-scheme: dark)');
|
||||||
|
mq.addEventListener('change', sync);
|
||||||
|
return () => mq.removeEventListener('change', sync);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** rgba() built from a token's hex, for fills that need their own alpha. */
|
||||||
|
export function alpha(name: ThemeToken, a: number): string {
|
||||||
|
const hex = token(name);
|
||||||
|
const m = /^#([0-9a-f]{6})$/i.exec(hex);
|
||||||
|
if (!m) return hex;
|
||||||
|
const n = parseInt(m[1], 16);
|
||||||
|
return `rgba(${(n >> 16) & 255}, ${(n >> 8) & 255}, ${n & 255}, ${a})`;
|
||||||
|
}
|
||||||
+40
-30
@@ -273,17 +273,29 @@ export function debounce<T extends (...args: any[]) => any>(
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Chart color palette (consistent with vanilla JS app)
|
* Series palette for comparing up to eight schools at once.
|
||||||
|
*
|
||||||
|
* These were Chart.js's stock demo colours, which is why the comparison view
|
||||||
|
* never looked like the rest of the site. They now point at the --series-*
|
||||||
|
* tokens, so the palette lives in one place and follows the theme.
|
||||||
|
*
|
||||||
|
* Every step clears WCAG AA on both grounds, so the same value works as a
|
||||||
|
* chart line and as the legend text keyed to it — there is no longer a
|
||||||
|
* separate text ramp to keep in sync.
|
||||||
|
*
|
||||||
|
* These are var() strings: correct anywhere the value lands in the DOM
|
||||||
|
* (inline styles, CSS custom properties). Canvas can't resolve var(), so
|
||||||
|
* Chart.js datasets must use `useSeriesColors()` from lib/theme instead.
|
||||||
*/
|
*/
|
||||||
export const CHART_COLORS = [
|
export const CHART_COLORS = [
|
||||||
'rgb(75, 192, 192)',
|
'var(--series-1)',
|
||||||
'rgb(255, 99, 132)',
|
'var(--series-2)',
|
||||||
'rgb(54, 162, 235)',
|
'var(--series-3)',
|
||||||
'rgb(255, 206, 86)',
|
'var(--series-4)',
|
||||||
'rgb(153, 102, 255)',
|
'var(--series-5)',
|
||||||
'rgb(255, 159, 64)',
|
'var(--series-6)',
|
||||||
'rgb(201, 203, 207)',
|
'var(--series-7)',
|
||||||
'rgb(255, 0, 255)',
|
'var(--series-8)',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -294,44 +306,42 @@ export function getChartColor(index: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Darker counterparts of CHART_COLORS for use as TEXT on the site's light
|
* @deprecated The series palette is now AA on both grounds, so line and text
|
||||||
* backgrounds — the raw series colours fail WCAG AA (e.g. 1.9:1 on cream).
|
* share one value. Kept as an alias so call sites can migrate incrementally.
|
||||||
* 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 = [
|
export const CHART_TEXT_COLORS = CHART_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 {
|
export function getChartTextColor(index: number): string {
|
||||||
return CHART_TEXT_COLORS[index % CHART_TEXT_COLORS.length];
|
return CHART_TEXT_COLORS[index % CHART_TEXT_COLORS.length];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert RGB color to RGBA with opacity
|
* Add opacity to a colour. Accepts `rgb(...)` or `#rrggbb` — the series
|
||||||
|
* palette resolves to hex now that it comes from the token layer, but the
|
||||||
|
* rgb() form is still used by callers passing Chart.js literals.
|
||||||
*/
|
*/
|
||||||
export function rgbToRgba(rgb: string, alpha: number): string {
|
export function rgbToRgba(color: string, alpha: number): string {
|
||||||
return rgb.replace('rgb', 'rgba').replace(')', `, ${alpha})`);
|
const hex = /^#([0-9a-f]{6})$/i.exec(color.trim());
|
||||||
|
if (hex) {
|
||||||
|
const n = parseInt(hex[1], 16);
|
||||||
|
return `rgba(${(n >> 16) & 255}, ${(n >> 8) & 255}, ${n & 255}, ${alpha})`;
|
||||||
|
}
|
||||||
|
return color.replace('rgb', 'rgba').replace(')', `, ${alpha})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get trend color based on direction
|
* Trend direction colour. Teal/amber rather than green/red so the signal
|
||||||
|
* survives red–green colour blindness; `at` is deliberately neutral so a
|
||||||
|
* school sitting on the average doesn't read as a verdict.
|
||||||
*/
|
*/
|
||||||
export function getTrendColor(trend: 'up' | 'down' | 'stable'): string {
|
export function getTrendColor(trend: 'up' | 'down' | 'stable'): string {
|
||||||
switch (trend) {
|
switch (trend) {
|
||||||
case 'up':
|
case 'up':
|
||||||
return '#22c55e'; // green
|
return 'var(--status-above)';
|
||||||
case 'down':
|
case 'down':
|
||||||
return '#ef4444'; // red
|
return 'var(--status-below)';
|
||||||
case 'stable':
|
case 'stable':
|
||||||
return '#6b7280'; // gray
|
return 'var(--status-at)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,15 @@ const nextConfig = {
|
|||||||
// Enable standalone output for Docker
|
// Enable standalone output for Docker
|
||||||
output: 'standalone',
|
output: 'standalone',
|
||||||
|
|
||||||
|
// app/opengraph-image.tsx reads the Schibsted Grotesk files off disk at
|
||||||
|
// request time (Satori needs a font buffer; it has no system fallback).
|
||||||
|
// File tracing currently picks these up on its own, but that relies on the
|
||||||
|
// tracer resolving a runtime join() — declare them so a Next upgrade can't
|
||||||
|
// silently drop them and turn every link preview into a 500.
|
||||||
|
outputFileTracingIncludes: {
|
||||||
|
'/opengraph-image': ['./assets/**'],
|
||||||
|
},
|
||||||
|
|
||||||
// The /api/* and /sitemap.xml proxies to the FastAPI backend are route
|
// The /api/* and /sitemap.xml proxies to the FastAPI backend are route
|
||||||
// handlers (app/api/[...path]/route.ts, app/sitemap.xml/route.ts) rather
|
// handlers (app/api/[...path]/route.ts, app/sitemap.xml/route.ts) rather
|
||||||
// than rewrites, so the backend host is read from FASTAPI_URL at runtime
|
// than rewrites, so the backend host is read from FASTAPI_URL at runtime
|
||||||
@@ -72,7 +81,9 @@ const nextConfig = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/favicon.svg',
|
// favicon.svg was replaced by app/icon.svg (the mark now has one
|
||||||
|
// source in components/Logo.tsx); this rule was caching a 404.
|
||||||
|
source: '/icon.svg',
|
||||||
headers: [
|
headers: [
|
||||||
{
|
{
|
||||||
key: 'Cache-Control',
|
key: 'Cache-Control',
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
<svg viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<rect width="40" height="40" rx="8" fill="#1a1612"/>
|
|
||||||
<circle cx="20" cy="20" r="14" stroke="#e07256" stroke-width="2"/>
|
|
||||||
<path d="M20 8L20 32M12 14L28 14M10 20L30 20M12 26L28 26" stroke="#e07256" stroke-width="1.5" stroke-linecap="round"/>
|
|
||||||
<circle cx="20" cy="20" r="3" fill="#e07256"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 374 B |
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
@@ -4,13 +4,31 @@
|
|||||||
"description": "Compare primary and secondary school performance across England",
|
"description": "Compare primary and secondary school performance across England",
|
||||||
"start_url": "/",
|
"start_url": "/",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"background_color": "#faf7f2",
|
"background_color": "#f2f1ed",
|
||||||
"theme_color": "#faf7f2",
|
"theme_color": "#f2f1ed",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "/favicon.svg",
|
"src": "/icon.svg",
|
||||||
"sizes": "any",
|
"sizes": "any",
|
||||||
"type": "image/svg+xml"
|
"type": "image/svg+xml"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icon-192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icon-512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icon-maskable-512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user