.shell-content {
  margin-left: var(--rail-w-collapsed);
}

/* Interior pages arrive slowly. Better than twice the drawer's duration, with
   the stagger opened out to match, so the page top and then each section rise
   in one unhurried cascade rather than snapping into place. The rise is only a
   little longer than the default — distance plus duration reads as sluggish,
   where duration alone reads as considered. */
body:not(.is-landing) {
  --t-reveal: 1200ms;
  --reveal-stagger: 100ms;
  --reveal-offset: 80ms;
  --reveal-rise: 26px;
}

/* The title panel comes in a beat behind everything else, so the photograph is
   seen whole before the navy covers its corner. Its own contents follow it,
   late enough that their cascade still reads against it rather than under it.
   The rise inside is shortened because the panel is already moving and the two
   transforms compound — 26px on top of 26px reads as a lurch.
   Both selectors carry the body prefix only to outweigh the rule above: the
   token is set there, and .phero-panel on its own would lose to it. */
body:not(.is-landing) .phero-panel { --reveal-offset: 400ms; }
body:not(.is-landing) .phero-panel .reveal {
  --reveal-offset: 620ms;
  --reveal-rise: 10px;
}

/* Everything on the first screenful reveals together on load, so its order has
   to be composed rather than left to whichever element happens to be listed
   first: the page top introduces the page, and the body follows it in. Only
   what is on screen at load waits — anything further down is revealed by
   scrolling to it, where a held-back start reads as lag rather than as
   sequence. The sibling combinator keeps this to pages that actually have a
   page top; a page without one has nothing to wait for. */
body:not(.is-landing) .phero ~ .psheet .is-initial { --reveal-offset: 900ms; }

/* Same column as the landing page's Instagram section: 72rem, centred, with
   a --sp-6 inset. Centred matters — left-aligned, every pixel of a wide
   monitor piles up on the right and the page reads as though it slid over. */
main#main {
  padding: var(--sp-16) var(--sp-6);
  /* 72rem plus the inset, so the CONTENT box is 72rem — the same measurement
     the landing sections cap at, which puts both left edges on the same line
     at every width instead of 6px apart. */
  max-width: calc(72rem + var(--sp-6) * 2);
  margin-inline: auto;
}

@media (max-width: 1023px), (hover: none) and (pointer: coarse) and (max-width: 1400px) {
  .shell-content {
    margin-left: 0;
    margin-top: var(--topbar-h);
  }
}

/* On a phone or tablet, the first heading of an ordinary page sits 20px
   (1.25rem) closer to the photograph above it (Sean, 2026-09-19). Only where
   the body opens straight onto a section heading, and only on general pages:
   a page with its own stylesheet, or one that opens on a standfirst, keeps
   the full --sp-16. */
@media (max-width: 1023px), (hover: none) and (pointer: coarse) and (max-width: 1400px) {
  .psheet--general main#main:has(> .page-section:first-child > .page-section-heading:first-child) {
    padding-top: calc(var(--sp-16) - 1.25rem);
  }
}

/* A page that opens on a single document link rather than a heading —
   Lettings, whose policy carries the pricing the page refers to. On a phone
   the space above and below that link is half the usual (Sean, 2026-09-19):
   96px to 48px above, 64px to 32px below. */
@media (max-width: 1023px), (hover: none) and (pointer: coarse) and (max-width: 1400px) {
  main#main:has(> .page-section--lead-doc:first-child) { padding-top: var(--sp-8); }
  .page-section--lead-doc .doclist { margin-block: var(--sp-4); }
  main#main > .page-section--lead-doc + .page-section { margin-top: var(--sp-8); }
}

/* main is the prose column; the hero sits outside it and runs edge to edge */
main#main > .page-section:first-child { margin-top: 0; }

/* No trailing space under the last section on an interior page: the content
   ends where the footer's white run-up begins, so the tinted ground stops on
   the last rule rather than a screen-width of it hanging below. The run-up
   itself is the breathing room — it belongs to the footer, which is why it
   isn't doubled here. */
.psheet main#main { padding-bottom: 0; }

/* ...and the run-up above the awards band is painted in the page's own colour
   rather than white. It keeps its full --footer-lead: the objection was to a
   slab of white on a page whose ground is already tinted, not to the distance,
   which is unchanged. The landing page keeps the white version — its content
   ends on white, so there is nothing there for a tinted run-up to continue. */
body:not(.is-landing) .footer-zone { background: none; }

/* ── Page top ───────────────────────────────────────── */
/* Narrow: photograph, then a navy band pulled up over its lower edge carrying
   the breadcrumb and the title. Wide (>=1200px, at the bottom of this file):
   mock-up.png — a white field with a pale sky block in its top-right corner,
   the breadcrumb above the photograph, and the title on a navy panel laid
   across the photograph's lower-left corner. */
.phero {
  position: relative;
  margin-left: 0;
  width: auto;
}
/* 16:9 by default, but never so tall that the title falls off the bottom of
   the window. Where the ratio already fits, nothing is cropped: a phone gets
   the whole 1920x1080 frame. */
.phero-media {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: max(18rem, calc(100svh - 13rem));
  overflow: hidden;
}
/* <picture> is inline by default and has no height of its own, so height:100%
   on the image never resolved: it rendered at its natural ratio, overflowed
   the frame and was clipped at the bottom by overflow:hidden — top-anchored,
   not the centred object-fit crop it appeared to be. */
.phero-media picture {
  display: block;
  width: 100%;
  height: 100%;
}
.phero-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Centred: where the cap crops, it takes evenly from the sky above and the
     tarmac below, leaving the middle of the frame. A photograph whose
     subject stands high sets --hero-y from _data/heroFocus.json, so the crop
     keeps heads in (crop review, 2026-09-19). Only the wide desktop frame
     crops at all; on a phone the photograph is shown whole. */
  object-position: 50% var(--hero-y, 50%);
}
.phero-panel {
  --phero-overlap: clamp(1.5rem, 4vw, 3.5rem);
  position: relative; /* above the photo, which it overlaps */
  margin-top: calc(var(--phero-overlap) * -1);
  padding-block: var(--sp-8) var(--sp-12);
  background: var(--bms-blue-900);
  color: var(--paper);
}
/* Same column as main#main, so the title sits on the same left edge as the
   body copy underneath it rather than on its own line. */
