/* ==========================================================================
   J & S Tots Pre-School — Munyonyo
   Design system: warm cream, deep cocoa, soft pastel accents, rounded type.
   ========================================================================== */

/* --------------------------------------------------- tokens */
:root {
  color-scheme: light;

  /* surfaces */
  --cream: #faf3e6;
  --cream-2: #f5ebd8;
  --sand: #f7e3bc;
  --paper: #ffffff;

  /* ink */
  --ink: #3b2217;
  --ink-2: #5a3a28;
  --muted: #8a7466;
  --line: rgba(59, 34, 23, 0.12);

  /* brand (taken from the school badge + flyer) */
  --red: #d3262c;
  --navy: #24386f;
  --green: #2e8b57;
  --gold: #f2a71b;

  /* pastels */
  --lav: #c3b2e6;
  --sage: #8fc2ac;
  --peach: #e8a17c;
  --sky: #aec7ec;
  --butter: #f0c96a;

  /* shape */
  --r-sm: 14px;
  --r: 24px;
  --r-lg: 34px;
  --r-xl: 44px;
  --pill: 999px;

  --shadow-xs: 0 2px 8px rgba(59, 34, 23, 0.05);
  --shadow-sm: 0 6px 20px rgba(59, 34, 23, 0.07);
  --shadow: 0 14px 44px rgba(59, 34, 23, 0.1);
  --shadow-lg: 0 28px 80px rgba(59, 34, 23, 0.16);

  /* rhythm */
  --maxw: 1180px;
  --gutter: clamp(1.1rem, 3.2vw, 2rem);
  --section: clamp(4.5rem, 9vw, 8rem);

  /* type */
  --font-display: "Quicksand", "Trebuchet MS", system-ui, sans-serif;
  --font-body: "Nunito", system-ui, -apple-system, "Segoe UI", sans-serif;
  --nav-h: 80px;
  --h1: clamp(1.95rem, 5.6vw, 4.4rem);
  --h2: clamp(1.95rem, 4vw, 3.1rem);
  --h3: clamp(1.35rem, 2.1vw, 1.8rem);
  --lede-size: clamp(1.02rem, 1.35vw, 1.2rem);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-pop: cubic-bezier(0.34, 1.56, 0.64, 1); /* overshoots, for springier motion */
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.015em;
  margin: 0 0 0.6em;
  text-wrap: balance;
}

h1 { font-size: var(--h1); }
h2 { font-size: var(--h2); }
h3 { font-size: var(--h3); letter-spacing: -0.01em; }

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

a { color: inherit; text-decoration: none; }

img, svg { max-width: 100%; display: block; }

ul, ol { margin: 0 0 1.1em; padding-left: 1.2em; }
li { margin-bottom: 0.45em; }

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

::selection { background: var(--butter); color: var(--ink); }

/* --------------------------------------------------- utilities */
.wrap {
  width: min(100% - (var(--gutter) * 2), var(--maxw));
  margin-inline: auto;
}

.wrap-wide {
  width: min(100% - (var(--gutter) * 2), 1440px);
  margin-inline: auto;
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: 50%; top: -100px;
  transform: translateX(-50%);
  background: var(--ink);
  color: #fff;
  padding: 0.7rem 1.3rem;
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  z-index: 200;
  transition: top 0.2s var(--ease);
}
.skip-link:focus { top: 0; }

.eyebrow {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.74rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 1rem;
}

.eyebrow-dot::before {
  content: "";
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--red);
  margin-right: 0.6em;
  vertical-align: 0.1em;
}

.lede {
  font-size: var(--lede-size);
  color: var(--ink-2);
  max-width: 62ch;
}

.muted { color: var(--muted); }
.center { text-align: center; }
.center .lede { margin-inline: auto; }

.section { padding-block: var(--section); }
.section-tight { padding-block: clamp(3rem, 6vw, 5rem); }

.dashed-rule {
  border: 0;
  border-top: 2px dashed var(--line);
  margin: 0;
}

/* --------------------------------------------------- buttons */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.98rem;
  line-height: 1;
  padding: 1.02em 1.7em;
  border-radius: var(--pill);
  border: 2px solid transparent;
  cursor: pointer;
  transition: transform 0.25s var(--ease), background-color 0.25s var(--ease),
              color 0.25s var(--ease), box-shadow 0.25s var(--ease),
              border-color 0.25s var(--ease), scale 0.18s var(--ease);
  white-space: nowrap;
}

.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }

.btn-dark { background: var(--ink); color: #fff; box-shadow: var(--shadow-sm); }
.btn-dark:hover { background: #2c190f; box-shadow: var(--shadow); }

.btn-red { background: var(--red); color: #fff; box-shadow: var(--shadow-sm); }
.btn-red:hover { background: #b81f25; box-shadow: var(--shadow); }

/* the primary calls to action shout; ghost and link buttons stay sentence
   case, so the emphasis still means something */
.btn-dark, .btn-red { text-transform: uppercase; letter-spacing: 0.08em; }

.btn-light {
  background: rgba(255, 255, 255, 0.75);
  color: var(--ink);
  border-color: var(--line);
  backdrop-filter: blur(6px);
}
.btn-light:hover { background: #fff; border-color: rgba(59, 34, 23, 0.25); }

.btn-ghost { background: transparent; color: var(--ink); border-color: var(--line); }
.btn-ghost:hover { border-color: var(--ink); }

.btn-on-dark { background: rgba(255, 255, 255, 0.12); color: #fff; border-color: rgba(255, 255, 255, 0.28); }
.btn-on-dark:hover { background: #fff; color: var(--ink); }

.btn .arrow { transition: transform 0.25s var(--ease); }
.btn:hover .arrow { transform: translateX(3px); }

.btn-sm { padding: 0.78em 1.3em; font-size: 0.9rem; }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 2rem;
}
.center .btn-row { justify-content: center; }

/* --------------------------------------------------- navigation */
.nav-wrap {
  position: sticky;
  top: 0;
  z-index: 100;
  padding-top: clamp(0.7rem, 1.6vw, 1.1rem);
  padding-bottom: 0.4rem;
}

.nav {
  width: min(100% - (var(--gutter) * 2), 1180px);
  margin-inline: auto;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(14px) saturate(140%);
  border-radius: var(--pill);
  box-shadow: var(--shadow-sm);
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.5rem 0.55rem 0.5rem 1.1rem;
  transition: box-shadow 0.3s var(--ease), background-color 0.3s var(--ease);
}

.nav-wrap.is-stuck .nav { box-shadow: var(--shadow); background: rgba(255, 255, 255, 0.97); }

.brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-right: auto;
  flex-shrink: 0;
}

.brand-mark { width: 40px; height: 40px; flex: none; }

.brand-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.12rem;
  letter-spacing: -0.02em;
  line-height: 1.05;
}
.brand-name strong { color: var(--red); font-weight: 700; }
.brand-name span { display: block; font-size: 0.62rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); font-family: var(--font-body); font-weight: 700; }

.nav-menu {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav-menu li { margin: 0; }

.nav-menu a {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  padding: 0.6rem 0.95rem;
  border-radius: var(--pill);
  color: var(--ink-2);
  transition: background-color 0.2s var(--ease), color 0.2s var(--ease);
}
.nav-menu a:hover { background: var(--cream-2); color: var(--ink); }
.nav-menu a[aria-current="page"] { color: var(--ink); background: var(--cream-2); }

.nav-cta { margin-left: 0.4rem; }

/* the drawer's own call to action only exists in the mobile menu */
.nav-menu-cta { display: none; }

.nav-toggle {
  display: none;
  width: 46px; height: 46px;
  border: 0;
  border-radius: 50%;
  background: var(--cream-2);
  cursor: pointer;
  position: relative;
  flex: none;
}
.nav-toggle .bars,
.nav-toggle .bars::before,
.nav-toggle .bars::after {
  position: absolute;
  left: 50%;
  width: 18px; height: 2.4px;
  background: var(--ink);
  border-radius: 2px;
  transform: translateX(-50%);
  transition: transform 0.28s var(--ease), opacity 0.2s var(--ease);
}
.nav-toggle .bars { top: 50%; margin-top: -1.2px; }
.nav-toggle .bars::before { content: ""; top: -6px; }
.nav-toggle .bars::after { content: ""; top: 6px; }

.nav-toggle[aria-expanded="true"] .bars { background: transparent; }
.nav-toggle[aria-expanded="true"] .bars::before { transform: translateX(-50%) translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .bars::after { transform: translateX(-50%) translateY(-6px) rotate(-45deg); }

/* --------------------------------------------------- hero */
/* The hero pins while the rest of the page rides up over it. This is plain
   sticky positioning rather than an animation, so the overlap itself works in
   every browser — only the dimming behind the sheet needs scroll-driven
   animation support. */
.hero { padding-top: 0; position: sticky; top: 0; z-index: 0; }

.after-hero {
  position: relative;
  z-index: 1;
  background: var(--cream);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  box-shadow: 0 -16px 44px rgba(59, 34, 23, 0.14);
}

/* --------------------------------------------------- the pupil in the CTA
   She used to straddle the hero seam. The cast now stands along that floor,
   so she moved to the CTA panel, whose own overflow:hidden crops her cleanly
   against the panel edge. */
.cta .slot-pupil {
  position: absolute;
  /* left+right+auto margins centres her without touching `translate`, which
     pupil-arrive animates — a centring translate would simply be overwritten */
  left: 0;
  right: 0;
  margin-inline: auto;
  bottom: 0;
  width: var(--pupil-w);
  pointer-events: none;
  transform-origin: bottom center;
}
.pupil { display: block; width: 100%; height: auto; }

/* --------------------------------------------------- the photo rim
   Every cut-out carries the same sticker edge: four drop-shadows build a white
   rim, four more put the brand colours just outside it, and the last lifts it
   off the page. Each applies to the RESULT of the previous, which is what makes
   concentric rings rather than one flat halo. Static, so it rasterises once. */
.pupil,
.cast {
  /* just the white sticker edge and a lift now — the brand colours moved to
     the floating stroke behind, which halves the filter passes as well */
  --rim: 2px;
  filter:
    drop-shadow(var(--rim) 0 0 #fff) drop-shadow(calc(var(--rim) * -1) 0 0 #fff)
    drop-shadow(0 var(--rim) 0 #fff) drop-shadow(0 calc(var(--rim) * -1) 0 #fff)
    drop-shadow(0 16px 20px rgba(59, 34, 23, 0.32));
}



/* The hero is a stage: badge, news pill and headline in the upper half, and
   the cast standing on the floor breaking the bottom of the type — the move
   every one of the reference posters makes. The box carries the hero's own
   height, since there is no full-bleed picture left to set it. */
.hero-media {
  position: relative;
  width: min(100% - (var(--gutter) * 2), 1440px);
  margin-inline: auto;
  margin-top: calc(var(--nav-h) * -1);
  border-radius: var(--r-xl);
  overflow: hidden;
  /* the warm glow of the reference poster, over the brand's own amber */
  background:
    radial-gradient(86% 64% at 50% 112%, rgba(255, 255, 255, 0.48) 0%, transparent 58%),
    radial-gradient(70% 55% at 50% 12%, #ffd89c 0%, transparent 72%),
    linear-gradient(168deg, #f6a93f 0%, #ef7a2a 46%, #df5220 100%);
  box-shadow: var(--shadow);
  /* floor and ceiling both: tall enough that the sheet stays off screen at
     scroll 0, short enough that the wording stays on it */
  min-height: 96vh; /* fallback for browsers without lvh */
  min-height: max(470px, 96lvh);
  max-height: 96vh;
  max-height: 96lvh;
}

.hero-overlay {
  position: relative;
  z-index: 2;
  min-width: 0;
  padding: calc(var(--nav-h) + 0.1rem) clamp(1.2rem, 4vw, 3.2rem) 0;
  color: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.45rem;
}

.hero-badge {
  width: clamp(36px, 3.6vw, 54px);
  height: auto;
  filter: drop-shadow(0 6px 14px rgba(90, 34, 8, 0.32));
}

/* the pill inherits align-self: flex-start from the old left-aligned hero;
   this stage is centred, so it has to be told */
.hero-overlay .ticker { align-self: center; }

/* Bolder than the site default: larger, tighter tracking and a shorter
   measure, so it lands as a statement rather than a sentence. */
.hero-overlay h1 {
  position: relative;
  z-index: 0;
  color: #fff;
  margin: 0;
  max-width: 17ch;
  font-size: clamp(2.1rem, 5.4vw, 4.25rem);
  letter-spacing: -0.03em;
  line-height: 0.99;
  text-shadow: 0 3px 22px rgba(110, 42, 10, 0.32);
}

/* A marker stroke behind two words, in the spirit of the reference poster.
   The text stays white on a solid brand red, so the accent costs nothing in
   contrast — tinting the words themselves would have. The four corner radii
   differ so the bar reads as drawn by hand rather than set by a computer. */
/* --------------------------------------------------- crayon highlights
   A waxy marker stroke behind the words that matter. The texture is an SVG
   turbulence filter rather than an image, so it costs nothing to download and
   stays sharp at any size; the displacement roughens the bar's edges the way
   a crayon skips over paper. The four corner radii differ so the shape reads
   as drawn rather than set. */
.hl {
  position: relative;
  z-index: 0;
  white-space: nowrap;
}
.hl::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0.1em -0.24em 0.06em -0.24em;
  background: var(--red);
  border-radius: 0.5em 0.42em 0.55em 0.38em;
  rotate: -1.1deg;
  filter: url("#crayon");
  transform-origin: left center;
}
.hero-overlay h1 .hl::before { box-shadow: 0 6px 16px rgba(120, 30, 10, 0.25); }
.cta h2 .hl { color: #fff; }

/* A highlighter pen rather than a marker bar. .hl lays solid red behind white
   wording, which only works where the wording is already white; on the cream
   pages the same treatment would bury the words. This one is translucent gold,
   so dark text reads straight through it and one class can mark key points
   anywhere on the site. It joins the same draw-on-reveal and wobble as .hl
   below, so a page does not end up with two different crayon behaviours. */
.mark {
  position: relative;
  z-index: 0;
  white-space: nowrap;
}
.mark::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0.14em -0.22em 0.04em -0.22em;
  background: var(--gold);
  opacity: 0.45;
  border-radius: 0.46em 0.38em 0.52em 0.34em;
  rotate: -0.9deg;
  filter: url("#crayon");
  transform-origin: left center;
}
/* Inline accents get an underline rather than a full bar, so body copy stays
   readable.

   It is a background on the inline box, not an absolutely positioned ::after.
   A bar cannot follow a phrase that wraps: the containing block of an
   absolutely positioned child of a wrapped inline is the union of its
   fragments, so on a phone "opposite Munyonyo C.O.U. Church" drew a 162px
   underline that matched neither of its two lines, and "right here in
   Munyonyo" drew one 3px wide. A background with box-decoration-break: clone
   gives every line its own rule, the full width of that line.

   The cost is the crayon texture — a filter here would roughen the words along
   with the rule beneath them. .hl and .mark keep it: they mark short phrases
   chosen not to wrap. */
.shout {
  padding-bottom: 0.1em;
  background-image: linear-gradient(var(--gold), var(--gold));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 0.24em;
  border-radius: 0.3em;
  -webkit-box-decoration-break: clone;
          box-decoration-break: clone;
}

/* --------------------------------------------------- the cast
   Absolutely positioned on purpose: four photographs must never be the thing
   that decides how tall the hero is. Letting a picture drive that height is
   the fault that put the wording below the fold twice already. */
/* --------------------------------------------------- the cast on the seam
   All three stand on the line where the sheet climbs over the pinned hero,
   not on the hero's own floor. The sheet does no overflow clipping and sits
   at z-index 1 over the hero's 0, so they hang above that line as whole
   figures and paint in front of everything in the hero.

   Sized to stand side by side without touching. With their height multipliers
   the three together measure about 2.07x the row height, so at the 140px floor
   they come to 310px -- inside the 367px a 390px phone leaves once the padding
   is off. The 280px cap stops them growing into the sheet on a large monitor.

   The offset is a negative `top`, not a translate: the scroll animation owns
   translate and would overwrite a positioning one -- the trap the CTA pupil
   fell into. */
.seam-cast {
  --cast-h: clamp(150px, 17vw, 280px);
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--cast-h) * -0.55);
  display: flex;
  align-items: flex-end;
  /* Together, not spread. space-between put one at each corner of a 1425px
     row with 400px of bare seam between them, which is not side by side. A
     proportional gap keeps them a group at any width: about 12px apart on a
     phone, 43px on a desktop. */
  justify-content: center;
  gap: clamp(0.5rem, 3vw, 4rem);
  /* mirrors the hero card's own inset, so they line up with its edges */
  padding-inline: calc(max(var(--gutter), (100% - 1440px) / 2) + 1.2rem);
  pointer-events: none;
}

/* The slot is the flex item and carries the width; the photograph just fills
   it. The slot exists so there is something to hang the floating stroke on —
   an <img> is a replaced element and will not render ::before. */
.cast-slot {
  /* one home for the two stroke opacities: the reveal rules below repeat
     them, and a mismatch would show as a jump when the stroke fades in */
  --stroke-in: 1;
  --stroke-out: 0.85;
  position: relative;
  z-index: 0;
  display: block;
  /* min-width:0 lets them shrink together rather than overflow the row on a
     narrow screen; heights follow the aspect ratio, so they shorten with it */
  min-width: 0;
}

.cast {
  display: block;
  height: 100%;
  width: auto;
}

/* --------------------------------------------------- the floating stroke
   A two-colour copy of the child's own silhouette, drifting behind them. The
   photograph is used as the mask, so the shape follows the cut-out instead of
   being a disc behind it, and scaling it past 1 makes it read as a stroke
   peeking out around the edges. Only transform properties animate, so it is
   all compositor work and nothing repaints.

   z-index -1 inside the slot's own stacking context keeps it behind the
   photograph and still in front of the hero background. */
.cast-slot::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(142deg, var(--b1) 0%, var(--b2) 100%);
  -webkit-mask-image: var(--img);
          mask-image: var(--img);
  -webkit-mask-size: contain;
          mask-size: contain;
  -webkit-mask-position: bottom center;
          mask-position: bottom center;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  /* Grow it about its own centre, not its feet. Anchoring at bottom centre
     pushed a 400px-tall silhouette ~58px upward at 1.1, which read as a ghost
     standing behind the child rather than an outline around them. From the
     centre a far smaller scale gives an even edge all the way round. */
  transform-origin: center;
  scale: 1.09;
  opacity: var(--stroke-in);
}
/* A second, wider stroke in the brand red sits behind the gradient one, so the
   edge reads as two layers rather than one. Same mask, larger scale, lower
   opacity; z-index -2 puts it behind ::before, which is at -1. */
.cast-slot::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  background: var(--red);
  -webkit-mask-image: var(--img);
          mask-image: var(--img);
  -webkit-mask-size: contain;
          mask-size: contain;
  -webkit-mask-position: bottom center;
          mask-position: bottom center;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  transform-origin: center;
  scale: 1.18 1.1;
  opacity: var(--stroke-out);
}
.js .cast-slot::after { opacity: 0; }
.js .cast-slot.is-ready::after {
  opacity: var(--stroke-out);
  transition: opacity 0.45s var(--ease);
}


/* Until the mask image has decoded there is nothing to cut the shape with, so
   ::before paints its whole box and you get a brief coloured rectangle behind
   each child. Each slot reveals its own stroke when its own picture has
   arrived, so a lazy image that is still off screen simply stays hidden. */
.js .cast-slot::before { opacity: 0; }
.js .cast-slot.is-ready::before {
  opacity: var(--stroke-in);
  transition: opacity 0.45s var(--ease);
}

/* two brand colours each, and the photograph that cuts the shape */
/* Every stroke now ends in the brand red, the way the CTA one does, so the
   cut-outs read as one family instead of four unrelated pairs. The first stop
   still differs per child, so each keeps two colours. */
.slot-desk  { --b1: var(--gold);   --b2: var(--red); --img: url("../img/kid-desk.webp"); }
.slot-jump  { --b1: var(--sky);    --b2: var(--red); --img: url("../img/kid-jump.webp"); }
.slot-grad  { --b1: var(--butter); --b2: var(--red); --img: url("../img/kid-grad.webp"); }
.slot-hand  { --b1: var(--peach);  --b2: var(--red); --img: url("../img/kid-hand.webp"); }
.slot-pupil { --b1: var(--gold);   --b2: var(--red); --img: url("../img/pupil.webp"); }

/* Sized per crop: the desk shot is landscape and sits low, the graduate is
   the tallest and anchors the middle. Her width sets how far the cast rises
   into the headline, because she is the tallest: at 22vw the overlap reached
   66px and her cap swallowed the last word of the line, so she is trimmed to
   land around 40px, which clips the type without hiding any of it. */
.cast-slot { height: calc(var(--cast-h) * var(--h, 1) * var(--cast-scale, 1)); }
.slot-desk { --h: 0.58; }
.slot-jump { --h: 0.92; }
.slot-grad { --h: 1; }
.slot-hand { --h: 0.96; }

/* No negative margin any more: space-evenly does the spacing, and the row is
   kept inside the card by the width term in --cast-h instead. */

.hero-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 0.2rem;
}

/* Short labels carry caps well; long headings do not, so this treatment is
   kept to chips, the primary buttons and the inline .shout accent below. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.5em 0.95em;
  border-radius: var(--pill);
  background: rgba(255, 255, 255, 0.92);
  color: var(--ink);
}
.chip-red { background: var(--red); color: #fff; }
.chip-navy { background: var(--navy); color: #fff; }

/* inline accent for a short key phrase inside body copy — two or three
   words at most, or it stops being emphasis and starts being noise */
.shout {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--red);
}
.chip-green { background: var(--green); color: #fff; }
.chip-gold { background: var(--gold); color: var(--ink); }

/* news ticker pill */
.ticker {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  align-self: flex-start;
  max-width: 100%;
  background: rgba(30, 16, 9, 0.82);
  backdrop-filter: blur(10px);
  color: #fff;
  border-radius: var(--pill);
  padding: 0.42rem 1.1rem 0.42rem 0.42rem;
  font-size: 0.9rem;
}

.ticker-badge {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  background: #fff;
  color: var(--ink);
  border-radius: var(--pill);
  padding: 0.42em 0.9em;
  flex: none;
}

.ticker-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
}
.ticker-text.is-out { opacity: 0; transform: translateY(-6px); }

/* --------------------------------------------------- page hero (inner pages) */
.page-hero {
  padding-top: clamp(2.6rem, 6vw, 4.6rem);
  padding-bottom: clamp(2rem, 4vw, 3rem);
  text-align: center;
}
.page-hero h1 { max-width: 18ch; margin-inline: auto; }
.page-hero .lede { margin-inline: auto; }

.crumbs {
  font-size: 0.82rem;
  color: var(--muted);
  margin-bottom: 1.1rem;
  font-weight: 600;
}
.crumbs a:hover { color: var(--ink); text-decoration: underline; }
.crumbs span { margin-inline: 0.45em; opacity: 0.5; }

/* --------------------------------------------------- feature icon row */
.feature-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(1.5rem, 3vw, 2.6rem);
  text-align: center;
}

.feature {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
}

.feature-icon {
  width: 60px; height: 60px;
  margin-bottom: 0.3rem;
  stroke-width: 2.4;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.feature:nth-child(1) .feature-icon { stroke: var(--peach); }
.feature:nth-child(2) .feature-icon { stroke: var(--lav); }
.feature:nth-child(3) .feature-icon { stroke: var(--sage); }
.feature:nth-child(4) .feature-icon { stroke: var(--gold); }

.feature h3 {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.82rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  margin: 0;
}

.feature p { color: var(--muted); font-size: 0.96rem; max-width: 26ch; margin: 0; }

/* --------------------------------------------------- split section */
.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}

.split-media { position: relative; }

.split-media img {
  width: 100%;
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
}

.split.is-reversed .split-media { order: 2; }

/* A cut-out photograph in place of the illustration that used to sit here.
   The illustration carried its own pale ground; the photograph has a
   transparent one, so without a backdrop the rounded corners and the shadow
   would be drawn around nothing and she would float on the cream. The frame
   supplies the colour the illustration used to, and the picture keeps its
   alpha so she still reads as a cut-out rather than a pasted rectangle.

   No overflow: hidden here — the ring and bulb doodles are positioned to hang
   over this box's edges on purpose, and clipping would cut them in half. */
.split-media-photo {
  /* How far her head climbs above the frame. A percentage margin resolves
     against the containing block WIDTH, not its height — which suits this: the
     picture holds a fixed 1.78 ratio, so a share of the width is a fixed share
     of the picture as well, and the protrusion stays put at every screen size.
     18% of the width is about 32% of her height, which puts the frame line
     behind her chin: her whole head clears it, rather than the line cutting
     across her forehead. */
  --protrude: 18%;
  background:
    linear-gradient(168deg,
      color-mix(in srgb, var(--sage) 34%, #fff) 0%,
      color-mix(in srgb, var(--sage) 16%, #fff) 100%);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
}
/* She breaks the top of the frame rather than sitting inside it. Pulling the
   picture up by a negative margin takes the frame height with it, because the
   picture is its only in-flow content — so the tinted ground stops at her
   shoulders while she carries on above it. The cut-out alpha is what makes it
   read: only her head and hair paint above the line, not a rectangle of photo.

   The drop-shadow follows that same alpha, so what falls on the panel is her
   silhouette rather than a box, and she lifts off it instead of being pasted
   on. The frame keeps its own box-shadow for the panel itself. */
.split-media-photo img {
  box-shadow: none;
  display: block;
  margin-top: calc(var(--protrude) * -1);
  filter: drop-shadow(0 12px 16px rgba(59, 34, 23, 0.26));
  /* .split-media img sets width: 100% and no height, so the HTML height
     attribute is taken as the CSS height. The SVGs that rule was written for
     letterbox inside that box and look unharmed; a photograph instead squashes
     — this one rendered 554x505 against a natural 900x505, a 1.10 ratio where
     it should be 1.78. Scoped here rather than fixed on .split-media img,
     which would relayout the illustrations on three other pages. */
  height: auto;
}


/* hand-drawn doodle decorations, like the reference */
.doodle {
  position: absolute;
  pointer-events: none;
  z-index: 2;
}
.doodle-ring { width: 150px; right: -32px; bottom: -34px; color: var(--lav); }
.doodle-bulb { width: 92px; left: -34px; top: -30px; color: var(--gold); }
.doodle-star { width: 70px; right: -20px; top: -26px; color: var(--sage); }

/* --------------------------------------------------- hero doodles
   The corners that the wording and the graduate leave empty, filled with the
   furniture of a classroom wall: a sun, two clouds, a paper plane on a dotted
   trail, a balloon, a letter brick, a crayon squiggle and a rainbow coming up
   off the floor.

   The group is its own stacking context at z-index 1, which is what lets the
   shared .doodle z-index 2 go on ordering these among themselves while the
   whole lot stays behind the wording (2) and the cast (3).

   Every position is a percentage. The card is sized against the viewport, so
   anything placed in pixels would wander across the art as the window
   changes; --dw does the same job for size, one clamp per shape. */
.hero-doodles {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  pointer-events: none;
  border-radius: inherit;
}
.hero-doodles .doodle { width: var(--dw); }
.hero-doodles .doodle svg { display: block; width: 100%; height: auto; }

.d-sun      { --dw: clamp(54px, 7vw, 104px);   left: 5%;   top: 13%;     color: var(--butter); opacity: 0.9; }
.d-cloud-a  { --dw: clamp(60px, 9.5vw, 142px); left: 12%;  top: 26%;     color: #fff; opacity: 0.34; }
.d-cloud-b  { --dw: clamp(56px, 8vw, 118px);   right: 6%;  top: 9.5%;    color: #fff; opacity: 0.3; }
.d-plane    { --dw: clamp(34px, 4.6vw, 64px);  right: 6%;  top: 26%;     color: #fff; opacity: 0.92; }
.d-trail    { --dw: clamp(74px, 10vw, 150px);  right: 11%; top: 33%;     color: #fff; opacity: 0.42; }
.d-balloon  { --dw: clamp(36px, 5vw, 70px);    left: 41%;  top: 50%;     color: var(--red); opacity: 0.88; }
.d-squiggle { --dw: clamp(62px, 9vw, 136px);   left: 4%;   top: 37%;     color: var(--red); opacity: 0.68; }
.d-rainbow  { --dw: clamp(78px, 16vw, 240px);  left: 38%;  bottom: -4%;  opacity: 0.58; }
.d-star-a   { --dw: clamp(16px, 2.2vw, 30px);  left: 47%;  top: 49%;     color: #fff; }
.d-star-b   { --dw: clamp(13px, 1.8vw, 25px);  right: 4%;  top: 44%;     color: var(--butter); }
.d-star-c   { --dw: clamp(15px, 2vw, 28px);    left: 52%;  top: 66%;     color: #fff; }

/* --------------------------------------------------- name blocks
   The school name as a row of toy bricks. Static styling only; the bounce
   and the eyes live in the motion section, behind the reduced-motion guard,
   so this still looks deliberate when it never moves. */
.blocks {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: clamp(0.35rem, 1.1vw, 0.65rem);
  margin: 0;
  padding: 0;
}

.block-gap { width: clamp(0.5rem, 2vw, 1.4rem); }

.block {
  --size: clamp(50px, 8.5vw, 86px);
  --g: #fff;
  position: relative;
  width: var(--size);
  height: var(--size);
  border-radius: clamp(11px, 1.8vw, 18px);
  background: var(--c);
  color: var(--g);
  /* the flat drop under each brick is what makes it read as a toy block
     rather than a button */
  box-shadow: 0 5px 0 rgba(59, 34, 23, 0.18), var(--shadow-sm);
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(var(--size) * 0.5);
  line-height: 1;
  user-select: none;
  transition: rotate 0.25s var(--ease-pop), scale 0.25s var(--ease-pop);
}

/* every brick sits a little crooked, like they were set down by hand */
.block:nth-child(odd) { rotate: -3deg; }
.block:nth-child(even) { rotate: 2.6deg; }
.block:hover { rotate: 0deg; scale: 1.08; }

.block .glyph { grid-area: 1 / 1; }

/* on a brick with eyes the letter drops to make room for the face */
.has-eyes .glyph { margin-top: 26%; font-size: 0.8em; }

.eyes {
  grid-area: 1 / 1;
  align-self: start;
  margin-top: 15%;
  display: flex;
  gap: 0.28em;
  font-size: calc(var(--size) * 0.26);
}
.eyes i {
  position: relative;
  width: 1em;
  height: 1em;
  border-radius: 50%;
  background: #fff;
  box-shadow: inset 0 0.08em 0.12em rgba(59, 34, 23, 0.28);
}
.eyes i::after {
  content: "";
  position: absolute;
  width: 0.44em;
  height: 0.44em;
  border-radius: 50%;
  background: var(--ink);
  top: 30%;
  left: 28%;
}

/* Below roughly 430px the seven bricks no longer fit on one line, and left to
   itself flex-wrap breaks wherever it runs out of room — which split TOTS as
   "T O / T S". Turning the gap into a full-width break makes the name stack as
   J&S over TOTS instead. */
@media (max-width: 480px) {
  .block-gap { flex-basis: 100%; width: 0; height: 0; }
}

.stat-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  gap: 1.5rem 1.4rem;
  margin-top: 2.2rem;
  padding-top: 1.8rem;
  border-top: 2px dashed var(--line);
}

.stat strong {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 2.1vw, 1.9rem);
  line-height: 1;
  color: var(--red);
  margin-bottom: 0.25rem;
}
.stat span { font-size: 0.86rem; color: var(--muted); font-weight: 600; }

/* --------------------------------------------------- cards */
.card {
  background: var(--paper);
  color: var(--ink); /* cards keep their own ink inside .band-dark */
  border-radius: var(--r-lg);
  padding: clamp(1.6rem, 2.6vw, 2.3rem);
  box-shadow: var(--shadow-xs);
  border: 1px solid rgba(59, 34, 23, 0.06);
  transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease);
}
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow); }

.card-icon {
  width: 54px; height: 54px;
  border-radius: 18px;
  display: grid;
  place-items: center;
  margin-bottom: 1.1rem;
  flex: none;
}
.card-icon svg { width: 27px; height: 27px; fill: none; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }

.tint-lav { background: color-mix(in srgb, var(--lav) 38%, #fff); }
.tint-lav svg { stroke: #6f55b0; }
.tint-sage { background: color-mix(in srgb, var(--sage) 38%, #fff); }
.tint-sage svg { stroke: #2f7d63; }
.tint-peach { background: color-mix(in srgb, var(--peach) 38%, #fff); }
.tint-peach svg { stroke: #b65f31; }
.tint-sky { background: color-mix(in srgb, var(--sky) 42%, #fff); }
.tint-sky svg { stroke: #3a5a93; }
.tint-butter { background: color-mix(in srgb, var(--butter) 42%, #fff); }
.tint-butter svg { stroke: #9a7314; }
.tint-red { background: color-mix(in srgb, var(--red) 16%, #fff); }
.tint-red svg { stroke: var(--red); }

.card h3 { margin-bottom: 0.45rem; }
.card p { color: var(--muted); font-size: 0.97rem; }

.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1rem, 2vw, 1.6rem); }
.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(1rem, 2vw, 1.6rem); }

/* --------------------------------------------------- dark band */
.band-dark {
  background: var(--ink);
  color: #fff;
  border-radius: var(--r-xl);
  padding: clamp(2.6rem, 6vw, 5rem) 0;
  width: min(100% - (var(--gutter) * 2), 1440px);
  margin-inline: auto;
  overflow: hidden;
}
.band-dark h2 { color: #fff; max-width: 18ch; }
.band-dark .eyebrow { color: rgba(255, 255, 255, 0.6); }
.band-dark .lede { color: rgba(255, 255, 255, 0.78); }
.band-dark .dashed-rule { border-color: rgba(255, 255, 255, 0.18); }

.band-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 2rem;
  margin-bottom: clamp(1.8rem, 3vw, 2.6rem);
}

/* --------------------------------------------------- carousel */
.carousel { position: relative; }

.carousel-track {
  display: flex;
  gap: clamp(1rem, 2vw, 1.5rem);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding-bottom: 0.6rem;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.carousel-track::-webkit-scrollbar { display: none; }

.carousel-track > * {
  scroll-snap-align: start;
  flex: 0 0 min(560px, 82%);
}

.carousel-nav { display: flex; gap: 0.6rem; flex: none; }

.c-btn {
  width: 50px; height: 50px;
  border-radius: 50%;
  border: 2px solid var(--line);
  background: transparent;
  color: inherit;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background-color 0.25s var(--ease), color 0.25s var(--ease),
              border-color 0.25s var(--ease), opacity 0.25s var(--ease);
}
.c-btn svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.c-btn:hover { background: var(--ink); color: #fff; border-color: var(--ink); }
.c-btn[disabled] { opacity: 0.32; cursor: default; }
.c-btn[disabled]:hover { background: transparent; color: inherit; border-color: var(--line); }

.band-dark .c-btn { border-color: rgba(255, 255, 255, 0.3); }
.band-dark .c-btn:hover { background: #fff; color: var(--ink); border-color: #fff; }
.band-dark .c-btn[disabled]:hover { background: transparent; color: #fff; border-color: rgba(255, 255, 255, 0.3); }

/* programme card inside carousel */
.prog-card {
  background: var(--paper);
  border-radius: var(--r-lg);
  overflow: hidden;
  display: grid;
  grid-template-columns: 38% 1fr;
  color: var(--ink);
  min-height: 272px;
}
.prog-card img { width: 100%; height: 100%; object-fit: cover; }
.prog-body { padding: clamp(1.4rem, 2.4vw, 2rem); display: flex; flex-direction: column; }
.prog-body .eyebrow { margin-bottom: 0.5rem; }
.prog-body h3 { font-size: clamp(1.4rem, 2.2vw, 1.85rem); margin-bottom: 0.5rem; }
.prog-body p { color: var(--muted); font-size: 0.95rem; }
.prog-body .btn { margin-top: auto; align-self: flex-start; }

/* --------------------------------------------------- values list */
.value-list { list-style: none; margin: 0; padding: 0; }

.value-item {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: clamp(1rem, 2.4vw, 1.8rem);
  padding: clamp(1.4rem, 2.6vw, 2rem) 0;
  border-top: 2px dashed var(--line);
  margin: 0;
  align-items: start;
}
.value-item:last-child { border-bottom: 2px dashed var(--line); }

.value-num {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  color: var(--red);
  padding-top: 0.5rem;
  min-width: 3ch;
}
.value-item h3 { margin-bottom: 0.4rem; }
.value-item p { color: var(--muted); max-width: 70ch; }

/* --------------------------------------------------- day flow */
.flow { display: grid; gap: 0; }

.flow-row {
  display: grid;
  grid-template-columns: 170px 1fr;
  gap: clamp(1rem, 3vw, 2.4rem);
  padding: clamp(1.1rem, 2.2vw, 1.6rem) 0;
  border-top: 2px dashed var(--line);
  align-items: baseline;
}
.flow-row:last-child { border-bottom: 2px dashed var(--line); }

.flow-time {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--ink);
  font-size: 1rem;
}
.flow-row h3 { font-size: 1.1rem; margin-bottom: 0.25rem; }
.flow-row p { color: var(--muted); font-size: 0.96rem; }

/* --------------------------------------------------- day-flow icons
   The time column is 170px wide and the time itself uses about 70 of them, so
   each activity's icon goes at that column's right-hand end — beside the thing
   it illustrates, and without a column of its own, which would have come out
   of the description's width. */
.flow-time {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
}
.flow-icon {
  flex: none;
  width: clamp(26px, 3vw, 34px);
  line-height: 0;
  transform-origin: 50% 85%;
}
.flow-icon svg { display: block; width: 100%; height: auto; }

.fi-wave   { color: var(--gold); }
.fi-note   { color: var(--navy); }
.fi-pencil { color: var(--gold); }
.fi-apple  { color: var(--red); }
.fi-kite   { color: var(--navy); }
.fi-ball   { color: var(--green); }
.fi-bowl   { color: var(--green); }
.fi-house  { color: var(--navy); }

/* --------------------------------------------------- testimonials */
.quote-card {
  background: var(--paper);
  color: var(--ink);
  border-radius: var(--r-lg);
  padding: clamp(1.7rem, 3vw, 2.5rem);
  box-shadow: var(--shadow-xs);
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  min-height: 100%;
}

.quote-card blockquote {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.08rem, 1.7vw, 1.32rem);
  line-height: 1.45;
  color: var(--ink);
}

.quote-by { display: flex; align-items: center; gap: 0.85rem; margin-top: auto; }

.avatar {
  width: 48px; height: 48px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1rem;
  color: var(--ink);
  flex: none;
}

.quote-by strong { display: block; font-family: var(--font-display); font-size: 1rem; }
.quote-by span { font-size: 0.86rem; color: var(--muted); }

/* --------------------------------------------------- tilted cards (why choose us) */
.tilt-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2vw, 1.5rem);
}

.tilt {
  border-radius: var(--r-lg);
  padding: clamp(1.6rem, 2.6vw, 2.2rem);
  min-height: 230px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  color: var(--ink);
  transition: rotate 0.4s var(--ease), translate 0.4s var(--ease), box-shadow 0.4s var(--ease);
  box-shadow: var(--shadow-xs);
}
.tilt:nth-child(1) { background: color-mix(in srgb, var(--sage) 55%, #fff); rotate: -1.6deg; }
.tilt:nth-child(2) { background: color-mix(in srgb, var(--sky) 55%, #fff); rotate: 0.9deg; }
.tilt:nth-child(3) { background: color-mix(in srgb, var(--peach) 58%, #fff); rotate: -0.7deg; }
.tilt:hover { rotate: 0deg; translate: 0 -6px; box-shadow: var(--shadow); }

.tilt h3 { margin-bottom: 0.4rem; }
.tilt p { color: rgba(59, 34, 23, 0.72); font-size: 0.97rem; }

/* --------------------------------------------------- embedded map */
.map-embed {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--cream-2);
  box-shadow: var(--shadow-sm);
  border: 1px solid rgba(59, 34, 23, 0.08);
}

/* opaque, so the frame reads as a loading panel rather than a broken box
   while the tiles arrive. If it never loads, the two buttons beside it
   still take the parent straight to Google Maps. */
.map-embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  background: var(--cream-2);
}

@media (max-width: 900px) {
  .map-embed { aspect-ratio: 3 / 2; }
}

/* --------------------------------------------------- CTA band */
.cta {
  background: var(--sand);
  border-radius: var(--r-xl);
  padding: clamp(2.4rem, 5.5vw, 4.4rem) clamp(1.6rem, 5vw, 4rem);
  width: min(100% - (var(--gutter) * 2), 1180px);
  margin-inline: auto;
  text-align: center;
  position: relative;
  overflow: hidden;
}
.cta h2 { max-width: 20ch; margin-inline: auto; }
.cta .lede { margin-inline: auto; }

.cta-phone {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.3rem, 2.6vw, 1.9rem);
  color: var(--red);
  margin-top: 0.4rem;
}
.cta-phone svg { width: 24px; height: 24px; stroke: currentColor; fill: none; stroke-width: 1.9; }

/* --------------------------------------------------- accordion */
.acc { border-top: 2px dashed var(--line); }
.acc-item { border-bottom: 2px dashed var(--line); }

.acc-btn {
  width: 100%;
  background: none;
  border: 0;
  text-align: left;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.02rem, 1.6vw, 1.18rem);
  color: var(--ink);
  padding: 1.25rem 2.6rem 1.25rem 0;
  cursor: pointer;
  position: relative;
  line-height: 1.35;
}
.acc-btn::after {
  content: "";
  position: absolute;
  right: 0.4rem; top: 50%;
  width: 13px; height: 13px;
  margin-top: -9px;
  border-right: 2.4px solid var(--muted);
  border-bottom: 2.4px solid var(--muted);
  transform: rotate(45deg);
  transition: transform 0.3s var(--ease);
}
.acc-btn[aria-expanded="true"]::after { transform: rotate(-135deg); margin-top: -4px; }

.acc-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.35s var(--ease);
}
.acc-panel > div { overflow: hidden; }
.acc-item.is-open .acc-panel { grid-template-rows: 1fr; }
.acc-panel p { color: var(--muted); padding-bottom: 1.4rem; max-width: 72ch; }

/* --------------------------------------------------- forms */
.form-card {
  background: var(--paper);
  border-radius: var(--r-lg);
  padding: clamp(1.6rem, 3vw, 2.6rem);
  box-shadow: var(--shadow-xs);
}

.field { margin-bottom: 1.1rem; }

.field label {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.88rem;
  margin-bottom: 0.4rem;
}

.field input,
.field select,
.field textarea {
  width: 100%;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--ink);
  background: var(--cream);
  border: 2px solid transparent;
  border-radius: var(--r-sm);
  padding: 0.85rem 1rem;
  transition: border-color 0.2s var(--ease), background-color 0.2s var(--ease);
}
.field textarea { min-height: 128px; resize: vertical; }
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--navy);
  background: #fff;
}
.field input::placeholder, .field textarea::placeholder { color: color-mix(in srgb, var(--muted) 70%, #fff); }

.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }

.form-note { font-size: 0.86rem; color: var(--muted); margin-top: 0.9rem; }

.form-status {
  margin-top: 1rem;
  padding: 0.9rem 1.1rem;
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--sage) 28%, #fff);
  font-size: 0.93rem;
  font-weight: 600;
  display: none;
}
.form-status.is-shown { display: block; }
.form-status.is-error { background: color-mix(in srgb, var(--red) 12%, #fff); color: #92191e; }

/* --------------------------------------------------- contact details */
.detail-list { list-style: none; margin: 0; padding: 0; }

.detail {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1rem;
  padding: 1.15rem 0;
  border-bottom: 2px dashed var(--line);
  margin: 0;
  align-items: start;
}
.detail:first-child { border-top: 2px dashed var(--line); }
.detail h3 { font-size: 0.78rem; letter-spacing: 0.15em; text-transform: uppercase; font-family: var(--font-body); color: var(--muted); margin-bottom: 0.25rem; }
.detail p { font-family: var(--font-display); font-weight: 600; font-size: 1.05rem; }
.detail a:hover { color: var(--red); }

.detail-icon {
  width: 44px; height: 44px;
  border-radius: 14px;
  display: grid;
  place-items: center;
  flex: none;
}
.detail-icon svg { width: 22px; height: 22px; fill: none; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }

/* --------------------------------------------------- footer */
.footer {
  background: var(--sand);
  margin-top: clamp(3rem, 7vw, 6rem);
  padding-top: clamp(3rem, 6vw, 5rem);
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr 1fr;
  gap: clamp(1.8rem, 4vw, 3.4rem);
  padding-bottom: clamp(2.4rem, 5vw, 4rem);
}

.footer-label {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.74rem;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 1.1rem;
}

.footer-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.15rem;
  margin-bottom: 0.5rem;
}

.footer p { color: var(--ink-2); font-size: 0.97rem; margin-bottom: 0.6rem; }
.footer a:hover { color: var(--red); }

.footer-links { list-style: none; margin: 0; padding: 0; }
.footer-links li { margin-bottom: 0.6rem; }
.footer-links a { font-family: var(--font-display); font-weight: 600; font-size: 1rem; }

.footer-base {
  border-top: 2px dashed rgba(59, 34, 23, 0.18);
  padding-block: 1.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem 1.6rem;
  justify-content: space-between;
  align-items: center;
  font-size: 0.86rem;
  color: var(--muted);
}

.footer-social { display: flex; gap: 0.5rem; }
.footer-social a {
  width: 40px; height: 40px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: rgba(255, 255, 255, 0.6);
  transition: background-color 0.25s var(--ease), transform 0.25s var(--ease);
}
.footer-social a:hover { background: #fff; transform: translateY(-2px); }
.footer-social svg { width: 19px; height: 19px; fill: none; stroke: var(--ink); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* --------------------------------------------------- floating WhatsApp */
.wa-float {
  position: fixed;
  right: clamp(1rem, 3vw, 1.8rem);
  bottom: clamp(1rem, 3vw, 1.8rem);
  z-index: 90;
  width: 56px; height: 56px;
  border-radius: 50%;
  background: #25d366;
  display: grid;
  place-items: center;
  box-shadow: var(--shadow);
  transition: transform 0.25s var(--ease);
}
.wa-float:hover { transform: scale(1.07); }
.wa-float svg { width: 29px; height: 29px; fill: #fff; }

/* --------------------------------------------------- scroll reveal */
/* `translate` is its own property, so a revealed element keeps any rotate or
   transform of its own (the tilt cards rely on this). */
.js .reveal {
  opacity: 0;
  translate: 0 26px;
  transition: opacity 0.7s var(--ease), translate 0.7s var(--ease-pop);
}
.js .reveal.is-in { opacity: 1; translate: none; }

.js .reveal-d1 { transition-delay: 0.08s; }
.js .reveal-d2 { transition-delay: 0.16s; }
.js .reveal-d3 { transition-delay: 0.24s; }
.js .reveal-d4 { transition-delay: 0.32s; }

/* --------------------------------------------------- scroll-linked motion
   All of this is handed to the browser's own scroll-driven animations, so
   there is no scroll listener behind any of it and the work stays off the
   main thread. Only opacity, scale and translate are touched — nothing here
   triggers layout or a repaint.

   The @supports guard is load-bearing, not politeness. A browser that does
   not know `animation-timeline` drops that one declaration but still honours
   the rest, so it would run the keyframes on the document timeline with no
   duration and leave the hero parked at its faded end state. Guarded, those
   browsers simply get a still hero, which is what the site looked like
   before. */
@media (prefers-reduced-motion: no-preference) {

  /* the hero wording arrives on load, a beat apart */
  @keyframes hero-in {
    from { opacity: 0; translate: 0 16px; }
    to   { opacity: 1; translate: none; }
  }
  .hero-overlay > * { animation: hero-in 0.6s var(--ease) both; }
  .hero-overlay > *:nth-child(1) { animation-delay: 0.06s; }
  .hero-overlay > *:nth-child(2) { animation-delay: 0.15s; }
  .hero-overlay > *:nth-child(3) { animation-delay: 0.24s; }
  .hero-overlay > *:nth-child(4) { animation-delay: 0.33s; }

  /* The stroke behind each child levitates. Rotating and unevenly scaling an
     asymmetric blob reads as morphing, which is why the border-radius itself
     never animates — that is a paint property and would cost a full repaint
     every frame on five shapes at once. These are transform-only. */
  /* the marks draw on from the left, the way a crayon is dragged, then
     settle into a slow wobble so they never look printed */
  @keyframes crayon-draw { from { scale: 0 1; } to { scale: 1 1; } }
  @keyframes crayon-wobble {
    0%, 100% { rotate: -1.1deg; }
    50%      { rotate: -0.1deg; }
  }

  .hero-overlay h1 .hl::before {
    animation: crayon-draw 0.5s var(--ease-pop) 0.55s both,
               crayon-wobble 7s ease-in-out 1.1s infinite;
  }

  /* the ones further down wait for their block to be revealed */
  .js .reveal .hl::before,
  .js .reveal .mark::before { scale: 0 1; }
  .js .reveal.is-in .hl::before,
  .js .reveal.is-in .mark::before {
    scale: 1 1;
    transition: scale 0.55s var(--ease-pop) 0.2s;
  }
  /* the underline draws itself the same way, but by growing its background
     rather than scaling a box — and because the background is cloned per line
     fragment, each line draws its own */
  .js .reveal .shout { background-size: 0% 0.24em; }
  .js .reveal.is-in .shout {
    background-size: 100% 0.24em;
    transition: background-size 0.55s var(--ease-pop) 0.2s;
  }
  .js .reveal.is-in .hl::before { animation: crayon-wobble 7.5s ease-in-out 1s infinite; }
  .js .reveal.is-in .mark::before { animation: crayon-wobble 8s ease-in-out 1.15s infinite; }

  /* Each icon moves the way its own object would: the hand waves, the note
     drifts up the stave, the pencil rocks as if writing, the apple squashes,
     the ball bounces and the house sways. Six different tempos, none of them
     a factor of another, so a column of six never pulses in unison. */
  @keyframes fi-wave-kf   { 0%, 100% { rotate: -13deg; }                     50% { rotate: 15deg; } }
  @keyframes fi-note-kf   { 0%, 100% { translate: 0 0;    rotate: -6deg; }   50% { translate: 0 -4px; rotate: 6deg; } }
  @keyframes fi-pencil-kf { 0%, 100% { rotate: -8deg; }                      50% { rotate: 8deg; } }
  @keyframes fi-apple-kf  { 0%, 100% { scale: 1 1; }                         50% { scale: 1.11 0.93; } }
  @keyframes fi-ball-kf   { 0%, 100% { translate: 0 0; }                     45% { translate: 0 -7px; } }
  @keyframes fi-house-kf  { 0%, 100% { translate: 0 0;   rotate: 0deg; }     50% { translate: 0 -3px; rotate: 3deg; } }
  @keyframes fi-kite-kf   { 0%, 100% { translate: 0 0;   rotate: -7deg; }   50% { translate: 2px -5px; rotate: 8deg; } }
  @keyframes fi-bowl-kf   { 0%, 100% { translate: 0 0; }                    50% { translate: 0 -3px; } }

  .fi-wave   { animation: fi-wave-kf   2.4s ease-in-out infinite; }
  .fi-note   { animation: fi-note-kf   3.1s ease-in-out infinite; }
  .fi-pencil { animation: fi-pencil-kf 2.7s ease-in-out infinite; transform-origin: 50% 90%; }
  .fi-apple  { animation: fi-apple-kf  2.9s ease-in-out infinite; transform-origin: 50% 100%; }
  .fi-ball   { animation: fi-ball-kf   1.9s cubic-bezier(0.3, 0, 0.5, 1) infinite; }
  .fi-house  { animation: fi-house-kf  3.4s ease-in-out infinite; }
  .fi-kite   { animation: fi-kite-kf   3.6s ease-in-out infinite; }
  .fi-bowl   { animation: fi-bowl-kf   3.3s ease-in-out infinite; }

  /* the tiles lift as the pointer crosses them; the child rises a little
     further than the tile so she parts from its floor rather than sliding
     about on it */
  .gallery-item { transition: translate 0.4s var(--ease), box-shadow 0.4s var(--ease); }
  .gallery-item img { transition: scale 0.5s var(--ease); }
  .gallery-item:hover { translate: 0 -5px; box-shadow: var(--shadow-sm); }
  .gallery-item:hover img { scale: 1.05; }


  @keyframes blob-float {
    0%, 100% { translate: 0 0;       rotate: 0deg;    scale: 1.09; }
    33%      { translate: -1% -1.5%; rotate: -2deg;   scale: 1.13; }
    66%      { translate: 1% -0.5%;  rotate: 1.5deg;  scale: 1.07; }
  }
  @keyframes blob-float-outer {
    0%, 100% { translate: 0 0;       rotate: 0deg;    scale: 1.18 1.1; }
    33%      { translate: 1% -1%;    rotate: 1.4deg;  scale: 1.22 1.13; }
    66%      { translate: -1% -0.5%; rotate: -1deg;   scale: 1.16 1.08; }
  }
  .cast-slot::after { animation: blob-float-outer 11s ease-in-out infinite; }
  .cast-slot::before  { animation: blob-float 9s ease-in-out infinite; }
  .slot-jump::before  { animation-duration: 7.4s;  animation-delay: -2s; }
  .slot-grad::before  { animation-duration: 10.5s; animation-delay: -4s; }
  .slot-hand::before  { animation-duration: 8.2s;  animation-delay: -6s; }
  .slot-pupil::before { animation-duration: 8.8s;  animation-delay: -3s; }

  @keyframes cast-idle {
    0%, 100% { translate: 0 0; rotate: 0deg; }
    50%      { translate: 0 -9px; rotate: 0.8deg; }
  }
  .cast { animation: cast-idle 5.6s ease-in-out infinite; }
  .cast-jump { animation-duration: 4.4s; animation-delay: -1.1s; }
  .cast-grad { animation-duration: 6.2s; animation-delay: -2.3s; }
  .cast-hand { animation-duration: 5s;   animation-delay: -3.1s; }

  @supports (animation-timeline: view()) {

    /* ---- the home hero falls away as the page scrolls past it.
       Three layers on one shared timeline at three speeds: the words leave
       first and travel furthest, the card behind them dims and settles back,
       and the picture pushes in slowly underneath. Together that reads as
       depth; any one of them on its own is just a fade.

       The timeline comes from .after-hero rather than from the hero itself:
       the hero is pinned, and a pinned element never moves, so its own view
       timeline would sit at progress 0 for the entire page. Measuring the
       sheet climbing over it gives the motion something that actually
       travels, and it finishes exactly as the hero vanishes behind it. */
    main { timeline-scope: --cover; }
    .after-hero { view-timeline-name: --cover; }

    .hero-media,
    .hero-overlay {
      animation-timeline: --cover;
      animation-timing-function: linear;
      animation-fill-mode: both;
    }

    .hero-overlay {
      animation-name: hero-words-away;
      animation-range: entry 15% entry 72%;
    }

    .hero-media {
      animation-name: hero-card-away;
      animation-range: entry 15% entry 100%;
    }

    /* no `from` block anywhere below, so each animation starts from whatever
       the element already computes to and the fill leaves it untouched until
       the hero actually begins to leave */
    @keyframes hero-words-away { to { opacity: 0; translate: 0 -3.25rem; } }
    @keyframes hero-card-away  { to { opacity: 0.2; scale: 0.96; } }
    @keyframes hero-push-in    { to { scale: 1.06; } }

    /* She rises into place as the sheet climbs over the fading hero: the hero
       dissolves, she steps forward. Driven by the same --cover timeline as the
       hero fade, so the two are locked together rather than merely similar.

       Deliberately no opacity here: she is already well inside the frame at
       scroll 0 (top at 423px of a 900px viewport), so fading her in would mean
       loading the page with a visible hole where she stands. */
    /* her own view timeline: she lives in the CTA now, nowhere near the hero */
    .pupil {
      animation: pupil-arrive linear both;
      animation-timeline: view();
      animation-range: entry 12% entry 72%;
    }
    @keyframes pupil-arrive {
      from { translate: 0 30px; scale: 0.94; }
      to   { translate: 0 0; scale: 1; }
    }

    /* ---- the inner pages' text hero gets the same courtesy, in one layer */
    .page-hero {
      animation: hero-words-away linear both;
      animation-timeline: view();
      animation-range: exit 8% exit 72%;
    }

    /* ---- editorial pictures settle into their box as they come up.
       `scale` only: the reveal above animates `translate` and the tilt cards
       animate `rotate`, so the three compose instead of cancelling each
       other out. Growing up to 1 rather than down from above it also keeps
       the picture inside its own box — overshooting would push the rounded
       corners and the shadow across the neighbouring column. */
    .split-media img {
      animation: media-settle linear both;
      animation-timeline: view();
      animation-range: entry 18% entry 96%;
    }
    @keyframes media-settle { from { scale: 0.955; } to { scale: 1; } }

    /* ---- the jumper rides the seam.
       Same --cover timeline as the hero fade, but he travels up while the
       sheet climbs and the hero settles back behind it, so three things move
       at three different rates. That difference is the whole effect: he reads
       as a layer standing in front of the seam rather than a sticker printed
       on it. The rotate and scale are small on purpose — depth comes from the
       rates disagreeing, not from any one of them being large.

       He also carries the cast's idle float, but that lives on the <img> while
       this drives the slot, so the two compose instead of overwriting. */
    .seam-cast .cast-slot {
      animation: jump-ride linear both;
      animation-timeline: --cover;
      animation-range: entry 0% entry 100%;
    }
    /* a little apart in time, so the row reads as three children rather than
       one object sliding up */
    .seam-cast .slot-hand { animation-range: entry 4% entry 100%; }
    .seam-cast .slot-grad { animation-range: entry 8% entry 100%; }
    @keyframes jump-ride {
      from { translate: 0 2.6rem;  rotate: 4deg;  scale: 0.88; }
      to   { translate: 0 -2.4rem; rotate: -4deg; scale: 1.08; }
    }
  }

  /* ---- a pre-school should feel springy, so nothing lands quite flat and
     the decorations never sit completely still. Transform-only throughout,
     and all of it inside the reduced-motion guard above. */

  /* the class chips spring to size one after another. Their fade is already
     handled by hero-in on the parent, so these only do the bounce. */
  @keyframes chip-pop { from { scale: 0.4; rotate: -10deg; } to { scale: 1; rotate: 0deg; } }
  .hero-badges .chip { animation: chip-pop 0.5s var(--ease-pop) both; }
  .hero-badges .chip:nth-child(1) { animation-delay: 0.20s; }
  .hero-badges .chip:nth-child(2) { animation-delay: 0.29s; }
  .hero-badges .chip:nth-child(3) { animation-delay: 0.38s; }
  .hero-badges .chip:nth-child(4) { animation-delay: 0.47s; }

  /* the hand-drawn doodles drift, so the page is never completely still.
     Two or three small SVGs per page, transform-only, so this stays on the
     compositor — but it is the one thing here that never stops, which is
     why it is the first thing to drop if the page ever feels busy. */
  @keyframes doodle-bob { 50% { translate: 0 -9px; rotate: 3deg; } }
  .doodle { animation: doodle-bob 7s ease-in-out infinite; }
  .doodle-bulb { animation-duration: 8.4s; animation-delay: -2.6s; }
  .doodle-star { animation-duration: 6.2s; animation-delay: -1.3s; }
  /* The hero's furniture drifts on its own clocks. Most keep the shared bob
     and differ only in tempo; the sun turns, the plane and its trail glide as
     one unit, and the stars twinkle. The durations avoid common factors on
     purpose, so the group never falls into step and starts reading as a
     single mechanical pulse. */
  @keyframes doodle-turn { to { rotate: 360deg; } }
  @keyframes doodle-glide {
    0%, 100% { translate: 0 0;       rotate: -4deg; }
    50%      { translate: -6% -13%;  rotate: 3deg; }
  }
  @keyframes doodle-twinkle {
    0%, 100% { scale: 1;    opacity: 0.95; }
    50%      { scale: 0.55; opacity: 0.3; }
  }
  .hero-doodles .d-sun      { animation: doodle-turn 54s linear infinite; }
  .hero-doodles .d-plane    { animation: doodle-glide 9.5s ease-in-out infinite; }
  .hero-doodles .d-trail    { animation: doodle-glide 9.5s ease-in-out infinite; }
  .hero-doodles .d-cloud-a  { animation-duration: 11s;   animation-delay: -3s; }
  .hero-doodles .d-cloud-b  { animation-duration: 13s;   animation-delay: -6s; }
  .hero-doodles .d-balloon  { animation-duration: 8.6s;  animation-delay: -1.8s; }
  .hero-doodles .d-squiggle { animation-duration: 10.2s; animation-delay: -2.4s; }
  .hero-doodles .d-rainbow  { animation-duration: 12.5s; animation-delay: -5.5s; }
  .hero-doodles .d-star-a   { animation: doodle-twinkle 4.2s ease-in-out infinite; }
  .hero-doodles .d-star-b   { animation: doodle-twinkle 5.1s -1.7s ease-in-out infinite; }
  .hero-doodles .d-star-c   { animation: doodle-twinkle 3.6s -2.4s ease-in-out infinite; }


  /* the name blocks bounce in a wave and the two faces blink and glance
     about. This is far and away the busiest motion on the site — seven
     bricks and four eyes, all looping — so if the page ever needs calming,
     start here rather than with the doodles. */
  @keyframes block-bounce { 50% { translate: 0 -12px; } }
  .block {
    animation: block-bounce 1.7s ease-in-out infinite;
    animation-delay: calc(var(--i) * 0.11s);
  }

  /* --i is set on the brick and custom properties inherit, so each face
     blinks off the other's beat instead of in creepy unison */
  @keyframes eye-blink { 0%, 90%, 100% { scale: 1 1; } 95% { scale: 1 0.1; } }
  .eyes i {
    animation: eye-blink 5.4s ease-in-out infinite;
    animation-delay: calc(var(--i) * -1.7s);
  }

  @keyframes eye-look { 0%, 100% { translate: 0 0; } 30% { translate: 26% 10%; } 68% { translate: -22% 6%; } }
  .eyes i::after {
    animation: eye-look 4.6s ease-in-out infinite;
    animation-delay: calc(var(--i) * -0.8s);
  }

  /* a shake when you point at an icon, and a squash when you press a button */
  @keyframes wiggle { 25% { rotate: -9deg; } 75% { rotate: 9deg; } }
  .feature:hover .feature-icon,
  .brand:hover .brand-mark { animation: wiggle 0.55s ease-in-out; }
  .btn:active { scale: 0.96; }
}

/* --------------------------------------------------- responsive */
@media (max-width: 1040px) {
  .feature-row { grid-template-columns: repeat(2, 1fr); row-gap: 2.6rem; }
  .grid-3, .tilt-grid { grid-template-columns: repeat(2, 1fr); }
  .footer-grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 900px) {
  .nav-menu {
    position: absolute;
    top: calc(100% + 0.6rem);
    left: 0; right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0.15rem;
    background: #fff;
    border-radius: var(--r);
    padding: 0.7rem;
    box-shadow: var(--shadow);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-10px);
    transition: opacity 0.25s var(--ease), transform 0.25s var(--ease), visibility 0.25s;
  }
  .nav { position: relative; flex-wrap: wrap; }
  .nav-menu.is-open { opacity: 1; visibility: visible; transform: none; }
  .nav-menu a { padding: 0.85rem 1rem; font-size: 1.02rem; }
  .nav-toggle { display: block; order: 3; }
  .nav-cta { display: none; }
  .nav-menu .nav-menu-cta { display: block; margin-top: 0.35rem; }
  .nav-menu .nav-menu-cta a { background: var(--ink); color: #fff; text-align: center; }
  .nav-menu .nav-menu-cta a:hover { background: #2c190f; color: #fff; }

  .split { grid-template-columns: 1fr; }
  .split.is-reversed .split-media { order: 0; }
  .doodle-ring { width: 110px; right: -14px; bottom: -22px; }
  .doodle-bulb { width: 70px; left: -14px; top: -18px; }

  .band-head { flex-direction: column; align-items: flex-start; gap: 1.4rem; }
  .prog-card { grid-template-columns: 1fr; }
  .prog-card img { height: 190px; }
  .carousel-track > * { flex-basis: min(440px, 88%); }


  .flow-row { grid-template-columns: 1fr; gap: 0.3rem; }
  .flow-time { justify-content: flex-start; gap: 0.7rem; }
}

@media (max-width: 620px) {
  .feature-row { grid-template-columns: 1fr; }
  .grid-3, .grid-2, .tilt-grid, .field-row { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr; }
  .hero-media {
    width: 100%;
    border-radius: 0;
  }
  /* no min-height override here: the base rule now sizes the hero against the
     viewport at every width, which is what keeps the fade from pre-applying */

  .tilt { rotate: none !important; }
  .value-item { grid-template-columns: 1fr; gap: 0.2rem; }
  .value-num { padding-top: 0; }
  .btn { width: 100%; justify-content: center; }
  .btn-row .btn { width: auto; flex: 1 1 auto; }
  .ticker { font-size: 0.82rem; }

  /* The doodles hang outside their box by design. At phone widths that, plus
     the bob rotating them a little further, pushed a few pixels past the
     screen edge — clipped rather than scrollable, but still a nicked
     decoration. Pull them in instead of widening the clip. */
  .doodle-ring { width: 112px; right: -14px; bottom: -22px; }
  .doodle-bulb { width: 74px; left: -14px; top: -20px; }
  .doodle-star { width: 56px; right: -10px; top: -18px; }

  /* Only the jumper and the graduate are in the markup now, so there is
     nothing to hide here. flex-shrink is off so they keep their size and let
     the card edges crop them, which reads as a crowd rather than a squeeze. */
  .cast-slot { flex-shrink: 0; }
  /* Twelve shapes read as a scene on a wide card and as clutter on a phone.
     The narrow column leaves exactly two gaps -- a strip beside the badge and
     the band between the headline and the graduate -- so five shapes stay and
     move into them. Anything in the headline's vertical band has nowhere to
     go: the wording runs the full width here. */
  .hero-doodles .d-cloud-a,
  .hero-doodles .d-trail,
  .hero-doodles .d-squiggle,
  .hero-doodles .d-star-a,
  .hero-doodles .d-star-c,
  .hero-doodles .d-plane { display: none; }
  .d-cloud-b { right: 6%; top: 9%;     --dw: clamp(60px, 17vw, 96px); }
  .d-sun     { left: 5%;  top: 37%; }
  .d-balloon { right: 8%; left: auto; top: 36%; --dw: clamp(34px, 10vw, 52px); }
  .d-star-b  { left: 20%; right: auto; top: 45%; }
  .d-rainbow { left: 30%; top: 52%; bottom: auto; --dw: clamp(84px, 32vw, 150px); }

  /* side by side on the seam, so the overlap that let two large children
     share a narrow card is gone */
  .seam-cast { padding-inline: 3%; }

  /* the cut-outs are smaller here, so the same rim reads thicker: hold the
     proportion rather than the pixel */
  .pupil,
  .cast { --rim: 1px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
  .js .reveal { opacity: 1; translate: none; }
  .carousel-track { scroll-behavior: auto; }
}

/* --------------------------------------------------- the CTA's foot
   Centred, she stands exactly where the centred wording is, so the panel
   reserves a foot her own height for her to stand in. Her picture is 620x930,
   so her height is always 1.5x her width and one rule covers every screen.
   It sits down here because .cta's own `padding` shorthand is declared below
   the responsive blocks and would otherwise win. */
.cta {
  --pupil-w: clamp(130px, 16vw, 240px);
  padding-bottom: calc(var(--pupil-w) * 1.5 + 1.4rem);
}

/* --------------------------------------------------- late overrides
   These sit below .cta on purpose. The responsive blocks higher up cannot
   override it — a media query adds no specificity, so .cta's own `padding`
   shorthand, declared further down, simply wins. */
@media (max-width: 900px) {
  /* the centred CTA wording fills the panel at this width, so the panel grows
     a foot for her to stand in rather than her standing on the buttons */
}

/* --------------------------------------------------- short windows
   The hero is sized against the viewport but its wording is sized against the
   text, and on a short window the wording wins. Compacting the column is what
   keeps the hero's promise of fitting the screen. */
@media (max-height: 720px) {
  .hero-overlay {
    padding-top: calc(var(--nav-h) + 0.2rem);
    gap: 0.5rem;
  }
  .hero-overlay h1 { font-size: clamp(1.5rem, 3.2vw, 2.4rem); }
  .hero-badge { width: clamp(38px, 3.8vw, 56px); }
  /* --cast-scale is gone: it existed to squeeze four children across a short
     window, and with two it only shrank them twice over. --cast-h already
     tracks the viewport height on its own. */
}


.g-sage   { background: linear-gradient(168deg, color-mix(in srgb, var(--sage) 38%, #fff), color-mix(in srgb, var(--sage) 16%, #fff)); }
.g-sky    { background: linear-gradient(168deg, color-mix(in srgb, var(--sky) 46%, #fff), color-mix(in srgb, var(--sky) 18%, #fff)); }
.g-butter { background: linear-gradient(168deg, color-mix(in srgb, var(--butter) 42%, #fff), color-mix(in srgb, var(--butter) 16%, #fff)); }
.g-peach  { background: linear-gradient(168deg, color-mix(in srgb, var(--peach) 40%, #fff), color-mix(in srgb, var(--peach) 16%, #fff)); }
.g-lav    { background: linear-gradient(168deg, color-mix(in srgb, var(--lav) 48%, #fff), color-mix(in srgb, var(--lav) 20%, #fff)); }

/* Two columns on a phone, with the wide one still spanning both. One column
   would make each tile as wide as the screen and the section twice as long as
   the page it sits in. */
/* --------------------------------------------------- gallery
   Every photograph on this site is a cut-out with a transparent ground, so a
   plain grid of them would be children floating on cream with nothing holding
   them. Each tile brings its own colour instead and the child stands on its
   floor, which is the same idea as the mission frame and the hero cast.

   The tiles are a fixed 4:3 and the picture is sized by HEIGHT inside them, so
   five photographs of four different ratios still line up on one baseline. */
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(0.7rem, 1.6vw, 1.2rem);
}

.gallery-item {
  position: relative;
  margin: 0;
  aspect-ratio: 4 / 3;
  border-radius: var(--r-lg);
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  box-shadow: var(--shadow-xs);
}

/* the landscape photograph gets the double-width tile; the four upright ones
   take the singles, which is what keeps every child at a sensible scale */
.gallery-wide { grid-column: span 2; aspect-ratio: 8 / 3; }

.gallery-item img {
  width: auto;
  height: 94%;
  max-width: none;
  display: block;
  /* the shadow follows the cut-out alpha, so it is the child's silhouette on
     the tile rather than a rectangle */
  filter: drop-shadow(0 8px 12px rgba(59, 34, 23, 0.2));
}
.gallery-wide img { height: 88%; }

/* The About gallery holds cut-outs, which stand on a tinted floor at 94% of
   the tile. These are drawings that carry their own ground and their own 4:3,
   so they fill the tile edge to edge instead — same grid, same radius, same
   hover, different fit. The drop-shadow goes with them: it traces the alpha,
   which on a cut-out is the child and on a full-bleed drawing is a rectangle. */
.gallery-art .gallery-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: none;
}

@media (max-width: 760px) {
  .gallery { grid-template-columns: repeat(2, 1fr); }
  /* four of the five photographs are upright, and a 4:3 tile on a 172px column
     left the children about 120px tall — too small to see a face. Upright
     tiles on a phone give them nearly twice that. */
  .gallery-item { aspect-ratio: 3 / 4; }
  /* that upright tile is for the cut-outs on the About page, which are upright
     themselves. The drawings are 4:3, and cover was shearing the sides off
     them — the blocks and the easel both lost an edge. */
  .gallery-art .gallery-item { aspect-ratio: 4 / 3; }
  .gallery-wide { grid-column: span 2; aspect-ratio: 2 / 1; }
}

/* --------------------------------------------------- class level
   Apricot, Lavender, Jasmine and Tulip are the school's own names for its
   classes, but a parent looking for a place knows Baby, Middle and Top. Both
   are shown: the flower is the heading, the level sits under it as a label.

   A block of its own rather than a parenthesis inside the heading, so the
   name keeps the display face and the heading's own size while the level
   stays a quiet, fixed size at either heading level. */
.class-level {
  display: block;
  margin-top: 0.4em;
  font-family: var(--font-body);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --------------------------------------------------- photographs in place
   Two one-off frames: the staff on About and the signboard on Contact. Both
   carry the same radius and shadow the rest of the site's media uses, so a
   photograph does not arrive looking like a different component. */
.staff-shot,
.sign-shot {
  margin: 0;
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.staff-shot img,
.sign-shot img {
  display: block;
  width: 100%;
  height: auto;
}
.sign-shot { margin-top: 1.4rem; }
.sign-shot figcaption {
  padding: 0.7rem 1rem 0.9rem;
  background: var(--cream-2);
  color: var(--muted);
  font-size: 0.92rem;
}

/* --------------------------------------------------- photograph rows
   Two rows of photographs: the three Kids Activity shots under their cards,
   and the pair on Admissions. Both crop to a fixed shape with object-fit, so
   a portrait and a landscape frame can sit side by side without one of them
   setting the row's height. */
.activity-shots,
.arrival-shots {
  display: grid;
  gap: clamp(0.7rem, 1.6vw, 1.2rem);
  margin-top: clamp(1.4rem, 3vw, 2.4rem);
}
.activity-shots { grid-template-columns: repeat(3, 1fr); }
.arrival-shots  { grid-template-columns: 1fr 1.35fr 1.35fr; }

.activity-shots figure,
.arrival-shots figure {
  margin: 0;
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--shadow-xs);
}
.activity-shots img,
.arrival-shots img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.activity-shots figure { aspect-ratio: 4 / 3; }
.arrival-shots figure  { aspect-ratio: 3 / 4; }
.arrival-shots figure:not(:first-child) { aspect-ratio: 16 / 10; align-self: center; }

/* a phone has no room for three across; the activity row halves and the
   arrival pair stacks, so neither ends up as a row of stamps */
/* One per row on a phone. Two across left each photograph 172px wide, which
   is too small to make out a child, and the stairs shot is a portrait -- the
   landscape crop took a horizontal slice out of the middle of it. Each keeps
   its own shape instead. */
@media (max-width: 760px) {
  .activity-shots,
  .arrival-shots { grid-template-columns: 1fr; }
  .activity-shots figure { aspect-ratio: 16 / 10; }
  .arrival-shots figure:first-child { aspect-ratio: 4 / 5; }
  .arrival-shots figure:not(:first-child) { aspect-ratio: 16 / 10; }
}

/* --------------------------------------------------- print */
@media print {
  .nav-wrap, .wa-float, .carousel-nav, .btn { display: none !important; }
  body { background: #fff; }
}
