@font-face {
  font-family: "Plus Jakarta Sans Variable";
  font-style: normal;
  font-display: swap;
  font-weight: 200 800;
  src: url("../fonts/plus-jakarta-sans-latin-wght-normal.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Plus Jakarta Sans Variable";
  font-style: normal;
  font-display: swap;
  font-weight: 200 800;
  src: url("../fonts/plus-jakarta-sans-latin-ext-wght-normal.woff2") format("woff2-variations");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Plus Jakarta Sans Variable";
  font-style: italic;
  font-display: swap;
  font-weight: 200 800;
  src: url("../fonts/plus-jakarta-sans-latin-wght-italic.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Plus Jakarta Sans Variable";
  font-style: italic;
  font-display: swap;
  font-weight: 200 800;
  src: url("../fonts/plus-jakarta-sans-latin-ext-wght-italic.woff2") format("woff2-variations");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Reset */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; }
body { min-height: 100svh; }
img, picture, svg, video { display: block; max-width: 100%; }
input, button, textarea, select { font: inherit; color: inherit; }
p, h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }
ul[role="list"], ol[role="list"] { list-style: none; padding: 0; }
a:not([class]) { color: inherit; }

/* Typography */
html { font-size: 100%; }
body {
  font-family: "Plus Jakarta Sans Variable", "Segoe UI", system-ui, -apple-system, sans-serif;
  font-weight: 400;
  font-size: var(--step-0);
  line-height: 1.65;
  color: var(--ink);
  background: var(--page-ground);
}
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
  color: var(--bms-blue-700);
  font-weight: 800;
  line-height: 1.1;
}
h3, h4, h5, h6, .h3, .h4, .h5, .h6 { font-weight: 600; }
h1, .h1 { font-size: var(--step-4); letter-spacing: -0.02em; }
h2, .h2 { font-size: var(--step-3); letter-spacing: -0.02em; line-height: 1.15; }
h3, .h3 { font-size: var(--step-2); line-height: 1.15; }
h4, .h4 { font-size: var(--step-1); line-height: 1.15; }
h5, h6, .h5, .h6 { font-size: var(--step-0); line-height: 1.15; }
b, strong { font-weight: 600; }

a { color: var(--bms-blue-700); }
p a, li a, dd a { text-decoration: underline; text-underline-offset: 0.15em; }

/* Focus — never outline: none */
:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius);
}

/* Skip link
   Hidden by clipping, NOT by translating it off the top edge. An element
   parked above the document origin gets exposed by the overscroll bounce on
   mobile, which flashed this link top-left on a fast scroll up. Clipped to
   nothing, there is no off-screen box to reveal. */
.skip-link {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  background: var(--bms-blue-700);
  color: var(--paper);
  font-weight: 600;
  text-decoration: none;
  z-index: 1000;
  border-radius: 0 0 var(--radius) 0;
}
/* fixed so it stays put once focused, wherever the page happens to be */
.skip-link:focus {
  position: fixed;
  width: auto;
  height: auto;
  padding: var(--sp-3) var(--sp-4);
  overflow: visible;
  clip-path: none;
}

/* Screen-reader-only text */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Scroll reveal — see assets/js/reveal.js.
   Gated on .js so that with scripting off nothing is ever hidden. */
.js .reveal {
  opacity: 0;
  transform: translateY(var(--reveal-rise));
}
/* Transitions are switched on only after the hidden state has been applied
   and flushed. Otherwise adding .reveal animates each element OUT from
   visible to hidden first — a visible flash before it fades back in. */
.js.reveal-ready .reveal {
  transition:
    opacity var(--t-reveal) var(--ease-reveal),
    transform var(--t-reveal) var(--ease-reveal);
  transition-delay: calc(var(--reveal-offset) + var(--reveal-i, 0) * var(--reveal-stagger));
}
.js .reveal.is-revealed {
  opacity: 1;
  transform: none;
}

/* Intro curtain — partials/intro-curtain.njk. A white sheet carrying the
   school mark, wiping upward to open the page.

   Gated on .has-intro, which the head script adds only when scripting is on
   AND motion is wanted. So the two failure modes both fail safe: no script,
   no curtain; reduced motion, no curtain. The lift is a CSS animation rather
   than a JS class swap, which means nothing can leave it covering the page.

   z-index sits below the skip link's 1000 on purpose. A visitor who tabs
   straight away gets the skip link drawn over the sheet rather than trapped
   behind it, and pointer-events are off throughout, so the page underneath is
   live the whole time even though it cannot yet be seen. */