.phero-inner {
  max-width: calc(72rem + var(--sp-6) * 2);
  margin-inline: auto;
  padding-inline: var(--sp-6);
}
.phero-title {
  color: var(--paper);
  font-size: var(--step-4);
  letter-spacing: -0.02em;
  line-height: 1.05;
  text-wrap: balance;
}
/* Names the section this page sits in. Hidden here, where the breadcrumb
   immediately above the title already says the same thing; the wide layout
   moves the breadcrumb away from the panel and turns this on. */
.phero-eyebrow { display: none; }
/* Set below the title with a hairline between them on wide screens. Kept at
   body weight — it is a standfirst, not a second heading. */
.phero-standfirst {
  margin-top: var(--sp-4);
  max-width: 46ch;
  text-wrap: pretty;
  color: var(--paper);
  font-size: var(--step-0);
  line-height: 1.55;
}
/* Narrow: sits directly on top of the title's band, so the two read as one
   block. Wide overrides this into a row above the photograph. */
.phero-crumbbar {
  position: relative;
  background: var(--bms-blue-900);
  color: var(--paper);
  /* Breadcrumb links on a ground the default ring cannot be seen against —
     see tokens.css. */
  --focus-ring: var(--paper);
  padding-block: var(--sp-6) 0;
}
.phero-crumbs { margin-bottom: 0; }
.phero-crumbs ol {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--step--1);
  color: var(--paper);
}
.phero-crumbs li + li::before {
  content: "/";
  margin-right: var(--sp-2);
  opacity: 0.6;
}
.phero-crumbs a { color: var(--paper); }

/* ── Prose column + section card ─────────────────────── */
/* One column until the page is wide enough to carry two. The card's links are
   all in the drawer already, so nothing is lost by leaving it out below that
   — it would only push the content of the page down a screen. */
.secnav { display: none; }
/* No panel: a hairline, a label and a list, sitting straight on the page
   ground — menu-example.png. Nothing here has a fill or a box, so it reads as
   an index beside the page rather than as a second piece of furniture. */
.secnav {
  border-left: 1px solid var(--hairline);
  padding-left: var(--sp-6);
}
/* A page's own line in this column, where it has no sibling list to show.
   Set from frontmatter; see partials/section-nav.njk. */
.secnav-note {
  margin: 0;
  font-size: var(--step-0);
  font-weight: 600;
  line-height: 1.5;
  color: var(--ink);
}
/* The rule down the left belongs to an index: it is what separates a list of
   links from the page beside it. A single line of prose is not an index, so
   where the column carries only a note there is no rule and nothing to inset
   it from. */
.secnav--note-only {
  border-left: 0;
  padding-left: 0;
}
/* Drops the note to the top of the embed beside it, rather than the top of
   the column. The 7.5rem is the heading, its rule, the date line and the
   embed's own top margin — measured at 121px, not derivable from tokens
   because most of it is the heading's font metrics. If what sits above the
   embed on that page changes, this has to be measured again. */
.secnav-note--embed { margin-top: 7.5rem; }
.secnav-note + .secnav-heading { margin-top: var(--sp-8); }

.secnav-heading {
  margin-bottom: var(--sp-2);
  color: var(--ink);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.2;
}
/* A page can sit in two menus at once, so the card can carry more than one
   list. The gap is what separates them — they are groups, not a run-on. */
.secnav-list + .secnav-heading { margin-top: var(--sp-8); }
.secnav-link {
  display: flex;
  align-items: center;
  /* No divider and no fill, so the row's only job is to be a large enough
     target. 44px is the house minimum; the type sits centred in it. */
  min-height: 44px;
  padding-block: var(--sp-2);
  color: var(--bms-blue-700);
  font-size: var(--step--1);
  line-height: 1.35;
  text-decoration: none;
  transition: color 0.15s var(--ease);
}
.secnav-link:hover {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
/* Weight and colour carry the current page, with a short length of gold laid
   over the hairline beside it — 3.3:1 on the page ground, and never the only
   marker, since aria-current names it too. */
.secnav-link[aria-current="page"] {
  color: var(--ink);
  font-weight: 600;
}
/* Subject and therapy pages are not in nav.json, so the sibling list above has
   no link to the hub they were reached from. A hairline sets it apart from the
   siblings: it goes up a level rather than across. */
.secnav-back {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 44px;
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--hairline);
  color: var(--bms-blue-700);
  font-size: var(--step--1);
  font-weight: 600;
  line-height: 1.35;
  text-decoration: none;
  transition: color 0.15s var(--ease);
}
.secnav-back:hover {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
.secnav-back-icon {
  flex: none;
  width: 1.1em;
  height: 1.1em;
}
.secnav-item { position: relative; }
.secnav-item:has(> [aria-current="page"])::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--sp-6) * -1 - 1px);
  width: 2px;
  background: var(--gold-ink);
}

/* ── Page sections ─────────────────────────────────────────────── */
.page-section + .page-section { margin-top: var(--sp-16); }
.page-section-heading {
  font-size: var(--step-2);
  margin-bottom: var(--sp-6);
}
/* The short gold mark from the mock-up, used here as the section's opening
   rather than as a divider between sections. Decorative, so it stays out of
   the accessible name. */
.page-section-heading::before {
  content: "";
  display: block;
  width: 2.5rem;
  height: 2px;
  margin-bottom: var(--sp-4);
  background: var(--gold-ink);
}

/* ── Portrait ─────────────────────────────────── */
/* A headshot with its caption. Square, capped, left-aligned with the column —
   the caption names the person, so the image itself carries alt="". */
.portrait {
  margin: 0 0 var(--sp-8);
  max-width: 15rem;
}
.portrait-img {
  width: 100%;
  height: auto;
  border: 1px solid var(--hairline);
}
.portrait-caption {
  margin-top: var(--sp-3);
  color: var(--ink-muted);
  font-size: var(--step--1);
  line-height: 1.4;
}
/* A landscape photograph belonging to the section it sits in, rather than a
   head-and-shoulders portrait beside the text. */
.portrait--wide { max-width: 100%; }

