/* =============================================================================
   BRIGHT — after tinyeinstein.org and mothersprideusa.com

   A programme-led conversion site. The register is a modern nursery brand:
   rounded type, pill buttons, generous radii, four saturated accents on white,
   and colour blocking rather than photography to separate sections.

   Contrast rule for this palette, computed not guessed: ink #1F2430 reads at
   10.1:1 on sunshine, 7.8:1 on leaf, 5.9:1 on sky and 5.6:1 on coral — so ink
   is safe on all four. WHITE on coral is 2.8:1, so white text never sits on an
   accent; it only ever sits on ink.
   ============================================================================= */

:root {
  --white: #ffffff;
  --cream: #fffbf2;
  --sunshine: #ffc93c;
  --coral: #ff6b6b;
  --sky: #4ea8de;
  --leaf: #57cc99;
  --ink: #1f2430;
  --ink-2: #565d6e;
  --line: #e7e3da;

  /* A rounded stack. ui-rounded resolves to SF Rounded on Apple platforms;
     everywhere else this degrades to the platform UI face, which is the
     trade-off accepted when we chose system fonts over webfont bytes. */
  --font: ui-rounded, "Hiragino Maru Gothic ProN", "Segoe UI Variable Display",
          "Segoe UI", Roboto, system-ui, -apple-system, "Helvetica Neue", sans-serif;

  --r-sm: 12px;
  --r: 20px;
  --r-lg: 28px;
  --r-xl: 40px;
  --pill: 999px;

  --shell: 1200px;
  --pad: clamp(18px, 4vw, 44px);
  --gap-y: clamp(52px, 9vw, 104px);

  --shadow: 0 10px 30px rgba(31, 36, 48, 0.09);
  --shadow-lg: 0 18px 50px rgba(31, 36, 48, 0.14);
}

*, *::before, *::after { box-sizing: border-box; }

/* scroll-padding-top clears the sticky masthead, which is a flat ~79px at
   every breakpoint, so one value needs no media query. Without it every
   in-page anchor lands its target flush underneath the header: the skip
   link buried the breadcrumb on /about by 43px on a phone, and an arrival
   from a Google result carrying a #:~:text= fragment does the same. */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 6rem; }

body {
  margin: 0;
  background: var(--white);
  color: var(--ink);
  font-family: var(--font);
  font-size: 1.0625rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; height: auto; }
iframe { max-width: 100%; border: 0; }

h1, h2, h3, h4 {
  margin: 0 0 0.5em;
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.022em;
}

p { margin: 0 0 1.1em; }
p:last-child { margin-bottom: 0; }
a { color: inherit; }

ul { margin: 0 0 1.1em; padding-left: 1.2em; }
li { margin-bottom: 0.4em; }

:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; border-radius: 4px; }

.shell { max-width: var(--shell); margin-inline: auto; padding-inline: var(--pad); }

.skip { position: absolute; left: -9999px; background: var(--ink); color: #fff; padding: 0.8em 1.2em; z-index: 200; }
.skip:focus { left: 0; top: 0; }

/* ---------------------------------------------------------------- utility bar */

.u-bar {
  background: var(--ink);
  color: #fff;
  font-size: 0.8125rem;
  padding-top: env(safe-area-inset-top, 0px);
}
.u-bar__in {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 1.5rem;
  min-height: 42px;
  padding-block: 0.4rem;
}
.u-bar__calls { margin-left: auto; display: flex; gap: 0.9rem; flex-wrap: wrap; }
.u-bar__tel { text-decoration: none; font-weight: 700; }
.u-bar__tel:hover { text-decoration: underline; }
@media (max-width: 719px) {
  .u-bar__where, .u-bar__when { display: none; }
  .u-bar__calls { margin-left: 0; }
}

/* ------------------------------------------------------------------ masthead */

.masthead { position: sticky; top: 0; z-index: 100; background: rgba(255, 255, 255, 0.96); backdrop-filter: blur(8px); border-bottom: 1px solid var(--line); }
.masthead__in { display: flex; align-items: center; gap: 1rem; min-height: 78px; }

.brand { display: inline-flex; align-items: center; gap: 0.6rem; text-decoration: none; }
.brand__mark { width: 44px; height: auto; }
.brand__name { display: flex; flex-direction: column; line-height: 1.12; }
.brand__name strong { font-size: 1.22rem; font-weight: 800; letter-spacing: -0.02em; }
.brand__name span { font-size: 0.7rem; color: var(--ink-2); letter-spacing: 0.04em; text-transform: uppercase; font-weight: 600; }

.nav { margin-left: auto; display: flex; align-items: center; gap: 1.6rem; }
.nav__list { display: flex; gap: 1.15rem; list-style: none; margin: 0; padding: 0; }
.nav__list li { margin: 0; }
.nav__list a {
  text-decoration: none;
  font-size: 0.895rem;
  font-weight: 700;
  padding: 0.45em 0;
  display: inline-block;
  border-bottom: 3px solid transparent;
}
.nav__list a:hover { border-bottom-color: var(--sunshine); }
.nav__list a.is-current { border-bottom-color: var(--coral); }
.nav__cta { display: flex; gap: 0.55rem; }

.burger { display: none; flex-direction: column; justify-content: center; align-items: center; gap: 4px; width: 48px; height: 48px; margin-left: auto; padding: 0; border: 0; background: none; cursor: pointer; }
.burger span:not(.burger__label) { display: block; width: 24px; height: 2.5px; background: var(--ink); border-radius: 2px; transition: transform .25s ease, opacity .25s ease; }
.burger__label { font-size: 0.55rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-2); margin-top: 2px; }
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