.intro-curtain { display: none; }
.has-intro .intro-curtain {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: grid;
  place-items: center;
  background: var(--paper);
  pointer-events: none;
  animation: intro-lift var(--t-intro-lift) var(--ease-intro) var(--t-intro-hold) both;
}
@keyframes intro-lift {
  from { clip-path: inset(0 0 0 0); }
  to   { clip-path: inset(0 0 100% 0); visibility: hidden; }
}
/* Sized by height, not width: the mark is a tall, narrow shape, and driving
   it from the axis it actually fills means a short viewport can never crop it
   and the aspect ratio can never be squashed. */
.has-intro .intro-mark {
  height: min(41vh, 331px);
  width: auto;
  animation: intro-mark var(--t-intro-mark) var(--ease) 60ms both;
}
@keyframes intro-mark {
  from { clip-path: inset(100% 0 0 0); transform: translateY(24px); }
  to   { clip-path: inset(0 0 0 0);    transform: none; }
}
/* Belt and braces: the sheet is dismissed outright the moment anyone reaches
   for the keyboard, rather than making them wait out an animation. */
.intro-skipped .intro-curtain { display: none; }

/* Prose */
.prose {
  max-width: var(--measure);
  text-align: left;
}
.prose > * + * { margin-top: var(--sp-4); }
.prose h2, .prose h3, .prose h4 { margin-top: var(--sp-8); }

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-3) var(--sp-6);
  border-radius: var(--radius);
  font-weight: 600;
  font-size: var(--step--1);
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease), border-color 0.15s var(--ease);
}
.btn-primary {
  background: var(--bms-blue-700);
  color: var(--paper);
}
.btn-primary:hover { background: var(--bms-blue-900); }
.btn-secondary {
  background: transparent;
  color: var(--bms-blue-700);
  border-color: var(--bms-blue-700);
}
.btn-secondary:hover { background: var(--bms-blue-100); }

/* PDF / download links */
.pdf-link {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--ink-muted);
  border-radius: var(--radius);
  color: var(--ink);
  text-decoration: none;
  font-weight: 600;
}
.pdf-link:hover { border-color: var(--bms-blue-700); color: var(--bms-blue-700); }
.pdf-link svg { flex-shrink: 0; }
.pdf-link .format {
  color: var(--ink-muted);
  font-weight: 400;
  font-size: var(--step--1);
}

/* Placeholder blocks — "no stock photos, no generated images" */
.placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  background: var(--paper-alt);
  border: 1px solid var(--ink-muted);
  color: var(--ink-muted);
  font-size: var(--step--1);
  padding: var(--sp-4);
  min-height: 12rem;
}

/* Footer — on every page */
.site-footer {
  background: var(--bms-blue-900);
  color: var(--paper);
  /* The default ring cannot be seen on this ground — see tokens.css. */
  --focus-ring: var(--paper);
  /* Tuned to land the footer at twice its previous 248px */
  padding: calc(var(--sp-24) + var(--sp-1)) var(--sp-6);
  text-align: center;
  /* Whether the grid below goes three across is decided by the footer's own
     width, not the window's. See the @container rule. */
  container: site-footer / inline-size;
}
.site-footer a { color: var(--paper); }
/* One column until the footer is wide enough for three (the @container rule
   below). Source order carries the stack: quote, social, contact, school,
   hours, address. A browser too old for container queries keeps the stack,
   which reads properly at any width. */
.site-footer-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-12);
  max-width: 72rem;
  margin: 0 auto;
}
/* Stacked order: quote, social, contact, address, hours, then the school
   name and copyright last. Source order already gives address before hours,
   so only the school block has to move — everything else stays at 0 and
   holds its source order.
   NOTE: this reorders visually only, so a screen reader still reaches the
   school name before address and hours. It carries no links, so tab order is
   unaffected. */
.site-footer-group--school { order: 1; }
/* Full-width hairline between the two rows. Its own grid row, so the --sp-16
   row gap falls on both sides of it. Drawn only three across: in one column
   it would cut the stack arbitrarily. */
.site-footer-rule {
  display: none;
  grid-column: 1 / -1;
  height: 1px;
  background: var(--hairline-on-dark);
}
/* Both vertical hairlines hang off the MIDDLE column, one either side, so the
   pair can be pulled inward together — they travel in opposite directions, and
   splitting them across two columns would need two mirrored rules.
   Resting position is the centre of the --sp-8 column gap; --rule-inset then
   draws them 20% of the way toward the middle column's own centre. The
   percentage resolves against this cell's width, so it holds at any breakpoint.
   Cells stretch to the tallest in their row (the grid's default), so the lines
   run the full row height and stay in register across both rows.
   No content until three across (below): in one column there is nothing to
   divide, and the lines would land against the text edge. */