/* ── Lyric ────────────────────── */
/* Verse, set as verse: every line break in the school band's song is the
   school's, so the lines are not reflowed into paragraphs. A gold rule down
   the left rather than quotation marks, which would imply someone is being
   quoted rather than sung. */
.lyric {
  margin: var(--sp-8) 0;
  padding-left: var(--sp-6);
  border-left: 2px solid var(--gold-ink);
  color: var(--ink);
  max-width: var(--measure);
}
.lyric p {
  margin: 0 0 var(--sp-4);
  line-height: 1.7;
}
.lyric em,
.lyric i { font-style: normal; }


/* ── Award grid ───────────────────────────────── */
/* Each award on its own white tile. The logos arrive in mixed formats — half
   are JPEGs with baked-in white grounds — so laying them straight on the page
   would show a row of rectangles in slightly different whites. A tile makes
   that consistent and gives every logo the same footprint whatever its shape.
   Hairline rather than a shadow. */
.awardgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: var(--sp-4);
}
.awardgrid-item { display: flex; }
.awardgrid-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  padding: var(--sp-6) var(--sp-4) var(--sp-4);
  background: var(--paper);
  border: 1px solid var(--hairline);
  color: var(--ink);
  text-align: center;
  text-decoration: none;
  transition: border-color 0.2s var(--ease), transform 0.2s var(--ease);
}
.awardgrid-link:hover {
  border-color: var(--bms-blue-500);
  transform: translateY(-2px);
}
/* Fixed box, contained image: the logos range from a wide strip to a square
   badge, and without it the rows would step. */
.awardgrid-media {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 6.5rem;
}
.awardgrid-media img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
}
.awardgrid-name {
  font-size: var(--step--1);
  font-weight: 600;
  line-height: 1.3;
  text-wrap: balance;
}
.awardgrid-since {
  margin-top: auto;
  color: var(--ink-muted);
  font-size: var(--step--1);
}

/* ── Subject index ─────────────────── */
/* The way into the eighteen subject pages. Deliberately not a card grid: a
   ruled index, the same device the left rail uses, so the page reads as a
   contents list rather than eighteen boxes competing for attention. The rule
   above each subject is the affordance — on hover and focus a gold one draws
   across it, left to right, and the arrow steps forward. Order comes from
   _data/subjects.json and is the school's, not alphabetical. */
.subjectgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  column-gap: var(--sp-8);
  row-gap: var(--sp-2);
  margin: var(--sp-8) 0 0;
  padding: 0;
  list-style: none;
}
.subjectgrid-item { display: flex; }
.subjectgrid-link {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  min-height: 3.25rem;              /* keeps the target above 44px */
  padding: var(--sp-4) 0 var(--sp-5);
  border-top: 1px solid var(--hairline);
  color: var(--ink);
  text-decoration: none;
}
/* Sits on top of the hairline rather than replacing it, so nothing shifts by a
   pixel when it appears. */
.subjectgrid-link::before {
  content: "";
  position: absolute;
  inset-block-start: -1px;
  inset-inline-start: 0;
  width: 100%;
  height: 2px;
  background: var(--gold-ink);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.34s var(--ease);
}
.subjectgrid-link:hover::before,
.subjectgrid-link:focus-visible::before { transform: scaleX(1); }
.subjectgrid-name {
  font-weight: 600;
  line-height: 1.3;
  text-wrap: balance;
}
.subjectgrid-arrow {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  margin-inline-start: auto;
  color: var(--ink-muted);
  transition: transform 0.34s var(--ease), color 0.2s var(--ease);
}
.subjectgrid-link:hover .subjectgrid-arrow,
.subjectgrid-link:focus-visible .subjectgrid-arrow {
  color: var(--gold-ink);
  transform: translateX(4px);
}
.subjectgrid-link:hover .subjectgrid-name { color: var(--bms-blue-700); }

/* ── Photo grid ─────────────────── */
/* A row of photographs that belong together — the Careers page opens with
   four. No frames or shadows: they sit on the page ground with a hairline, the
   same treatment the award tiles get. */
.photogrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--sp-6);
  margin: 0 0 var(--sp-12);
  padding: 0;
  list-style: none;
}
/* Room above the row when it follows something — butted straight against the
   end of a prose column it read as part of the paragraph above it. Not when it
   opens the page: the Careers pages lead with one, and main's own padding is
   the space there. */
.photogrid:not(:first-child) { margin-top: var(--sp-16); }
.photogrid img {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border: 1px solid var(--hairline);
}

/* ── Data table ─────────────────── */
/* Ruled rather than boxed. On a phone three columns cannot both fit and stay
   legible, so the table keeps a minimum width and scrolls inside its own box
   rather than either wrapping to shreds or pushing the page sideways. The
   container is focusable because a region that scrolls has to be reachable
   without a mouse. */
.datatable-scroll {
  overflow-x: auto;
  margin: var(--sp-8) 0;
}
.datatable-scroll:focus-visible {
  outline: 2px solid var(--bms-blue-700);
  outline-offset: 2px;
}
.datatable {
  width: 100%;
  min-width: 34rem;
  border-collapse: collapse;
  font-size: var(--step--1);
  text-align: left;
}
/* Two tables stacked in one section have to line up: on Times of the School
   Day the end-of-day time belongs under Finish, not under Start. Auto layout
   sizes each table to its own content and they drift apart, so these share
   one fixed set of columns. The end-of-day table spans its label across the
   first two, which is what puts its value in the third. */
.datatable--aligned { table-layout: fixed; }
.datatable--aligned col:first-child { width: 50%; }
.datatable--aligned col + col { width: 25%; }
/* --fit: a table short enough to hold on a phone without scrolling (Sean,
   2026-09-19 — Times of the School Day, then Term Dates). No minimum width,
   and on a phone the row names wrap inside their column instead of forcing
   the table wider. Tables with longer content keep the scrolling box. */
.datatable--fit { min-width: 0; }
@media (max-width: 699px) {
  /* Doubled class: the base .datatable rules come later in this file at the
     same specificity and would otherwise win. */
  .datatable.datatable--fit tbody th { white-space: normal; }
  .datatable.datatable--fit th,
  .datatable.datatable--fit td { padding-right: var(--sp-3); }
  /* Two-column tables (Term Dates) split evenly, so each term's dates start
     their second column at the same point as the term above. The aligned
     tables already carry their own columns. */
  .datatable--fit:not(.datatable--aligned) { table-layout: fixed; }
}