@media (max-width: 1023px) {
  .burger { display: flex; }
  .nav {
    position: absolute; left: 0; right: 0; top: 100%;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--white); border-bottom: 1px solid var(--line);
    padding: 0 var(--pad);
    max-height: 0; overflow: hidden; transition: max-height .3s ease;
  }
  .nav[data-open="true"] { max-height: 80vh; padding-block: 0.8rem 1.4rem; overflow-y: auto; }
  .nav__list { flex-direction: column; gap: 0; }
  .nav__list a { display: block; padding: 0.85em 0; border-bottom: 1px solid var(--line); border-left: 4px solid transparent; padding-left: 0.6em; }
  .nav__list a.is-current { border-left-color: var(--coral); border-bottom-color: var(--line); }
  .nav__cta { padding-top: 1rem; }
  .nav__cta .btn { flex: 1; text-align: center; }
}

/* -------------------------------------------------------------------- buttons */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px;
  padding: 0.75em 1.7em;
  border: 2.5px solid transparent;
  border-radius: var(--pill);
  background: var(--sunshine);
  color: var(--ink);
  font: inherit; font-size: 0.9rem; font-weight: 800;
  text-decoration: none; cursor: pointer;
  transition: transform .18s ease, box-shadow .18s ease, background .18s ease;
}
.btn:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
.btn:active { transform: translateY(0); }
.btn--coral { background: var(--coral); }
.btn--leaf { background: var(--leaf); }
.btn--sky { background: var(--sky); }
.btn--ink { background: var(--ink); color: #fff; }
.btn--ghost { background: transparent; border-color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: #fff; }
.btn--onDark { border-color: #fff; color: #fff; }
.btn--onDark:hover { background: #fff; color: var(--ink); }
.btn[disabled] { opacity: .55; cursor: not-allowed; transform: none; box-shadow: none; }

/* --------------------------------------------------------------------- blocks */

.block { padding-block: var(--gap-y); }
.block--cream { background: var(--cream); }
.block--ink { background: var(--ink); color: #fff; }
.block--tight { padding-block: clamp(36px, 6vw, 68px); }

.eyebrow {
  display: inline-block;
  margin-bottom: 0.75rem;
  padding: 0.4em 1em;
  border-radius: var(--pill);
  background: var(--sunshine);
  /* Explicit, not inherited. Inside the hero .eyebrow sat in a block with
     color:#fff, so white landed on sky at 2.63:1 — invisible, not merely low.
     Ink is 10.1:1 on sunshine, 7.8:1 on leaf, 5.9:1 on sky, 5.6:1 on coral. */
  color: var(--ink);
  font-size: 0.72rem; font-weight: 800;
  letter-spacing: 0.12em; text-transform: uppercase;
}
.eyebrow--coral { background: var(--coral); }
.eyebrow--sky { background: var(--sky); }
.eyebrow--leaf { background: var(--leaf); }
.block--ink .eyebrow { color: var(--ink); }

/* The vh term only engages on a window shorter than about 800px, where the
   hero copy was otherwise taller than the hero itself. On a phone the vw
   term is already the smaller of the two and the 2.1rem floor governs, so
   nothing there changes. */
.h-xl { font-size: clamp(2.1rem, min(5.4vw, 7vh), 3.5rem); }
.h-lg { font-size: clamp(1.75rem, 3.8vw, 2.6rem); }
.lead { font-size: clamp(1.02rem, 1.5vw, 1.18rem); color: var(--ink-2); max-width: 62ch; }
.block--ink .lead { color: rgba(255,255,255,.76); }
.center { text-align: center; }
.center .lead { margin-inline: auto; }

/* ----------------------------------------------------------------------- hero */

.hero { position: relative; background: var(--ink); }
.hero__track {
  display: flex; list-style: none; margin: 0; padding: 0;
  overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.hero__track::-webkit-scrollbar { display: none; }
.hero__slide { flex: 0 0 100%; scroll-snap-align: center; margin: 0; }
/* The hero has no height of its own: this is what sets it. The floor has to
   hold the copy plus the wave and dots band beneath it, or the copy centres
   itself out through both ends of the hero — under the masthead at the top
   and under the wave at the bottom, which is what it used to do on any
   window below ~700px tall. Below 900px wide the headline is a third of the
   size and 74vh already clears it, so the floor only rises above that. */
.hero__slide img { width: 100%; height: clamp(470px, 74vh, 760px); object-fit: cover; }
@media (min-width: 900px) { .hero__slide img { height: clamp(660px, 74vh, 760px); } }

.hero__wash {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(105deg, rgba(20,24,33,.90) 0%, rgba(20,24,33,.74) 38%, rgba(20,24,33,.30) 70%, rgba(20,24,33,.12) 100%);
}
/* Centred in what the wave and the dots leave, not in the whole hero. Same
   reasoning as .hero__dots further down, which lifts itself clear of the
   wave by the wave's own height; the copy never got the same treatment.
   4.2rem is the dots band: the 1.4rem they sit above the wave plus their
   44px tap target.

   z-index outranks the wave's 3. With the height floor above it should
   never come into play, but if the copy ever does outgrow its hero (a large
   default font size, a longer headline) text painted over the wave beats
   text painted under it. */
.hero__copy {
  position: absolute; inset: 0; display: flex; align-items: center;
  padding-bottom: calc(clamp(42px, 6vw, 84px) + 4.2rem);
  z-index: 5;
  pointer-events: none;
}
.hero__copy .shell { width: 100%; }
.hero__inner { max-width: 40ch; color: #fff; pointer-events: auto; }
.hero__inner .lead { color: rgba(255,255,255,.88); }
.hero__btns { display: flex; flex-wrap: wrap; gap: 0.7rem; margin-top: 1.6rem; }

.hero__dots { position: absolute; left: 0; right: 0; bottom: 1.4rem; display: flex; justify-content: center; gap: 0.5rem; }
.hero__dot { width: 44px; height: 44px; padding: 0; border: 0; background: none; cursor: pointer; display: grid; place-items: center; }
.hero__dot::after { content: ''; width: 11px; height: 11px; border-radius: 50%; background: rgba(255,255,255,.45); transition: background .2s ease, transform .2s ease; }
.hero__dot.is-on::after { background: var(--sunshine); transform: scale(1.35); }

/* ------------------------------------------------------------------ programmes */

.progs { display: grid; gap: clamp(1.1rem, 2.4vw, 1.8rem); grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); list-style: none; margin: 2.4rem 0 0; padding: 0; }
.prog {
  margin: 0; padding: 1.7rem 1.5rem 1.5rem;
  border-radius: var(--r-lg);
  background: var(--white);
  box-shadow: var(--shadow);
  border-top: 7px solid var(--sunshine);
  display: flex; flex-direction: column;
}
.prog:nth-child(2) { border-top-color: var(--coral); }
.prog:nth-child(3) { border-top-color: var(--sky); }
.prog:nth-child(4) { border-top-color: var(--leaf); }
.prog__age { display: inline-block; align-self: flex-start; margin-bottom: 0.8rem; padding: 0.3em 0.85em; border-radius: var(--pill); background: var(--cream); font-size: 0.78rem; font-weight: 800; }
.prog h3 { font-size: 1.2rem; margin-bottom: 0.4em; }
.prog p { font-size: 0.94rem; color: var(--ink-2); }
.prog__more { margin-top: auto; padding-top: 1rem; font-size: 0.87rem; font-weight: 800; text-decoration: none; border-bottom: 2px solid var(--sunshine); align-self: flex-start; }

/* ------------------------------------------------------------------ enrichment */

.tiles { display: grid; gap: clamp(1rem, 2.2vw, 1.6rem); grid-template-columns: 1fr; list-style: none; margin: 2.4rem 0 0; padding: 0; }
/* Fixed counts, not auto-fit: six tiles want two rows of three. auto-fit gave
   five across and orphaned the sixth on a row of its own. */
@media (min-width: 620px) { .tiles { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 980px) { .tiles { grid-template-columns: repeat(3, 1fr); } }
.tile { margin: 0; padding: 1.5rem 1.3rem; border-radius: var(--r-lg); background: var(--white); border: 2px solid var(--line); }
.tile h3 { font-size: 1.02rem; margin-bottom: 0.35em; }
.tile p { font-size: 0.88rem; color: var(--ink-2); margin: 0; }

/* ---- photo inside a tile --------------------------------------------- */

/* Four across, not three. The 980px rule above is tuned for the six
   co-curricular tiles on /programs; four tiles under it strand one on a row of
   its own. Four also lines this row up with the four programme cards directly
   above it on the homepage, which is the only place .tiles--pic is used. */
@media (min-width: 980px) { .tiles--pic { grid-template-columns: repeat(4, 1fr); } }

/* Full-bleed to the card edge, the same trick as .prog--pic. overflow:hidden
   on the card is what clips the photo to the 28px radius, and the negative
   margins match .tile's own 1.5rem/1.3rem padding exactly.

   max-width:none is load-bearing: the global `img { max-width: 100% }` caps
   this at the card's content box, so calc(100% + 2.6rem) would silently
   resolve to 100% and the photo would stop short of both edges. */
.tile--pic { overflow: hidden; }
.tile__pic {
  max-width: none;
  width: calc(100% + 2.6rem);
  margin: -1.5rem -1.3rem 1.1rem;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}
/* Deliberately the same pill as .prog__age. .tile is not a flex column, so it
   centres itself inside .center instead of needing align-self. */
.tile__stat { display: inline-block; margin-bottom: 0.8rem; padding: 0.3em 0.85em; border-radius: var(--pill); background: var(--cream); font-size: 0.78rem; font-weight: 800; }

/* ------------------------------------------------------------------ why / split */

.split { display: grid; gap: clamp(1.8rem, 4vw, 3.5rem); align-items: center; }
@media (min-width: 900px) { .split { grid-template-columns: 1fr 1fr; } .split--flip > *:first-child { order: 2; } }
.split__media img { border-radius: var(--r-xl); box-shadow: var(--shadow-lg); width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.ticks { list-style: none; margin: 1.5rem 0 0; padding: 0; }
.ticks li { position: relative; padding-left: 2.4rem; margin-bottom: 1rem; }
.ticks li::before { content: ''; position: absolute; left: 0; top: 0.15em; width: 26px; height: 26px; border-radius: 50%; background: var(--leaf); }
.ticks li::after { content: ''; position: absolute; left: 8px; top: 0.45em; width: 10px; height: 6px; border-left: 2.5px solid var(--ink); border-bottom: 2.5px solid var(--ink); transform: rotate(-45deg); }
.ticks strong { display: block; }

/* -------------------------------------------------------------------- timeline */

.day { list-style: none; margin: 2.6rem 0 0; padding: 0; display: grid; gap: 0; }
@media (min-width: 860px) { .day { grid-template-columns: repeat(6, 1fr); } }
.day__step { margin: 0; position: relative; padding: 0 1rem 2rem; }
@media (min-width: 860px) { .day__step { padding: 3.2rem 0.7rem 0; text-align: center; } }
.day__dot { width: 20px; height: 20px; border-radius: 50%; background: var(--sunshine); border: 4px solid var(--ink); position: relative; z-index: 1; }
@media (min-width: 860px) {
  .day__dot { position: absolute; top: 0; left: 50%; transform: translateX(-50%); }
  .day__step::before { content: ''; position: absolute; top: 9px; left: 0; right: 0; height: 3px; background: rgba(255,255,255,.22); }
  .day__step:first-child::before { left: 50%; }
  .day__step:last-child::before { right: 50%; }
}
@media (max-width: 859px) {
  .day__step { padding-left: 2.6rem; }
  .day__dot { position: absolute; left: 0; top: 0.3rem; }
  .day__step::before { content: ''; position: absolute; left: 9px; top: 1.6rem; bottom: -0.4rem; width: 3px; background: rgba(255,255,255,.22); }
  .day__step:last-child::before { display: none; }
}
.day__time { display: block; margin-top: 0.7rem; font-size: 0.76rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--sunshine); }
.day__step h3 { font-size: 1rem; margin: 0.35em 0 0.25em; }
.day__step p { font-size: 0.86rem; color: rgba(255,255,255,.72); margin: 0; }

/* ----------------------------------------------------------------- testimonials */

.voices { display: flex; gap: 1.2rem; overflow-x: auto; scroll-snap-type: x mandatory; list-style: none; margin: 2.4rem 0 0; padding: 0 0 1rem; scrollbar-width: none; }
.voices::-webkit-scrollbar { display: none; }
.voice { flex: 0 0 min(88%, 380px); scroll-snap-align: start; margin: 0; padding: 1.8rem 1.6rem; border-radius: var(--r-lg); background: var(--white); box-shadow: var(--shadow); }
.voice__stars { color: var(--sunshine); font-size: 1.1rem; letter-spacing: 0.1em; margin-bottom: 0.7rem; }
.voice p { font-size: 0.98rem; }
.voice cite { display: block; margin-top: 1rem; font-size: 0.82rem; font-style: normal; font-weight: 800; color: var(--ink-2); }

/* --------------------------------------------------------------------- gallery */

.gals { display: grid; gap: clamp(1.1rem, 2.4vw, 1.8rem); grid-template-columns: repeat(auto-fit, minmax(min(100%, 270px), 1fr)); list-style: none; margin: 2.4rem 0 0; padding: 0; }
.gal { margin: 0; }
.gal__link { display: block; text-decoration: none; border-radius: var(--r-lg); overflow: hidden; background: var(--white); box-shadow: var(--shadow); }
.gal__link img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; transition: transform .35s ease; }
.gal__link:hover img { transform: scale(1.04); }
.gal__body { display: block; padding: 1.1rem 1.2rem 1.3rem; }
.gal__title { display: block; font-weight: 800; font-size: 1.05rem; }
.gal__count { display: block; font-size: 0.82rem; color: var(--ink-2); margin-top: 0.15rem; }

.shots { display: grid; gap: clamp(0.5rem, 1.4vw, 1rem); grid-template-columns: repeat(2, 1fr); list-style: none; margin: 2.2rem 0 0; padding: 0; }
@media (min-width: 900px) { .shots { grid-template-columns: repeat(3, 1fr); } }
.shots li { margin: 0; }
.shot { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: zoom-in; border-radius: var(--r); overflow: hidden; }
.shot img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; transition: transform .3s ease; }
.shot:hover img { transform: scale(1.05); }

/* -------------------------------------------------------------------- lightbox */

.lb:not([open]) { display: none; }
.lb[open] { position: fixed; inset: 0; z-index: 300; display: grid; place-items: center; width: 100%; max-width: 100%; height: 100%; max-height: 100%; padding: clamp(1rem, 4vw, 3rem); border: 0; background: rgba(15, 18, 25, .94); }
.lb::backdrop { background: rgba(15, 18, 25, .94); }
.lb img { max-width: 100%; max-height: 80vh; width: auto; border-radius: var(--r); }
.lb__cap { color: #e9e9ec; font-size: 0.85rem; text-align: center; margin-top: 0.9rem; max-width: 62ch; }
.lb__x, .lb__nav button { position: absolute; width: 52px; height: 52px; border: 0; border-radius: 50%; background: rgba(255,255,255,.14); color: #fff; font-size: 1.4rem; cursor: pointer; line-height: 1; }
.lb__x { top: 1rem; right: 1rem; }
.lb__nav .prev { left: 1rem; top: 50%; transform: translateY(-50%); }
.lb__nav .next { right: 1rem; top: 50%; transform: translateY(-50%); }
.lb__x:hover, .lb__nav button:hover { background: rgba(255,255,255,.3); }

/* ----------------------------------------------------------------------- prose */

.prose { max-width: 68ch; }
.prose h2 { font-size: clamp(1.4rem, 2.6vw, 1.9rem); margin-top: 1.9em; }
.prose h3 { font-size: 1.12rem; margin-top: 1.5em; }
.prose h2:first-child, .prose h3:first-child { margin-top: 0; }

.callout { padding: 1.4rem 1.6rem; border-radius: var(--r-lg); background: var(--cream); border-left: 7px solid var(--sky); margin: 1.8rem 0; }

/* ----------------------------------------------------------------- fees & faq */

.faqs { margin-top: 1.8rem; }
.faq { border: 2px solid var(--line); border-radius: var(--r); margin-bottom: 0.8rem; background: var(--white); }
.faq > summary { cursor: pointer; padding: 1.05em 1.3em; font-weight: 800; font-size: 1rem; list-style: none; display: flex; justify-content: space-between; gap: 1rem; align-items: center; }
.faq > summary::-webkit-details-marker { display: none; }
.faq > summary::after { content: '+'; font-size: 1.5rem; font-weight: 700; color: var(--ink-2); line-height: 1; }
.faq[open] > summary::after { content: '\2212'; }
.faq > div { padding: 0 1.3em 1.2em; font-size: 0.95rem; color: var(--ink-2); }

/* -------------------------------------------------------------------- contact */

.contact-grid { display: grid; gap: clamp(1.4rem, 3vw, 2.4rem); grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr)); margin-top: 2.2rem; }
.cbox { padding: 1.6rem; border-radius: var(--r-lg); background: var(--white); box-shadow: var(--shadow); }
.cbox h2 { font-size: 1.05rem; margin-bottom: 0.6em; }
.cbox ul { list-style: none; padding: 0; margin: 0; font-size: 0.95rem; }
.cbox address { font-style: normal; font-size: 0.95rem; }
.cbox address span { display: block; }
.mapwrap { margin-top: 2.2rem; }
.map-frame { width: 100%; aspect-ratio: 16 / 10; border-radius: var(--r-lg); background: var(--cream); border: 2px solid var(--line); }
.mapwrap__cta { margin-top: 1rem; }

.form { max-width: 620px; margin-top: 2rem; }
.form__row { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); }
.form label { display: block; font-size: 0.82rem; font-weight: 800; margin-bottom: 0.4em; }
.form input, .form textarea { width: 100%; font: inherit; font-size: 1rem; padding: 0.8em 1em; border: 2px solid var(--line); border-radius: var(--r); background: var(--white); color: var(--ink); }
.form textarea { min-height: 140px; resize: vertical; }
.form input:focus, .form textarea:focus { outline: 3px solid var(--sky); outline-offset: 1px; border-color: var(--sky); }
.form__field { margin-bottom: 1.1rem; }

/* Honeypot. Positioned off-screen rather than display:none, because a bot that
   skips display:none fields is exactly the bot worth catching. Both the
   aria-hidden wrapper and the negative offset are recognised by the tap-target
   probe in tools/audit.js, which skips each of them by design. */
.hp { position: absolute; left: -9999px; top: auto; width: 1px; height: 1px; overflow: hidden; }

/* Send result. Empty until the response lands, so it takes no space and is not
   announced on arrival; role="status" reads it out once it fills. */
.form__status { margin-top: 1rem; font-weight: 700; min-height: 1.5em; }
.form__status--ok { color: #1f7a4d; }
.form__status--err { color: #b3261e; }

/* ------------------------------------------------------------------ placeholder */

/* Deliberately at odds with the palette. These blocks exist so the layout can
   be judged; the one outcome worse than an empty section is filler mistaken
   for the school's own words. */
.flag {
  display: inline-block; margin-bottom: 1rem;
  padding: 0.4em 0.95em;
  border: 2.5px dashed #b3261e; border-radius: var(--r-sm);
  background: #fff1f0; color: #8a1c1c;
  font-size: 0.74rem; font-weight: 800;
  letter-spacing: 0.08em; text-transform: uppercase;
}
.block--ink .flag { background: #2a1513; color: #ffb4ab; border-color: #ffb4ab; }

/* ---------------------------------------------------------------------- footer */

.foot { background: var(--ink); color: #fff; padding-block: clamp(42px, 7vw, 76px) 0; }
.foot__in { display: grid; gap: clamp(1.8rem, 4vw, 3rem); grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr)); }
.foot__col--wide { grid-column: 1 / -1; }
@media (min-width: 900px) { .foot__col--wide { grid-column: span 1; } }
.foot__mark { font-size: 1.3rem; font-weight: 800; margin-bottom: 0.3em; }
.foot__tag { color: rgba(255,255,255,.72); font-size: 0.95rem; }
.foot__btns { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 1.2rem; }
.foot__h { font-size: 0.78rem; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; color: var(--sunshine); margin-bottom: 0.9em; }
.foot__addr { font-style: normal; font-size: 0.92rem; color: rgba(255,255,255,.8); }
.foot__addr span { display: block; }
.foot__list { list-style: none; padding: 0; margin: 0; font-size: 0.92rem; color: rgba(255,255,255,.8); }
.foot__list a { text-decoration: none; }
.foot__list a:hover { text-decoration: underline; }
.foot__list--plain strong { display: block; color: #fff; font-weight: 800; }
.foot__link { font-size: 0.92rem; margin-top: 0.8rem; }
.foot__rule { border-top: 1px solid rgba(255,255,255,.14); margin-top: clamp(2rem, 5vw, 3.4rem); padding-block: 1.4rem calc(1.4rem + env(safe-area-inset-bottom, 0px)); }
.foot__rule p { font-size: 0.82rem; color: rgba(255,255,255,.6); margin: 0; }

/* ------------------------------------------------------------- reduced motion */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}

/* ----------------------------------------------------------------------- team */

.people { list-style: none; margin: 2.4rem 0 0; padding: 0; display: grid; gap: clamp(1.4rem, 3vw, 2.4rem); }
@media (min-width: 820px) { .people { grid-template-columns: 1fr 1fr; } }
.person { margin: 0; padding: 1.8rem 1.6rem; border-radius: var(--r-lg); background: var(--white); box-shadow: var(--shadow); }
.person__pic { width: 120px; height: 120px; border-radius: 50%; object-fit: cover; margin-bottom: 1.1rem; }
.person__body h3 { font-size: 1.12rem; margin-bottom: 0.15em; }
.person__role { font-size: 0.78rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--coral); margin-bottom: 1em; }
.person__body p:last-child { margin-bottom: 0; }
.person__body p { font-size: 0.94rem; color: var(--ink-2); }

/* ----------------------------------------------------------- interior banner */

/* Tightened now that the sub-heading is gone from these pages: the old
   padding was sized for a title plus a line of lead, and without it the band
   was mostly empty dark space. The trailing margin under the h1 goes too when
   nothing follows it. */
.banner { background: var(--ink); color: #fff; padding-block: clamp(36px, 5.5vw, 66px); }
.banner h1:last-child { margin-bottom: 0; }
.banner h1 { font-size: clamp(2rem, 4.6vw, 3.1rem); margin-bottom: 0.3em; }
.banner .lead { color: rgba(255,255,255,.78); }
.crumbs { font-size: 0.82rem; color: rgba(255,255,255,.6); margin-bottom: 1rem; }
/* Exempt from 2.5.8 as an inline target, but a 14px-high link is still a mean
   thing to ask a thumb to find. Padding costs nothing here. */
.crumbs a { text-decoration: none; display: inline-block; padding-block: 0.5em; }
.crumbs a:hover { text-decoration: underline; }


/* --------------------------------------------------------------- tap areas */

/* WCAG 2.5.8. A phone number stacked in a list is a target like any other
   button, and at its natural 15px line box it is a 21px-high one. Links
   genuinely inline inside a sentence are left alone — enlarging those would
   wreck the sentence, and the standard exempts them. */
.u-bar__tel,
.cbox ul a,
.cbox address a,
.cbox p a,
.foot__list a,
.foot__link a,
.prog__more,
.gal__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.gal__link { display: block; }
.foot__list li { margin-bottom: 0; }
.cbox ul li { margin-bottom: 0; }

/* Three numbers wrap to two rows on a phone and push the hero below the fold
   for the sake of duplicate information. One is enough there; the contact page
   and the footer still carry all three. */
@media (max-width: 719px) {
  .u-bar__tel:not(:first-child) { display: none; }
}

/* ---------------------------------------------------------------- hero wave */

/* A wave along the bottom edge of the hero, cutting into the block below.

   The shape is carried as a mask and the COLOUR as background-color, rather
   than baking a fill into an encoded SVG data URI. That is what lets the wave
   track whatever section follows the hero by changing one custom property,
   instead of re-encoding the URI every time the block beneath it changes.

   The mask STRETCHES rather than tiles. A fixed 1200px tile left a visible step
   on any viewport wider than the tile, where the end of one repeat met the
   start of the next at a different height. One stretched wave has no seam to
   get wrong, and preserveAspectRatio='none' is what makes stretching legal.

   -webkit-mask is kept alongside the unprefixed property for the older Android
   WebViews in this audience, where unprefixed mask is not yet safe. */
.hero__wave {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;               /* -1px: kills the hairline seam at some zooms */
  height: clamp(42px, 6vw, 84px);
  z-index: 3;
  pointer-events: none;
  background-color: var(--wave-fill, var(--cream));
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: 50% 100%;
          mask-position: 50% 100%;
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 100' preserveAspectRatio='none'%3E%3Cpath d='M0 28 C 200 96 400 -18 600 30 C 800 78 1000 4 1200 38 L1200 100 L0 100 Z' fill='%23000'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 100' preserveAspectRatio='none'%3E%3Cpath d='M0 28 C 200 96 400 -18 600 30 C 800 78 1000 4 1200 38 L1200 100 L0 100 Z' fill='%23000'/%3E%3C/svg%3E");
}

/* The dots sat at 1.4rem and the wave now occupies that band, so they lift
   clear of it rather than being half-swallowed by the crest of the curve. */
.hero__dots { bottom: calc(1.4rem + clamp(42px, 6vw, 84px)); z-index: 4; }

/* ------------------------------------------------------------ footer social */

.foot__social { display: flex; gap: 0.6rem; margin-top: 1.1rem; }
.social {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;              /* clears the 44px tap-target floor */
  border: 2px solid rgba(255, 255, 255, 0.28);
  border-radius: 50%;
  color: #fff;
  transition: background .18s ease, border-color .18s ease, color .18s ease;
}
.social:hover { background: var(--sunshine); border-color: var(--sunshine); color: var(--ink); }
.social svg { display: block; }


/* ---------------------------------------------------------------- confetti */

/* For the one moment on this site that is actually an achievement: a parent
   has just sent an enquiry. Ported from the previous Doxa site, whose argument
   for building this rather than importing canvas-confetti holds here too. The
   library is ~4KB brotli, but that is 4KB of JavaScript, the most expensive
   resource byte-for-byte on the cheap Android handsets in this audience, and
   it would ship on all fourteen pages for a burst that fires on one.

   The pieces are built in js/site.js at the moment of the send and removed
   afterwards, so the resting cost is this block of CSS alone.

   One shared @keyframes driven by per-piece custom properties. A separate
   @keyframes per piece, which is the usual CodePen shape of this, multiplies
   the CSS many times over for no visual gain.

   z-index 400 puts it over the lightbox at 300, which is the highest thing
   otherwise on the page. */
.confetti {
  position: fixed;
  inset: 0;
  z-index: 400;
  overflow: hidden;
  pointer-events: none;   /* alongside aria-hidden + inert, set in site.js */
}
.confetti i {
  position: absolute;
  top: 0;
  left: var(--x);
  width: var(--w, 8px);
  height: var(--h, 12px);
  background: var(--c);
  border-radius: var(--br, 2px);
  opacity: 0;
  /* linear, not ease-out: confetti falls, it does not decelerate into the
     floor. ease-out made every piece slow to a halt at the bottom of the
     screen, which is the one thing real confetti never does. */
  animation: confetti-fall var(--dur-piece) linear var(--delay) 1 forwards;
}
@keyframes confetti-fall {
  /* --sy is set per piece, so the field is spread over 100vh above the fold
     rather than every piece starting on the same line and arriving as one
     dense curtain. */
  0%   { transform: translate3d(0, var(--sy, -12vh), 0) rotate(0deg); opacity: 1; }
  /* Full opacity almost the whole way down, fading only at the end. Fading
     across the entire fall made the burst look thin and grey through its own
     middle. */
  88%  { opacity: 1; }
  100% { transform: translate3d(var(--dx), 104vh, 0) rotate(var(--r)); opacity: 0; }
}

/* ========================================================================
   SECTION PHOTOGRAPHY
   Four treatments so a page of photographs does not read as a spreadsheet
   of rectangles. None of them are used on photos inside cards, which keep a
   plain edge so the card itself stays the frame.
   ======================================================================== */

.fig { margin: 0; position: relative; }
.fig img { width: 100%; display: block; }

/* ---- wave: the hero's bottom edge, reused ---------------------------- */

/* Same shape as .hero__wave, cut into the photo itself rather than laid over
   it, so whatever colour the section is shows through the trough. Stretched,
   not tiled, for the same reason the hero one is: a fixed tile leaves a step
   wherever one repeat meets the next at a different height. */
.fig--wave img {
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 900' preserveAspectRatio='none'%3E%3Cpath d='M0 0 H1200 V820 C 1000 880 800 760 600 812 C 400 864 200 776 0 828 Z' fill='%23000'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 900' preserveAspectRatio='none'%3E%3Cpath d='M0 0 H1200 V820 C 1000 880 800 760 600 812 C 400 864 200 776 0 828 Z' fill='%23000'/%3E%3C/svg%3E");
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}

/* ---- cloud: an organic, asymmetric edge ------------------------------ */

/* Eight radii rather than four. A single radius reads as a rounded rectangle
   however large it gets; unequal horizontal and vertical values on each corner
   are what stop the eye finding the circle and make the edge read as drawn. */
.fig--cloud img {
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 58% 42% 48% 52% / 44% 50% 50% 56%;
}
@media (max-width: 599px) {
  /* Gentler on a phone: at small sizes the full blob eats the subject. */
  .fig--cloud img { border-radius: 42% 58% 54% 46% / 46% 44% 56% 54%; }
}

/* ---- bite: something has been nibbling the edges ---------------------- */

/* Six semicircular bites taken out of a rounded rectangle, one or two per
   edge. Drawn as a single outline rather than as circles punched through it:
   CSS mask-image on an SVG reads ALPHA, not luminance, so a black circle over
   the shape would have masked nothing. Each bite is an arc swept the opposite
   way from the corners, which is what turns it from a bump into a bite.

   Chord lengths are exactly twice each radius, so every bite is a true
   semicircle, and the radii differ (62 to 115) so the edge reads as bitten
   rather than as a scalloped pattern.

   The viewBox is 4:3 and so is the photo, so the two scales match and the
   bites stay round however wide the column gets. */
.fig--bite img {
  aspect-ratio: 4 / 3;
  object-fit: cover;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 900' preserveAspectRatio='none'%3E%3Cpath d='M 40,0 L 250,0 A 105,105 0 0 0 460,0 L 720,0 A 68,68 0 0 0 856,0 L 1160,0 A 40,40 0 0 1 1200,40 L 1200,270 A 92,92 0 0 0 1200,454 L 1200,860 A 40,40 0 0 1 1160,900 L 900,900 A 115,115 0 0 0 670,900 L 372,900 A 62,62 0 0 0 248,900 L 40,900 A 40,40 0 0 1 0,860 L 0,600 A 88,88 0 0 0 0,424 L 0,40 A 40,40 0 0 1 40,0 Z' fill='%23000'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 900' preserveAspectRatio='none'%3E%3Cpath d='M 40,0 L 250,0 A 105,105 0 0 0 460,0 L 720,0 A 68,68 0 0 0 856,0 L 1160,0 A 40,40 0 0 1 1200,40 L 1200,270 A 92,92 0 0 0 1200,454 L 1200,860 A 40,40 0 0 1 1160,900 L 900,900 A 115,115 0 0 0 670,900 L 372,900 A 62,62 0 0 0 248,900 L 40,900 A 40,40 0 0 1 0,860 L 0,600 A 88,88 0 0 0 0,424 L 0,40 A 40,40 0 0 1 40,0 Z' fill='%23000'/%3E%3C/svg%3E");
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}

/* ---- pop: the photo rises out of its frame --------------------------- */

/* The first attempt at this put a panel behind the photo and let the photo
   overhang it by 14px. Technically a broken frame; visually just a photo with
   a coloured edge showing, and it was not read as a protrusion by anyone
   looking at it. This version commits:

     - the frame is a real object, filled and outlined, with a flat top edge
     - the photo is an ARCH, not a rectangle, so the part standing above the
       frame has a silhouette rather than a corner
     - it rises 62px clear, which is far enough to be the point of the
       composition rather than a rendering artefact

   A true photographic cut-out still is not possible here: it needs the subject
   on transparency and these are JPEG-derived WebPs with no alpha channel. What
   this does instead is give the photo a shape of its own and break the frame
   with it. Pick a photo whose subject sits high in the frame and set
   object-position to suit, or the arch crops someone's head off. */
.fig--pop { position: relative; padding-top: 62px; }

.fig--pop img {
  position: relative;
  z-index: 1;
  display: block;
  width: 80%;
  margin-inline: auto;
  margin-top: -62px;        /* cancels the padding: the photo starts at the top */
  margin-bottom: 28px;      /* and stops short, so the frame shows beneath it */
  aspect-ratio: 3 / 4;
  object-fit: cover;
  object-position: 50% 18%;
  border-radius: 220px 220px var(--r-sm) var(--r-sm);
  box-shadow: 0 14px 34px rgba(31, 36, 48, 0.22);
}

@media (max-width: 599px) {
  /* Less headroom on a phone, or the arch eats the column. */
  .fig--pop { padding-top: 40px; }
  .fig--pop::before { top: 40px; }
  .fig--pop img { width: 86%; margin-top: -40px; margin-bottom: 20px; }
}

/* ---- photo inside a programme card ----------------------------------- */

/* Full-bleed to the card edge. The negative margin matches .prog's own
   1.7rem/1.5rem padding exactly, and overflow:hidden on the card is what
   clips the photo to the card's radius. .prog--pic keeps all of this off the
   plain .prog cards used on /about and /404. */
.prog--pic { overflow: hidden; }
.prog__pic {
  /* max-width:none is load-bearing. The global `img { max-width: 100% }` caps
     this at the card's content box, so calc(100% + 3rem) silently resolved to
     100% and the photo stopped 48px short of the right edge. */
  max-width: none;
  width: calc(100% + 3rem);
  margin: -1.7rem -1.5rem 1.2rem;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