.site-footer-group--divided {
  position: relative;
  --rule-inset: calc((100% + var(--sp-8)) * 0.2 / 2);
}
.site-footer-group--divided::before,
.site-footer-group--divided::after {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--hairline-on-dark);
}
.site-footer-group--divided::before { left: calc(var(--sp-8) / -2 + var(--rule-inset)); }
.site-footer-group--divided::after { right: calc(var(--sp-8) / -2 + var(--rule-inset)); }
/* Three fixed columns in two rows, per footer-layout.png. Not auto-fit: the
   rows have to stay in register (address / contact / quote above social /
   hours / school), which a reflowing track count can't guarantee.

   Only once the footer can hold them. The widest line is the email address,
   and it needs a middle column of about 289px to clear the two rules drawn
   inside it: 58.25rem is three of those plus the two gaps. A window width
   could not say this, because the rail takes 101px beside the footer on a
   computer and nothing on a phone or tablet, so the same footer width comes
   at 980px in one and 1080px in the other. At 768px, where this used to
   switch, the address ran across its rule (Sean, 2026-09-21), and it touched
   it on a computer up to about 1080px. */
@container site-footer (min-width: 58.25rem) {
  .site-footer-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--sp-16) var(--sp-8);
  }
  /* Placed rather than left to source order (Sean, 2026-09-19): the Ofsted
     quote and the school name with its copyright share the right-hand column;
     Address and Contact, then Social and Hours, take the two on the left. The
     middle column is Contact above Hours, which is why those two carry the
     vertical rules. The markup keeps its order, so the stacked footer and the
     reading order are unchanged. */
  .site-footer-group--address { grid-column: 1; grid-row: 1; }
  .site-footer-group--contact { grid-column: 2; grid-row: 1; }
  .site-footer-quote { grid-column: 3; grid-row: 1; }
  .site-footer-rule { display: block; grid-row: 2; }
  .site-footer-group--social { grid-column: 1; grid-row: 3; }
  .site-footer-group--hours { grid-column: 2; grid-row: 3; }
  .site-footer-group--school { grid-column: 3; grid-row: 3; }
  .site-footer-group--divided::before,
  .site-footer-group--divided::after { content: ""; }
}
/* Set at regular weight and left to carry on size alone — at --step-1 it
   still leads the footer without shouting, which suits a quotation. */
.site-footer-quote {
  margin: 0;
  font-size: var(--step-1);
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: -0.01em;
}
.site-footer-quote-source {
  font-weight: 400;
  white-space: nowrap; /* keeps "– Ofsted, 2024" from breaking across lines */
}
.site-footer-quote cite { font-style: inherit; }
.site-footer-heading {
  font-weight: 800;
  margin-bottom: var(--sp-2);
}
/* Airier than body copy — the mockup sets these short stacked lines well
   apart, and it keeps the two-line and three-line columns reading evenly. */
.site-footer-group p { line-height: 1.9; }
.site-footer-group .site-footer-heading { line-height: 1.4; }
.site-footer-social {
  display: flex;
  justify-content: center;
  gap: var(--sp-3);
}
.site-footer-social a {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
}
.site-footer-icon { width: 22px; height: 22px; }

/* Footer zone — the white run-up, then the tinted awards band, then the
   footer. The run-up is painted here rather than left to the preceding
   section's padding: that made the gap the sum of two values and only correct
   on pages that had been tuned for it. Sections no longer need to know they
   come last. */
.footer-zone {
  background: var(--paper);
  padding-top: var(--footer-lead);
}

/* Tinted so the band reads as the start of the footer rather than as more of
   the white section above it. This only works because the logo strips carry
   real transparency; on flat-white artwork it would draw a white rectangle
   around them.
   No hairline: the tint edge does the dividing on its own, and the padding is
   even above and below the logos.
   NOTE: still one flat image per breakpoint, so it can't reflow. Separate
   files in a wrapping row would behave better and give each award its own alt
   text; worth doing when the individual logos are available. */
.awards {
  /* --bms-sky, the same accent the page top is bordered in, so the band
     bookends the page. It sat on --bms-blue-100 while the run-up above it was
     white: that tone is 1.02:1 off --page-ground, so once interior pages lost
     the run-up the band stopped reading as a band at all. This is 1.21:1 off
     the ground and 1.34:1 off white, so it holds either way. */
  background: var(--bms-sky);
  padding: var(--sp-12) var(--sp-6);
}
.awards-media {
  max-width: 72rem;
  margin: 0 auto;
}
.awards-img {
  width: 100%;
  height: auto;
}

/* 40% off each end. The stacked single column is already tall, so the deep
   desktop inset reads as dead space here — this brings the footer's own
   margins closer to the awards band's. A window rule, because a container
   query cannot restyle the container itself: 979px is where the footer, with
   no rail beside it, stops fitting three columns (see the @container rule). */
@media (max-width: 979px) {
  .site-footer {
    padding-top: calc((var(--sp-24) + var(--sp-1)) * 0.6);
    padding-bottom: calc((var(--sp-24) + var(--sp-1)) * 0.6);
  }
}