.datatable th,
.datatable td {
  padding: var(--sp-3) var(--sp-4) var(--sp-3) 0;
  border-bottom: 1px solid var(--hairline);
  vertical-align: top;
}
.datatable thead th {
  border-bottom-color: var(--ink);
  font-weight: 600;
  white-space: nowrap;
}
.datatable tbody th {
  color: var(--bms-blue-700);
  font-weight: 600;
  white-space: nowrap;
}

/* ── Tier figure ───────────────── */
/* Stands in for the pyramid diagram on the Speech and Language page. Reads
   base upwards, widest provision first, which is the order the prose beneath
   explains them in. The rule steps in at each tier so the narrowing is visible
   without being a picture of words. */
.tierfig {
  margin: var(--sp-8) 0;
  max-width: var(--measure);
}
.tierfig-list {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: tier;
}
.tierfig-list li {
  padding: var(--sp-3) 0 var(--sp-3) var(--sp-4);
  border-left: 2px solid var(--gold-ink);
  border-bottom: 1px solid var(--hairline);
}
.tierfig-list li:nth-child(2) { margin-left: var(--sp-6); }
.tierfig-list li:nth-child(3) { margin-left: var(--sp-12); }
.tierfig-list li:last-child { border-bottom: 0; }

/* ── Staff grid ────────────────── */
/* Leadership, with photographs. The portraits arrived between 168 and 200px
   wide, so the tiles stay small — showing them larger would only show the
   compression. Square crops, hairline, no card. */
.staffgrid {
  display: grid;
  /* Never more than four across: a column is at least a quarter of the row
     once the row is wide enough to hold four, so auto-fill cannot place a
     fifth. Below that the 9rem floor wins and fewer are placed, which is what
     keeps it working down to a phone. */
  grid-template-columns: repeat(
    auto-fill,
    minmax(max(9rem, (100% - 3 * var(--sp-4)) / 4), 1fr)
  );
  gap: var(--sp-6) var(--sp-4);
  margin: var(--sp-8) 0 0;
  padding: 0;
  list-style: none;
}
.staffgrid-item { display: flex; flex-direction: column; }
.staffgrid-photo {
  width: 100%;
  height: auto;
  /* A standing rectangle, not a box: the portraits carry a tenth of their
     width again above and below. The files are cut to the same 5:6 by
     tools/build-staff.py, so object-fit has nothing left to crop. */
  aspect-ratio: 5 / 6;
  object-fit: cover;
  border: 1px solid var(--hairline);
  margin-bottom: var(--sp-3);
}
.staffgrid-name { font-weight: 600; line-height: 1.3; }
.staffgrid-role {
  margin-top: var(--sp-1);
  color: var(--ink-muted);
  font-size: var(--step--1);
  line-height: 1.35;
}

/* ── The families update reading — /news/ ──────────────
   A native <audio>, not a third party's player: the file is ours, served from
   /assets/audio/. preload="none" means nothing is fetched until someone
   presses play, so a visitor who only wants to read the update pays nothing
   for the recording, and there is no autoplay to have to stop. */
.newsaudio {
  margin: var(--sp-6) 0 0;
  max-width: var(--measure);
}
.newsaudio-player {
  display: block;
  width: 100%;
  /* The control bar is the browser's own; this is only the room it sits in. */
  min-height: 44px;
}
.newsaudio-caption {
  margin-top: var(--sp-3);
  font-size: var(--step--1);
  color: var(--ink-muted);
}
/* ── Third-party embeds in the phone layout ───────────
   A page of A4 cannot be read in a phone-width frame, and Google's viewer
   inside it cannot either — so a phone or a tablet (assets/js/layout.js) is
   not offered the embed at all. It gets a link to the same thing instead: /news/ the update and a line
   saying where the recording is, /ks4-transition-support/ the recording, and
   /contact-us/ the "Find us on a map" link that already stood above the map.
   That also settles a layout bug these frames shared: each set a min-height
   which, through its aspect-ratio, became a MINIMUM WIDTH wider than a phone
   column (21rem x 4/3 = 448px; 15rem x 4/3 = 320px) and pushed the page
   sideways. Not offering the frame at all removes the overflow with it.
   The iframe carries no src until assets/js/wide-embed.js attaches one, so
   this is not merely hidden: on a phone Google is never contacted.
   Mobile first, so with no CSS at all everything is present and nothing is
   lost. The .js prefix on the desktop rules is what keeps the link standing
   on a desktop where the script never ran. */
[data-wide-embed] { display: none; }
.newslisten { display: none; }
.newslink,
.pageembed-link {
  margin: var(--sp-6) 0 0;
  font-weight: 600;
}
.newslisten-note {
  margin: 0;
  font-weight: 600;
  max-width: var(--measure);
}
@media (min-width: 1024px) and (hover: hover), (min-width: 1024px) and (pointer: fine), (min-width: 1024px) and (pointer: none), (min-width: 1401px) {
  .js [data-wide-embed] { display: block; }
  .js .newslink,
  .js .pageembed-link { display: none; }
  /* Not gated on .js: a native <audio> needs no script to work. */
  .newslisten { display: block; }
  .newslisten-note { display: none; }
}
.newslisten-intro { margin: 0 0 var(--sp-6); max-width: var(--measure); }

/* The date the update belongs to, under its heading. */
.newsdate {
  margin: calc(var(--sp-6) * -1) 0 var(--sp-6);
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--bms-blue-700);
}

/* ── Name list ─────────────────── */
/* Thirty-six names and nothing else. In columns rather than one long
   stack, so the section can be taken in at a glance. */
.namelist {
  margin: var(--sp-6) 0 0;
  padding: 0;
  list-style: none;
  columns: 3 11rem;
  column-gap: var(--sp-8);
}
.namelist li {
  break-inside: avoid;
  padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--hairline);
}

/* Name and role. The default description list is capped at --measure because
   it holds contact details; a staff list is two short columns and reads better
   using the width it has. */
.deflist--roles { max-width: none; }

/* ── Contact block ──────────────── */
/* A postal address, set as one. <address> is the right element and it comes
   with an italic default that has nothing to do with the rest of the page. */
.contactblock {
  display: flex;
  flex-direction: column;
  margin: var(--sp-8) 0 var(--sp-6);
  font-style: normal;
  line-height: 1.6;
}
.contactblock-name {
  font-weight: 600;
  color: var(--bms-blue-700);
}

/* ── Description list ──────────────────────────── */
/* Labelled details — a contact block, a set of dates. A real <dl>, so the
   pairing is in the markup and not just in the alignment. Two columns where
   there is room; stacked where there is not, because a max-content label
   column leaves nothing for the value on a phone. */
.deflist {
  display: grid;
  grid-template-columns: minmax(0, max-content) minmax(0, 1fr);
  gap: var(--sp-3) var(--sp-8);
  /* Collapses against a preceding heading's own margin, so this only opens a
     gap where the list follows prose. */
  margin: var(--sp-8) 0 0;
  max-width: var(--measure);
}
.deflist dt {
  font-weight: 600;
  color: var(--bms-blue-700);
}
.deflist dd { margin: 0; }
/* Only where the list is followed by more of the page. The top margin above
   is matched below, so the figures sit in their own band rather than running
   straight into the next paragraph — on /pupil-premium/ the last value and
   the paragraph under it were touching, with no gap at all. Every other
   deflist on the site ends its section, and :has(+ *) leaves those alone:
   a bottom margin there would only pad out the section's own end. */
.deflist:has(+ *) { margin-bottom: var(--sp-8); }
@media (max-width: 599px) {
  .deflist {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
  }
  .deflist dt { margin-top: var(--sp-4); }
  .deflist dt:first-child { margin-top: 0; }
}

/* A heading below a section's own — used where a section carries more than
   one document list. Sits at h3 size so the level order stays honest. */
.page-subheading {
  margin: var(--sp-8) 0 var(--sp-4);
  font-size: var(--step-1);
  color: var(--bms-blue-700);
}

/* ── Document list ─────────────────────────────────────────────── */
.doclist {
  /* Stands off whatever is around it. These lists sit between blocks of prose
     as often as they sit alone under a heading, and with no margin the first
     rule landed hard against the paragraph above. Collapses against a
     heading's own margin, so a list that opens a section is unaffected. */
  margin: var(--sp-8) 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--hairline);
}
.doclist-item { border-bottom: 1px solid var(--hairline); }
.doclist-link {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 44px;
  padding: var(--sp-3) var(--sp-2);
  color: var(--ink);
  text-decoration: none;
  transition: background-color 0.2s var(--ease), padding-left 0.2s var(--ease);
}
.doclist-link:hover {
  background: var(--bms-blue-100);
  padding-left: var(--sp-4);
  color: var(--bms-blue-700);
}
.doclist-icon { width: 20px; height: 20px; flex: none; color: var(--bms-blue-700); }
.doclist-label { font-weight: 600; }
/* Part of the link text, not a decoration: a screen reader reads "…(PDF,
   1.2MB)" as one name, which is the warning that matters on mobile data. */
.doclist-meta { color: var(--ink-muted); font-size: var(--step--1); }

/* ── Accordion ─────────────────────────────────────────────────── */
/* Plain <details>: it works with no JS, is keyboard-operable for free, and
   browsers now expose it to assistive tech as a disclosure. No height
   animation — it would be suppressed by content-hiding anyway. */
.acc { border-top: 1px solid var(--hairline); }
.acc-item { border-bottom: 1px solid var(--hairline); }
.acc-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  min-height: 44px;
  padding: var(--sp-4) var(--sp-2);
  font-size: var(--step-1);
  font-weight: 600;
  color: var(--bms-blue-700);
  cursor: pointer;
  list-style: none; /* Firefox marker */
}
.acc-summary::-webkit-details-marker { display: none; }
.acc-summary::after {
  content: "";
  flex: none;
  width: 12px;
  height: 12px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  rotate: 45deg;
  translate: 0 -25%;
  transition: rotate 0.25s var(--ease);
}
.acc-item[open] > .acc-summary::after { rotate: -135deg; translate: 0 25%; }
.acc-summary:hover { background: var(--bms-blue-100); }
.acc-body {
  padding: 0 var(--sp-2) var(--sp-6);
  max-width: var(--measure);
}
.acc-body > * + * { margin-top: var(--sp-4); }
.acc-body ul { padding-left: var(--sp-6); }
.acc-body li + li { margin-top: var(--sp-2); }

@media (max-width: 1199px), (hover: none) and (pointer: coarse) and (max-width: 1400px) {
  /* Narrow: the crumb bar and the title panel are one navy ribbon, drawn as
     two contiguous boxes. Nothing about the navy itself moves, because
     animating it is wrong in both directions — on separate offsets the ribbon
     arrived in halves, and on a shared offset the two boxes became two
     composited layers whose join sits on a fractional pixel, so a hairline of
     page ground showed through it for the length of the fade. The ribbon is
     simply there, like the photograph above it, and what it carries arrives:
     breadcrumb and title together, on one offset with no stagger between
     them. Wide screens keep the staged version — there the two are separated
     by the photograph and the beat between them reads. */
  body:not(.is-landing) .phero-panel {
    opacity: 1;
    transform: none;
  }
  body:not(.is-landing) .phero-crumbs,
  body:not(.is-landing) .phero-panel .reveal {
    --reveal-offset: 120ms;
    --reveal-rise: 10px;
    --reveal-stagger: 0ms;
  }
  /* The ribbon lands at 120ms here rather than 720ms, so the body follows it
     much sooner than it does on a wide screen. */
  body:not(.is-landing) .phero ~ .psheet .is-initial { --reveal-offset: 420ms; }

  /* No rail to run under here — it is a top bar, so the hero is simply
     full width. The photo keeps its 16:9 on a phone too. */
  .phero {
    margin-left: 0;
    width: 100%;
  }
  /* The bar and the band are contiguous here, so the overlap belongs to
     whichever comes first. */
  .phero-crumbbar { margin-top: calc(var(--phero-overlap, 1.5rem) * -1); }
  .phero-panel {
    margin-top: 0;
    padding-block: var(--sp-4) var(--sp-8);
  }
}

/* ── Wide: the page top as laid out in mock-up.png ───────── */
/* Four layers, all sharing one set of measurements so their edges line up
   without any of them knowing about the others:
     1. a white field, with a pale sky block filling its top-right quarter;
     2. the breadcrumb, on white, above the photograph;
     3. the photograph, inset equally left and right;
     4. a navy panel across its lower-left corner, hanging past the photograph
        on both the left and the bottom, and a section card on the lower right
        hanging past it into the body of the page.
   The panel replaces the gradient scrim the title used to sit on: a solid
   ground carries text at 15.9:1 whatever the photograph behind it is doing,
   so no page has to be re-measured when its hero image changes. */
@media (min-width: 1200px) and (hover: hover), (min-width: 1200px) and (pointer: fine), (min-width: 1200px) and (pointer: none), (min-width: 1401px) {
  .shell-content {
    /* Outer limit for the whole page. Set clear of the widest ordinary
       desktop on purpose: a cap that bites by a handful of pixels leaves
       hairline gutters beside the rail and the card that read as flaws
       rather than as margins. Below this the page simply fills the window. */
    --pg-band: 120rem;
    --pg-edge: clamp(2rem, 5.5vw, 6rem);      /* photograph + prose left inset */
    --pg-aside-w: clamp(12rem, 14vw, 15rem);
    /* Between the prose and the index. menu-example.png runs 51px of 1897;
       this is a little wider, which is where "close, but not that close"
       lands. */
    --pg-aside-gap: clamp(1.5rem, 3.4vw, 4rem);
    /* The body column. Its own value rather than --measure, which stays what
       it is — the reading width for nested prose. menu-example.png runs its
       column at about 62% of the page; this is short of that but well past
       65ch, which is what was holding the column in. */
    --pg-col: 76ch;
    /* Whatever the window has over the band, split either side. Written out
       at each use rather than stored here: a percentage in a custom property
       re-resolves against whichever box reads it. */
    --pg-panel-drop: 3.5rem;   /* how far the title panel hangs below the photo */
    /* Two ceilings: the window, so the title panel is never below the fold,
       and the frame's own width, so a short wide monitor doesn't turn a
       panorama into a square. 38vw tracks the photograph's width closely
       enough to hold it near 2.2:1 from 1200px up. Named because the sky
       field is measured against it. */
    --pg-photo-h: clamp(22rem, min(38vw, calc(100svh - 12rem)), 46rem);

  }

  /* The page top and the body share one band so the photograph, the prose and
     the card all sit on the same left and right edges. The footer stays
     outside it and runs full width.
     The page top takes the band as PADDING rather than as a max-width. Capped
     and centred, its box stops short of the rail once the window is wider than
     the band, and the few pixels of page ground left over showed as a thin
     grey line running up the left edge against the white. As padding, the
     white and the ground below it reach the rail at every width and only the
     content is inset. The body below can stay capped: what shows either side
     of it is the page ground, which is what it is painted on anyway. */
  .phero { padding-inline: max(0px, calc((100% - var(--pg-band)) / 2)); }
  .psheet {
    max-width: var(--pg-band);
    margin-inline: auto;
    /* A floor under the margins, so the block never runs up against the rail
       on a narrow desktop. Beyond that the centring below sets them. */
    padding-inline: var(--pg-edge);
  }

  /* Rows rather than markup order: the breadcrumb is written after the
     photograph, where it belongs in the reading order, and moved above it
     here. The third row is empty and exists to hold the panel's overhang, so
     the hero's own box still ends where the panel does. */
  .phero {
    display: grid;
    grid-template-areas: "crumbs" "media" "tail";
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto var(--pg-panel-drop);
    /* The border around the photograph deepens as it falls: it opens on the
       page ground at the top, reaches --bms-sky three quarters of the way
       down the picture, then releases back to the page ground on the
       picture's lower edge — which is where the body's own ground takes over,
       so the two meet at the same value with no line between them.
       It has to come back rather than simply arriving dark, because
       --page-ground is all but the lightest tone on the page: a fade that
       darkens downward has nothing darker to land on unless the whole body
       moves with it. Releasing over the last quarter keeps the border blue
       and the body light.
       Stops are measured in the picture's own height; the last one sits on
       the media row's lower edge, since the third row is exactly
       --pg-panel-drop tall. */
    background: linear-gradient(
      to bottom,
      var(--page-ground) 0,
      var(--bms-sky) calc(100% - var(--pg-panel-drop) - var(--pg-photo-h) * 0.25),
      var(--page-ground) calc(100% - var(--pg-panel-drop))
    );
  }

  .phero-crumbbar {
    grid-area: crumbs;
    z-index: 1;
    background: transparent;
    color: var(--ink-muted);
    margin-top: 0;
    padding-block: var(--sp-6) var(--sp-4);
  }
  .phero-crumbs ol { color: var(--ink-muted); }
  .phero-crumbs a { color: var(--bms-blue-700); }
  /* 0.6 was tuned for white on navy. The same fade on --ink-muted over white
     lands at 2.8:1, so the separators carry their own colour instead. */
  .phero-crumbs li + li::before { opacity: 1; }
  .phero-crumbbar .phero-inner {
    max-width: none;
    margin-inline: 0;
    padding-inline: var(--pg-edge);
  }

  /* Height set outright rather than by ratio. aspect-ratio plus max-height on
     a box whose width is not definite makes the browser re-derive the WIDTH
     from the ratio, which is how this frame ended up hundreds of pixels short
     of the right edge twice before. A flat height and object-fit: cover cannot
     do that, and it makes "show more of the photograph vertically" a single
     number to turn. */
  .phero-media {
    grid-area: media;
    z-index: 1;
    aspect-ratio: auto;
    max-height: none;
    height: var(--pg-photo-h);
    width: auto;
    margin-inline: var(--pg-edge);
  }
  .phero-media::after { content: none; }

  .phero-panel {
    grid-area: media;
    z-index: 2;
    align-self: end;
    justify-self: start;
    /* Wider than half only when there is room: the card opposite it needs
       --pg-aside-w and a gap, and the two must never meet. */
    width: min(56%, 56rem);
    margin: 0 0 calc(var(--pg-panel-drop) * -1) calc(var(--pg-edge) * 0.4);
    padding: var(--sp-8) var(--sp-12) var(--sp-8);
    background: var(--bms-blue-900);
  }
  /* --step-4 is sized for a full-width column; inside a panel that is 56% of
     the page it wraps a short title onto two lines from about 1660px down,
     and two lines of 84px type fill three-quarters of the photograph. Tied to
     the viewport instead, so the title grows to fill the panel and stops at
     --step-4 rather than overrunning it. */
  .phero-title { font-size: min(5.1vw, var(--step-4)); }

  .phero-panel .phero-inner {
    max-width: none;
    margin-inline: 0;
    padding-inline: 0;
  }

  /* Two-word label, so all-caps and tracking are within the house rule. The
     rule after it is a fixed length, not a filler to the panel edge — it
     reads as a mark rather than as an underline. */
  .phero-eyebrow {
    display: flex;
    align-items: center;
    gap: var(--sp-6);
    margin-bottom: var(--sp-4);
    color: var(--gold);
    font-size: var(--step--1);
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    line-height: 1.2;
  }
  .phero-eyebrow::after {
    content: "";
    width: clamp(3rem, 7vw, 7rem);
    height: 1px;
    background: var(--gold-line);
  }
  /* The hairline belongs to the standfirst, so a page without one gets a
     panel that simply ends after the title instead of a rule floating under
     it. */
  .phero-standfirst {
    margin-top: var(--sp-6);
    padding-top: var(--sp-6);
    position: relative;
  }
  .phero-standfirst::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 4rem;
    height: 1px;
    background: var(--hairline-on-dark);
  }

  /* Prose left, card right. The card is pulled back up into the page top; it
     is a later sibling of the hero, so it paints over the photograph without
     the hero having to contain it or reserve space for it. */
  /* Both tracks sized to their content and the pair centred, rather than the
     prose track taking whatever is left. That is what closes the gap between
     the text and the index: the column IS the measure, so every line of body
     copy ends on the same edge as the rules above and below it, a fixed gap
     from the index. Before this the rules ran to within 36px of the index
     while the prose stopped 293px short, and the void between the two was
     what read as wrong.
     minmax(0, ...) rather than a flat width so the track gives way on a
     narrow desktop instead of overflowing, and justify-content splits the
     remainder evenly — the margins come out equal by construction rather than
     by arithmetic that only holds at one width. */
  .psheet {
    display: grid;
    grid-template-columns: minmax(0, var(--pg-col)) var(--pg-aside-w);
    column-gap: var(--pg-aside-gap);
    justify-content: center;
    align-items: start;
  }
  /* Fills its track, which is already the measure. Everything from the base
     rule that used to place it — the 72rem cap, the auto margins, the inline
     padding — comes off, so the grid is the only thing deciding where the
     column sits. Scoped to .psheet: the landing page's main is full-bleed. */
  .psheet main#main {
    grid-column: 1;
    max-width: none;
    margin-inline: 0;
    padding-inline: 0;
  }
  /* Both carry --measure of their own, which would leave them ending short of
     the rules around them now the column is wider than it — the two right
     edges this layout just got rid of. The accordion keeps its cap: it is
     nested inside a disclosure, where reading width matters more than lining
     up, and it holds the longest passages on the site. */
  .psheet .prose,
  .psheet .deflist { max-width: none; }
  /* Starts level with the first line of the body rather than up in the page
     top: the same inset main carries, so the two columns begin together.
     Scrolls with the page — nothing pinned. */
  .secnav {
    display: block;
    grid-column: 2;
    margin-top: var(--sp-16);
  }
}

/* ── Video on an interior page ────────────────────────
   A sibling of .prose rather than a child of it: the prose column is capped
   at the reading measure, which is narrower than a 16:9 frame wants. The
   Explore pages have .exvideo for the same job on their own grounds; this is
   that furniture on the light one.

   controls, no autoplay, and preload="metadata" are the settings, not
   defaults to override: an autoplaying video with no stop control is the
   pattern this site is built to avoid, and metadata-only means a 26MB file is
   not fetched until a reader asks for it. The poster is what they see first,
   so it carries the weight of the frame. */
.pagevideo {
  margin: var(--sp-8) 0 0;
  max-width: 56rem;
}
.pagevideo video {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--bms-blue-900);
  border-radius: var(--radius);
}

/* ── An embedded player ───────────────────────────────
   For a recording that lives on someone else's service rather than in
   Assets/Videos. A sibling of .prose, like .pagevideo, and for the same
   reason: the reading measure is narrower than a video frame wants.

   The supplied embed code carries width="640" height="480", which would be a
   fixed box that overflows a 320px screen and does not grow on a large one.
   The ratio is kept and the size is not: the iframe fills the column and the
   wrapper holds the shape. */
.pageembed {
  margin: var(--sp-8) 0 0;
  /* Narrower than .pagevideo's 56rem. A 4:3 frame at that width is 672px
     tall, which is more of the screen than a recording of a meeting earns. */
  max-width: 44rem;
}
/* Every embed states its own shape below. There is no sensible default: what
   the frame has to be is whatever the service's own embed code says, and the
   one time that was second-guessed here it was wrong. */
.pageembed-frame {
  position: relative;
  background: var(--bms-blue-900);
  border-radius: var(--radius);
  overflow: hidden;
}
/* Drive's video player, from width="640" height="480". Its chrome is a title
   bar above the video and a control bar below, both a fixed height whatever
   size the frame is — so on a narrow screen the two claim most of the box and
   the controls end up not drawn at all. The ratio sets the shape; the floor
   makes room for pixels of someone else's chrome, which is not a proportion
   of ours and cannot be expressed as one. */
.pageembed--recording .pageembed-frame {
  aspect-ratio: 4 / 3;
  min-height: 21rem;
}
/* Slides, from width="960" height="569" — a 16:9 slide plus a control bar of
   about 29px. No floor: this player fits the slide to the frame and centres
   it, so a frame taller than the ratio just banks dark space above and below
   rather than buying anything. A slide too small to read on a phone is a real
   problem, but not one a height can fix — hence the link beside it. */
.pageembed--slides .pageembed-frame {
  aspect-ratio: 960 / 569;
}
/* YouTube, from width="560" height="315" — 16:9 exactly, and here the
   supplied numbers and the obvious ratio agree. No floor: this player's
   controls overlay the picture instead of adding to it, so the frame only
   ever has to be the video. */
.pageembed--video .pageembed-frame {
  aspect-ratio: 16 / 9;
}
/* Drive's PDF viewer, on /news/ — the one embed meant to be READ rather than
   watched, so it takes the whole column instead of .pageembed's 44rem.
   How wide it is, is how big the words are: Drive fits the page to the frame,
   so 915px of column renders the A4 at 915px and 576 renders it at 576.
   It had a max-height, which was the mistake. With an aspect-ratio set, a
   height cap does not crop the frame — it shrinks the WIDTH to keep the
   ratio, so an 80svh cap took the frame to 720px tall and 576 wide, and made
   the document smaller than the column it sat in. There is no cap now; the
   width leads and the height follows it.
   Tall on purpose, and taller than A4 needs. Whether Drive fits the page to
   the frame's width or its height is Drive's business and it has changed
   before; a generous height is the reading that is safe either way. */
.pageembed--document { max-width: none; }
.pageembed--document .pageembed-frame {
  /* 30:23 — two thirds of the height it had at 1:1.15, which was more of the
     screen than one update needs now the width is doing the reading. */
  aspect-ratio: 30 / 23;
  min-height: 32rem;
  /* Drive's own canvas colour rather than the site's navy, so the frame and
     the viewer inside it are the same surface. */
  background: var(--drive-canvas);
}
/* Drive leaves a margin of canvas below the last page and none above the
   first, so the document starts hard against the toolbar. This is that
   missing margin: the iframe is inset from the top and the frame's own
   background — the same grey — shows through. Nothing is cropped; the viewer
   is simply that much shorter and scrolls as it always did. */
.pageembed--document .pageembed-frame iframe {
  top: var(--sp-4);
  /* Not height:auto. An iframe is a replaced element, so auto gives it its
     intrinsic default — 150px — rather than stretching it between top and
     bottom the way a div would. It collapsed to exactly that. */
  height: calc(100% - var(--sp-4));
}

.pageembed-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
/* The service is named in the text, not just in the frame: a reader deciding
   whether to load it should not have to guess whose player it is. */
.pageembed-note {
  margin-top: var(--sp-3);
  color: var(--ink-muted);
  font-size: var(--step--1);
}

/* ── The Contact Us map ───────────────────────────────
   Google's own embed code, loaded with the page. It was gated behind a button
   until 2026-09-08 so that nothing reached Google until the reader chose it;
   Sean asked for it to load on its own, which is recorded in GO-LIVE.md — the
   page now contacts Google on every visit. loading="lazy" is kept from the
   supplied code, so the request at least waits until the map is scrolled to.

   No max-width: it runs the full width of the body column, as everything else
   on the page does, which is also what it already did on a phone. */
.mapembed {
  margin-top: var(--sp-8);
  margin-bottom: var(--sp-12);
}
.mapembed-frame {
  position: relative;
  /* 4:3, from the supplied width="600" height="450". Kept on a phone, where
     the frame is only ~327px across and a wider one would leave the map too
     short to read. Desktop takes a fifth off the height below. */
  aspect-ratio: 4 / 3;
  /* Google's controls sit over the map rather than beside it, so there is no
     chrome to make room for — this floor is only so the map is big enough to
     be useful on a phone. */
  min-height: 15rem;
  background: var(--bms-blue-100);
  border-radius: var(--radius);
  overflow: hidden;
}
.mapembed-frame iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}
/* Desktop: 5:3 rather than 4:3, which is exactly a fifth off the height —
   915x686 became 915x549 at the width the body column runs to. Set as a ratio
   rather than a height so the reduction holds at every desktop width, not
   just the one it was measured at. */
@media (min-width: 1024px) and (hover: hover), (min-width: 1024px) and (pointer: fine), (min-width: 1024px) and (pointer: none), (min-width: 1401px) {
  .mapembed-frame { aspect-ratio: 5 / 3; }
}

/* ── Site search results ──────────────────────────────────────────
   The WordPress theme's search.php. The prototype has no search page — its
   search was built in WordPress instead, by decision — but these rules live
   here with the rest of the interior page, in both copies of this file, so
   the prototype's page.css and the theme's stay one file.

   The box and the status line are the Policies filter's, restated rather than
   borrowed: policies.css is loaded on /policies/ alone. */
.sitesearch {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  max-width: 36rem;
  margin: var(--sp-6) 0 var(--sp-3);
}
.sitesearch-input {
  flex: 1 1 14rem;
  min-width: 0;
  min-height: 44px;
  padding: var(--sp-3) var(--sp-4);
  font: inherit;
  font-size: var(--step-0);
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--ink-muted);
  border-radius: var(--radius);
}
.sitesearch-input:focus-visible {
  outline: 2px solid var(--bms-blue-700);
  outline-offset: 2px;
  border-color: var(--bms-blue-700);
}
.sitesearch-status {
  margin: 0 0 var(--sp-6);
  font-size: var(--step--1);
  color: var(--ink-muted);
}

/* A ruled list, as .doclist is: each result its page's name, the section it
   sits in above it, and the passage that matched below. */
.sresults {
  max-width: var(--measure);
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--hairline);
}
.sresult {
  padding: var(--sp-6) 0;
  border-bottom: 1px solid var(--hairline);
}
.sresult-section {
  margin: 0 0 var(--sp-1);
  font-size: var(--step--1);
  color: var(--ink-muted);
}
.sresult-title {
  margin: 0;
  font-size: var(--step-1);
  letter-spacing: 0;
  line-height: 1.25;
}
.sresult-title a { text-underline-offset: 0.15em; }
.sresult-title a:hover { color: var(--bms-blue-900); }
.sresult-excerpt {
  margin: var(--sp-2) 0 0;
  color: var(--ink);
}
/* The way on — the menu or the school office — set apart from a list of
   results above it; after "No results" it follows the status line as it is. */
.sresults + .sitesearch-more { margin-top: var(--sp-8); }
