/* Generated by tools/build-site.py from the home page's stylesheets, in the
   order the page lists them. Edit those, never this. */

/* ---- assets/css/fonts.css ---- */
/* Generated by tools/make-fonts.py. Local fonts only; licenses in assets/fonts/licenses/. */

@font-face {
  font-family: 'Mona Sans';
  font-style: normal;
  font-weight: 200 900;
  font-stretch: 100%;
  font-display: swap;
  size-adjust: 92%;
  src: url('../fonts/monasans-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'Mona Sans';
  font-style: normal;
  font-weight: 200 900;
  font-stretch: 75% 99%;
  font-display: swap;
  size-adjust: 92%;
  src: url('../fonts/monasans-width.woff2') format('woff2');
}

@font-face {
  font-family: 'Mona Sans';
  font-style: normal;
  font-weight: 200 900;
  font-stretch: 101% 125%;
  font-display: swap;
  size-adjust: 92%;
  src: url('../fonts/monasans-width.woff2') format('woff2');
}

@font-face {
  font-family: 'Mona Sans';
  font-style: italic;
  font-weight: 200 900;
  font-stretch: 100%;
  font-display: swap;
  size-adjust: 92%;
  src: url('../fonts/monasans-italic.woff2') format('woff2');
}

@font-face {
  font-family: 'Bodoni Moda';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url('../fonts/bodonimoda-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'Bodoni Moda';
  font-style: italic;
  font-weight: 400 900;
  font-display: swap;
  src: url('../fonts/bodonimoda-italic.woff2') format('woff2');
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('../fonts/newsreader-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'Newsreader';
  font-style: italic;
  font-weight: 200 800;
  font-display: swap;
  src: url('../fonts/newsreader-italic.woff2') format('woff2');
}

@font-face {
  font-family: 'Literata';
  font-style: normal;
  font-weight: 200 900;
  font-display: swap;
  src: url('../fonts/literata-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'Literata';
  font-style: italic;
  font-weight: 200 900;
  font-display: swap;
  src: url('../fonts/literata-italic.woff2') format('woff2');
}

@font-face {
  font-family: 'EB Garamond';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../fonts/ebgaramond-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'EB Garamond';
  font-style: italic;
  font-weight: 400 800;
  font-display: swap;
  src: url('../fonts/ebgaramond-italic.woff2') format('woff2');
}

@font-face {
  font-family: 'Tiro Devanagari Hindi';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/tirodevanagarihindi-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'Tiro Devanagari Hindi';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/tirodevanagarihindi-italic.woff2') format('woff2');
}

/* ---- assets/css/cirs.css ---- */
/* ============================================================
   Chinmaya International Residential School
   ------------------------------------------------------------
   Ivory and white grounds, charcoal lettering, approved gold, and
   the earlier deep-purple brand accent. Natural green remains for
   campus and nature where it has meaning. Page sheets
   read them rather than defining their own. Photography is the
   school's own, re-cropped and graded, and is never recoloured.

   Type — families are named here and nowhere else; every sheet
   uses the role tokens below, and typography.css sets the roles.
     --font-body, --font-ui  Mona Sans: English body, interface,
                             labels, captions, data, film titles
     --font-display          headings and display lettering
     --font-editorial        editorial introductions
     --font-quote            quotations and heading emphasis
     --deva                  Tiro Devanagari Hindi: Sanskrit, Hindi
   Bodoni Moda carries display lettering. Literata and EB Garamond keep
   the selected editorial and quotation roles. All deployed faces are
   self-hosted under open font licences.
   ============================================================ */

:root{
  color-scheme: light;

  /* ----------------------------------------------------------
     Colour. One system, in roles rather than hues: the owner's
     ivory, gold, natural green and restored deep purple.
     Page sheets read these roles; they do not define their own
     paper, ink or gold. Ratios are WCAG, measured on the solid
     pairs named; a surface that is not one of these is measured
     where it is used.
     ---------------------------------------------------------- */

  /* Grounds. */
  --paper:    #FAF9F3;   /* signature ivory */
  --paper-2:  #F4F0E6;   /* alternate ivory */
  --paper-3:  #EDE7D8;   /* cream */
  --white:    #FFFFFF;

  /* The school's recovered purple gives shared dark scenes their ground.
     Film-specific black frames remain owned by each film page. */
  --dark:       #392A48;
  --dark-mid:   #2B2037;
  --dark-deep:  #1E1626;
  --dark-ink:   #1E1626;

  /* Earlier school gold is bright on purple (8.17:1), and too light for
     text on ivory. --gold-ink remains the readable paper text role. */
  --gold:      #FFC308;
  --gold-lit:  #FFD75C;
  --gold-pale: #FFE7A6;
  --gold-ink:  #8F6E2F;
  --gold-rgb:  255,195,8;
  --on-gold:   #1E1626;

  /* Brand and gold from the stylesheet before b04ab898; current ivory and
     typography remain in place. */
  --brand:        #392A48;
  --brand-mid:    #2B2037;
  --brand-deep:   #1E1626;
  --maroon:       #7A0F1E;
  --label:        var(--brand);
  --purple-pale:  #F3EDF6;

  /* Green belongs to campus and nature, not to every button. */
  --campus:       #2E5D3A;   /* 7.26:1 on ivory */
  --campus-dark:  #173B27;
  --sage:         #A7B896;
  --nature-pale:  #DCE6D6;

  /* Status: meaning only, never decoration. */
  --ok:    #287A45;
  --warn:  #D99A24;
  --error: #B84A4A;
  --info:  #4A8BA8;

  /* Lettering on paper. The reference grey #706F68 is 4.78:1 on
     ivory but 4.43:1 on the alternate ivory, 4.09:1 on cream and
     3.61:1 on pale gold, and secondary copy sits on all of those.
     --ink-mute is the nearest step that holds 4.5:1 on every light
     ground in this palette: 6.17:1 on ivory, 5.27:1 on cream,
     4.65:1 on pale gold, 5.06:1 on pale green. */
  --ink:       #1F1F1B;   /* 15.68:1 on ivory */
  --ink-soft:  #54534D;   /*  7.32:1 */
  --ink-mute:  #5F5E58;

  /* Lettering on the dark sections. Solid, not translucent, so a
     photograph under a scrim cannot thin it. */
  --on-dark:      #FAF9F3;
  --on-dark-soft: #D6D3CA;   /* 9.73:1 on --dark */
  --on-dark-mute: #B3B0A7;   /* 6.71:1 on --dark */

  /* Separation. Decorative: a required control outline uses
     --ink-mute, which is 6.17:1 against ivory. */
  --rule:       #E3DCCB;
  --rule-soft:  #EEE9DE;
  --rule-dark:  rgba(250,249,243,.20);
  --decoration-mute: #A8A69D;   /* disabled and decorative only */

  /* Keyboard focus on paper; dark surfaces use bright gold below. */
  --focus: #8F6E2F;

  --font-body: "Mona Sans", Arial, sans-serif;
  --font-ui: "Mona Sans", Arial, sans-serif;
  --font-display: "Bodoni Moda", Georgia, serif;
  --font-editorial: "Literata", Georgia, serif;
  --font-quote: "EB Garamond", Georgia, serif;
  --deva: "Tiro Devanagari Hindi", serif;

  /* The home hero's headline, and nothing else. Pulled back from 10.5vw so
     the campus behind it is a photograph rather than a backdrop. */
  --fs-mega:  clamp(2.6rem, 7.2vw, 6rem);
  --fs-hero:  clamp(2.5rem, 5.6vw, 4.8rem);
  --fs-h2:    clamp(2rem, 3.9vw, 3.4rem);
  --fs-h3:    clamp(1.25rem, 1.7vw, 1.6rem);
  --fs-lead:  clamp(1.08rem, 1.35vw, 1.32rem);
  --fs-body:  1rem;
  --fs-sm:    0.905rem;
  --fs-xs:    0.78rem;

  /* Spacing scale — every new component below is built on these steps,
     not on one-off pixel values. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  --space-9: 96px;
  --space-10: 144px;

  --gut:  clamp(20px, 4vw, 64px);
  --maxw: 1320px;
  --measure: 62ch;

  --e:  cubic-bezier(.22,.61,.36,1);
  --e2: cubic-bezier(.16,1,.3,1);

  /* A shared depth language: quiet enough to support the photography rather
     than becoming a second visual subject. */
  --shadow-image: 0 22px 52px rgba(31,31,27,.14);
  --shadow-control: 0 8px 22px rgba(31,31,27,.12);
}

/* ============================================================
   Base
   ============================================================ */
*,*::before,*::after{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; }
@media (prefers-reduced-motion:reduce){ html{ scroll-behavior:auto; } }
body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--font-body);
  font-size:var(--fs-body);
  line-height:1.62;
  -webkit-font-smoothing:antialiased;
  overflow-x:clip;
}
body.is-locked{ overflow:hidden; }
img{ display:block; max-width:100%; height:auto; }
svg{ display:block; }
a{ color:inherit; text-decoration:none; }
button{ font:inherit; color:inherit; background:none; border:0; cursor:pointer; }
h1,h2,h3,h4{ margin:0; font-family:var(--font-display); font-weight:400; text-wrap:balance; }
p{ margin:0; }
ul,ol{ margin:0; padding:0; list-style:none; }
strong,b{ font-weight:600; }
::selection{ background:var(--gold); color:var(--on-gold); }
:focus-visible{ outline:2px solid var(--focus); outline-offset:3px; }

.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:12px; top:-60px; z-index:300;
  background:var(--dark); color:#fff; padding:10px 18px; font-size:var(--fs-sm);
  transition:top .18s var(--e);
}
.skip-link:focus{ top:10px; }

/* ============================================================
   Type roles
   ============================================================ */
.serif{
  font-family:var(--font-display);
  font-weight:400;
  line-height:1.1;
  letter-spacing:-.006em;
  text-wrap:balance;
}
.serif em{ font-style:italic; }
.h1{ font-size:var(--fs-hero); line-height:1.02; letter-spacing:-.018em; }
.h2{ font-size:var(--fs-h2); line-height:1.06; letter-spacing:-.012em; }
.h3{ font-size:var(--fs-h3); line-height:1.2; }

.lead{
  font-size:var(--fs-lead); line-height:1.58; color:var(--ink-soft);
  max-width:var(--measure); text-wrap:pretty;
}
.copy{ color:var(--ink-soft); max-width:var(--measure); text-wrap:pretty; }
.copy + .copy{ margin-top:1.05em; }

/* Labels retain their hierarchy; the typography sheet controls caps and spacing. */
.sc{
  font-family:var(--font-ui);
  font-variant-caps:normal;
  font-feature-settings:normal;
  letter-spacing:.06em;
  font-size:1.02rem;
  color:var(--label);
  line-height:1;
}
/* Label-purple small caps sit at 1.9:1 on the dark grounds — unreadable.
   Gold is 7.9:1 there. .on-dark is not the only dark section: the film panel, the
   footer, the closing band and the motto all set a dark background of their
   own, so every dark context is listed here rather than relying on one class
   being remembered. On paper, the label purple stays (9.86:1) — it is the
   accent that ties the editorial type together. */
:is(.on-dark, .filmsec, .footer, .finalcta, .band, .motto)
  :is(.sc, .feature__tag, .dmoment__i){ color:var(--gold-lit); }

/* Section marker: the small diamond and hairline repeat one recognisable CIRS
   signature across otherwise very different editorial pages. */
.marker{ display:flex; align-items:center; gap:14px; margin-bottom:20px; }
.marker::before{
  content:""; width:7px; height:7px; flex:0 0 7px;
  border:1px solid var(--label); transform:rotate(45deg);
}
.marker::after{ content:""; height:1px; flex:1; background:var(--rule); }
.on-dark .marker::before,
:is(.filmsec,.footer,.finalcta,.band,.motto) .marker::before{ border-color:var(--gold-lit); }
.on-dark .marker::after{ background:var(--rule-dark); }

/* Figures: oldstyle in editorial settings, lining+tabular in data */
.osf{ font-variant-numeric:oldstyle-nums; }
.tnum{ font-variant-numeric:tabular-nums lining-nums; }

.deva{ font-family:var(--deva); font-weight:400; line-height:1.5; }

/* ============================================================
   Layout
   ============================================================ */
.wrap{ width:100%; max-width:var(--maxw); margin-inline:auto; padding-inline:var(--gut); }
/* Anchor targets must clear the sticky header, or the in-page nav drops the
   heading behind it. */
section[id]{ scroll-margin-top:88px; }
.section{ padding-block:clamp(60px,7.5vw,120px); }

.on-dark{ background:var(--dark-deep); color:var(--on-dark); }
.on-dark .lead,.on-dark .copy{ color:var(--on-dark-soft); }
.on-paper-2{ background:var(--paper-2); }

.sec-head{ max-width:660px; margin-bottom:clamp(34px,4vw,60px); }
.sec-head .h2{ margin-bottom:18px; }

/* ============================================================
   Header — the compositing rule only. The header, the menu and the
   Enquire sheet are drawn in drawer.css.
   ============================================================ */
.header{
  position:fixed; top:0; left:0; right:0; z-index:100;
  /* Keep the fixed chrome on its own compositor layer. Without this,
     Chromium can briefly paint a transformed pinned section over part of the
     header during a fast pin handoff even though the DOM stacking order is
     correct. */
  transform:translateZ(0); backface-visibility:hidden; isolation:isolate;
  /* Layout containment keeps the chrome independent without clipping the
     Enquire sheet that hangs below the bar. */
  will-change:transform; contain:layout style;
}

.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:9px;
  padding:12px 24px; font-size:var(--fs-sm); font-weight:600;
  border:1.5px solid transparent;
  box-shadow:var(--shadow-control);
  transition:background .25s var(--e), color .25s var(--e), border-color .25s var(--e),
             box-shadow .25s var(--e), transform .25s var(--e);
  white-space:nowrap;
}
.btn[href]::after{
  content:""; width:6px; height:6px; flex:none;
  border-top:1.5px solid currentColor; border-right:1.5px solid currentColor;
  transform:rotate(45deg); transition:transform .25s var(--e);
}
.btn[href]:hover{ transform:translateY(-2px); box-shadow:0 12px 28px rgba(24,24,21,.17); }
.btn[href]:hover::after{ transform:translateX(2px) rotate(45deg); }
.btn[href]:active{ transform:translateY(0); box-shadow:var(--shadow-control); }
.btn--primary{ background:var(--gold); color:var(--on-gold); transition:border-color .25s var(--e); }
.btn--primary:hover{ background:var(--gold-lit); color:var(--on-gold); }
.btn--outline{ border-color:var(--dark); color:var(--dark); }
.btn--outline:hover{ background:var(--dark); color:#fff; }
.btn--ghost{ border-color:rgba(255,255,255,.55); color:#fff; }
.btn--ghost:hover{ background:#fff; color:var(--dark-deep); border-color:#fff; }
.btn--lg{ padding:15px 30px; }

/* ============================================================
   Hero — a full-bleed monogram window. A translucent white wordmark
   is masked over the campus photograph, so the photo shows softly
   through the letterforms rather than being cut out by them; the
   readable headline sits below it as the school's motto.
   ============================================================ */
.hero{
  position:relative; min-height:100svh; min-height:100vh;
  display:flex; flex-direction:column; justify-content:flex-end;
  background:var(--dark-ink); overflow:hidden; isolation:isolate;
}
.hero__media{
  position:absolute; inset:0; z-index:0;
  will-change:transform; backface-visibility:hidden;
}
.hero__media img, .hero__media video{
  width:100%; height:100%; object-fit:cover; object-position:center 42%;
}

/* The scrim is deliberately lighter than a legible-at-any-cost wash: the
   campus is the point of this panel, so it holds the lower third — where
   the headline, the marker and the scroll cue sit — and lets the middle
   and the ridge line come through nearly clean. Measured, not guessed;
   tools/check-contrast.py samples the pixels behind each line across the
   video loop, and every one of them clears AA with room to spare. */
.hero__scrim{
  position:absolute; inset:0; z-index:2; pointer-events:none;
  background:
    linear-gradient(to top, rgba(24,24,21,.95) 0%, rgba(24,24,21,.86) 18%,
                    rgba(24,24,21,.64) 38%, rgba(24,24,21,.20) 70%,
                    rgba(24,24,21,.32) 100%);
}

/* Anchor the opening headline to the viewport, outside the page's capped grid. */
.hero > .wrap{
  max-width:none;
  padding-inline:clamp(20px,3vw,48px);
}
.hero__inner{
  position:relative; z-index:3;
  padding-block:0 clamp(24px,4vw,48px);
  max-width:min(1100px,92vw);
}
.hero .marker{ margin-bottom:var(--space-4); }
.hero .sc{ color:var(--gold-lit); font-size:.92rem; }
.hero .marker::after{ background:rgba(255,255,255,.28); max-width:120px; }
.hero h1{ font-size:var(--fs-mega); color:#fff; line-height:.98; letter-spacing:-.02em; }
.hero h1 em{ color:var(--gold-lit); }

.hero__scroll{
  display:inline-flex; align-items:center; gap:var(--space-3); margin-top:var(--space-5);
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal;
  font-size:.92rem; letter-spacing:.06em; color:rgba(255,255,255,.82);
}
.hero__scroll svg{ animation:hero-bob 1.8s ease-in-out infinite; }
@keyframes hero-bob{ 0%,100%{ transform:translateY(0); } 50%{ transform:translateY(5px); } }
@media (prefers-reduced-motion:reduce){ .hero__scroll svg{ animation:none; } }

/* ============================================================
   Motto band
   ============================================================ */
.motto{
  background:var(--dark); color:#fff;
  padding-block:clamp(44px,5.5vw,88px);
  text-align:center;
  background-image:
    radial-gradient(130% 150% at 50% -10%, rgba(var(--gold-rgb),.13) 0%, rgba(var(--gold-rgb),0) 58%);
}
.motto__deva{
  font-family:var(--deva);
  font-size:clamp(2rem,5.6vw,4.4rem);
  line-height:1.45;
  letter-spacing:.01em;
  color:#fff;
}
.motto__iast{
  font-family:var(--font-quote); font-style:italic;
  font-size:clamp(1.05rem,1.6vw,1.4rem);
  color:rgba(255,255,255,.72); margin-top:16px;
}
.motto__en{
  font-family:var(--font-body); font-variant-caps:normal;
  font-feature-settings:normal;
  font-size:1.02rem; letter-spacing:.06em; color:var(--gold-lit); margin-top:14px;
}
.motto__rule{ width:44px; height:1px; background:rgba(255,255,255,.4); margin:26px auto 0; }

/* ============================================================
   About — drop cap and offset fact rail
   ============================================================ */
.about{ display:grid; gap:clamp(30px,4vw,72px); align-items:start; }
@media (min-width:940px){ .about{ grid-template-columns:1.5fr .82fr; } }

.pull{
  font-family:var(--font-display);
  font-size:clamp(1.5rem,2.6vw,2.25rem);
  line-height:1.26; color:var(--dark); letter-spacing:-.01em;
  margin-bottom:26px; text-wrap:balance;
}
.pull em{ font-style:italic; }
.dropcap::first-letter{
  font-family:var(--font-display);
  float:left;
  font-size:4.1em;
  line-height:.82;
  padding:.05em .1em 0 0;
  color:var(--label);
}

.factrail{ border-top:2px solid var(--dark); }
.factrail > div{
  display:flex; justify-content:space-between; gap:18px; align-items:baseline;
  padding:12px 0; border-bottom:1px solid var(--rule-soft);
}
.factrail dt{
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal;
  font-size:1rem; letter-spacing:.1em; color:var(--ink-mute);
}
.factrail dd{
  margin:0; text-align:right; color:var(--dark); font-weight:500;
  font-size:var(--fs-sm); font-variant-numeric:oldstyle-nums;
}

/* ============================================================
   Academics
   ============================================================ */
.prog{ display:grid; gap:clamp(20px,2.6vw,38px); }
@media (min-width:880px){ .prog{ grid-template-columns:1fr 1fr; } }
.prog__card{ display:flex; flex-direction:column; }
.prog__card figure{
  margin:0 0 22px; overflow:hidden; aspect-ratio:16/9;
  background:var(--dark-deep); box-shadow:var(--shadow-image);
}
.prog__card img{ width:100%; height:100%; object-fit:cover; transition:transform .9s var(--e2); }
.prog__card:hover img{ transform:scale(1.045); }
.prog__head{ display:flex; align-items:baseline; gap:14px; margin-bottom:12px; }
.prog__idx{
  font-family:var(--font-display); font-size:1.5rem; color:var(--gold-ink);
  font-variant-numeric:oldstyle-nums; line-height:1;
}
.prog__card h3{ margin-bottom:12px; }
.prog__meta{
  display:flex; flex-wrap:wrap; gap:6px 26px; margin-top:auto; padding-top:16px;
  border-top:1px solid var(--rule); font-size:var(--fs-sm); color:var(--ink-mute);
}
.prog__meta b{ color:var(--dark); font-weight:600; }
/* The way through to a card's own page, where it has one. margin-top:auto
   holds it to the foot of the card so two cards side by side agree. */
.prog__more{ margin:20px 0 0; }
@media (min-width:880px){ .prog__more{ margin-top:auto; padding-top:20px; } }

/* ============================================================
   The run — the home page's horizontal passage
   ------------------------------------------------------------
   It fills the window. The section pins at 100svh with nothing
   above or below it inside the frame. The stage is a measured
   horizontal gallery: every text panel and photograph owns a
   distinct cell, so depth can never turn into overlap.

   Sizes are given in vh, so the run is composed against the
   height of the window rather than its width and a frame is
   always a known fraction of the screen.

   Depth: every item declares one, the stage is translated once,
   and each item again by its own parallax — measured against the
   middle of the window, so the offsets stay inside one screen
   and frames can lead or lag their neighbours without ever
   swapping places with them.
   ============================================================ */
.hrun{ position:relative; background:var(--dark-ink); }
.hrun__pin{
  height:100svh; height:100vh; overflow:hidden;
  background:
    radial-gradient(120% 90% at 12% 0%, rgba(143,110,47,.34), transparent 60%),
    radial-gradient(90% 80% at 92% 100%, rgba(42,41,37,.5), transparent 62%),
    var(--dark-ink);
}
.hrun__viewport{
  height:100%; overflow:hidden;
  /* A close, centred camera makes the photographs read as one curved
     gallery rather than as individually tilted cards. */
  perspective:1100px; perspective-origin:50% 48%;
}
.hrun__stage{
  position:relative; width:max-content; min-width:100%; height:100%;
  display:flex; align-items:center;
  gap:clamp(96px,10vw,180px);
  padding-inline:clamp(7vw,10vw,150px);
  will-change:transform;
}

/* --- the photographs ------------------------------------- */
.hframe{
  position:relative; inset:auto !important; z-index:1; margin:0;
  flex:0 0 auto;
  transform-style:preserve-3d; transform-origin:50% 50%;
  backface-visibility:hidden; will-change:transform;
}
.hframe img{
  display:block; width:100%; max-width:none; height:auto;
  object-fit:cover; border-radius:12px;
  border:1px solid rgba(var(--gold-rgb),.32);
  box-shadow:0 24px 64px rgba(0,0,0,.38), 0 0 0 1px rgba(255,255,255,.08);
  backface-visibility:hidden;
}
/* Above the frame and left-aligned with it, as in the reference: an index,
   not a caption, and quiet enough to read as one. */
.hframe__n{
  display:block; margin-bottom:12px;
  font-family:var(--font-ui); font-variant-numeric:oldstyle-nums;
  font-size:clamp(.78rem,.92vw,.96rem); letter-spacing:.06em;
  color:var(--on-dark); opacity:.52;
}
.hframe figcaption{
  margin-top:16px; max-width:34ch;
  font-family:var(--font-ui); font-size:.95rem; letter-spacing:.01em;
  color:var(--on-dark-soft);
}
/* Preserve the source orientation instead of forcing every photograph into
   one card size. Landscape frames use the requested 16:9 crop; the two
   portrait families retain their own 4:5 and 2:3 silhouettes. The shape is
   named on the figure rather than read off the image's pixel size, because
   not every photograph the school sends is large enough to be cut at the
   standard 1500 or 1000 pixels. */
.hframe--wide{ width:clamp(460px,46vw,690px); }
.hframe--wide img{ aspect-ratio:16 / 9; }
.hframe--portrait{ width:clamp(300px,29vw,430px); }
.hframe--portrait img{ aspect-ratio:4 / 5; }
.hframe--tall{ width:clamp(280px,26vw,390px); }
.hframe--tall img{ aspect-ratio:2 / 3; }

/* --- the written statements ------------------------------- */
.hsay{
  position:relative; inset:auto !important; z-index:2;
  flex:0 0 clamp(330px,34vw,540px);
  width:clamp(330px,34vw,540px);
  transform-style:preserve-3d; transform-origin:50% 50%;
  backface-visibility:hidden; will-change:transform;
}
.hsay__eyebrow{
  font-family:var(--font-body);
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.06em; font-size:.98rem; color:var(--gold);
  margin-bottom:clamp(16px,1.6vw,26px);
  transform:translateZ(68px);
}
.hsay__big{
  font-family:var(--font-display); font-weight:700; text-transform:none;
  font-size:clamp(1.8rem,3vw,3.2rem); line-height:.95;
  letter-spacing:-.03em; color:var(--on-dark);
  text-shadow:0 22px 42px rgba(42,42,38,.18);
  transform:translateZ(92px);
}
.hsay__sub{
  margin-top:clamp(18px,1.8vw,28px);
  color:var(--on-dark-soft); font-size:var(--fs-lead);
  transform:translateZ(38px);
}
.hsay--open{ width:clamp(320px,38vw,660px); }
.hsay--open .hsay__big{ font-size:clamp(2.1rem,4.2vw,4.4rem); }

/* --- the ghost words -------------------------------------- */
.hghost{
  display:none;
  position:absolute; z-index:0; pointer-events:none; white-space:nowrap;
  font-family:var(--font-display); font-weight:700; text-transform:none;
  font-size:clamp(4rem,12vw,14rem); line-height:.9; letter-spacing:-.045em;
  /* Below eight per cent on this ground it simply is not there. */
  color:var(--on-dark); opacity:.085;
  will-change:transform;
}

/* --- fallback: a native swipe track ----------------------- */
/* Absolute positions on a 780vw canvas mean nothing on a phone, so under
   900px — and with motion off, and if ScrollTrigger never arrives — the
   same items are laid out as an ordinary swipe track instead. Everything
   the canvas was carrying is unset here rather than scaled down. */
.hrun.is-static .hrun__pin{ height:auto; padding-block:clamp(56px,9vh,110px); }
.hrun.is-static .hrun__viewport{
  height:auto; overflow-x:auto; perspective:none;
  scroll-snap-type:x proximity; scroll-padding-inline-start:var(--gut);
  -webkit-overflow-scrolling:touch;
}
.hrun.is-static .hrun__viewport:focus-visible{outline:2px solid var(--on-dark);outline-offset:-3px}
.hrun.is-static .hrun__stage{
  width:auto; height:auto;
  display:flex; align-items:flex-start; gap:clamp(30px,7vw,72px);
  padding-inline:var(--gut);
}
.hrun.is-static .hframe,
.hrun.is-static .hsay{
  position:static; inset:auto !important; flex:none; transform:none; scroll-snap-align:start;
}
.hrun.is-static .hsay{ width:min(80vw,430px); }
.hrun.is-static .hsay > *{ transform:none; }
.hrun.is-static .hghost{ display:none; }
.hrun.is-static .hframe--xxl{ --h:44vh; }
.hrun.is-static .hframe--xl{ --h:38vh; }
.hrun.is-static .hframe--l { --h:32vh; }
.hrun.is-static .hframe--m { --h:28vh; }
.hrun.is-static .hframe--s { --h:24vh; }

.hrun.is-static .hframe--wide{ width:min(82vw,620px); }
.hrun.is-static .hframe--portrait{ width:min(68vw,400px); }
.hrun.is-static .hframe--tall{ width:min(62vw,360px); }

@media (max-width:700px){
  .hrun.is-static .hsay__big{ font-size:clamp(1.7rem,7vw,2.4rem); }
  .hrun.is-static .hframe--xxl,
  .hrun.is-static .hframe--xl,
  .hrun.is-static .hframe--l,
  .hrun.is-static .hframe--m,
  .hrun.is-static .hframe--s{ --h:30vh; }
}

@media (prefers-reduced-motion:reduce){
  .hsay > *{ transform:none; }
}

/* ============================================================
   Day — pinned horizontal timetable
   ============================================================ */
.dayh{ position:relative; background:var(--paper); }
.dayh__pin{ min-height:100svh; display:flex; flex-direction:column; justify-content:center; overflow:hidden; }
.dayh__head{ padding-top:clamp(80px,10vh,120px); }
.dayh__viewport{ overflow:hidden; padding-block:clamp(24px,3.5vh,48px); }
.dayh__track{
  display:flex; align-items:stretch; gap:clamp(18px,2.4vw,40px);
  padding-inline:var(--gut);
  will-change:transform;
}
.dmoment{
  flex:none; width:clamp(250px,29vw,380px);
  display:flex; flex-direction:column; gap:12px;
  padding-top:26px; border-top:2px solid var(--dark);
}
.dmoment__t{
  font-family:var(--font-display); font-size:clamp(2.2rem,3.6vw,3.2rem); line-height:.9;
  color:var(--dark); font-variant-numeric:oldstyle-nums; letter-spacing:-.015em;
}
.dmoment h3{ font-family:var(--font-display); font-size:var(--fs-h3); line-height:1.16; color:var(--ink); }
.dmoment p{ color:var(--ink-soft); font-size:var(--fs-sm); }
.dmoment__i{ font-family:var(--font-body); font-style:italic; color:var(--label); font-size:1.05rem; margin-top:auto; padding-top:14px; }

.dayh__rail{
  position:relative; margin:0 var(--gut);
  height:1px; background:var(--rule);
}
.dayh__fill{
  position:absolute; left:0; top:0; height:1px; width:0%;
  background:var(--gold);
}
.dayh__ticks{
  display:flex; justify-content:space-between; margin:12px var(--gut) 0;
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal;
  font-size:.92rem; letter-spacing:.12em; color:var(--ink-mute);
}
.dayh__ticks b{ color:var(--gold); font-weight:400; }

/* Fallback when the pin cannot run: a native swipe track. */
.dayh.is-static .dayh__pin{ min-height:0; }
.dayh.is-static .dayh__viewport{ overflow-x:auto; scroll-snap-type:x proximity; }
.dayh.is-static .dmoment{ scroll-snap-align:start; }
/* Snapping aligns a card's leading edge with the scroller's, which puts the
   first one hard against the edge of the screen and eats the gutter the
   track is padded with. Tell the scroller where its start really is. */
.dayh.is-static .dayh__viewport{ scroll-padding-inline-start:var(--gut); }
/* The rail is a readout of the scrub, and there is no scrub here: swiping
   the track leaves it sitting at zero, which reads as a progress bar that
   does not work. The two end labels still say what the track spans. */
.dayh.is-static .dayh__rail{ display:none; }
.dayh.is-static .dayh__tick{ visibility:hidden; }
.dayh.is-static .dayh__ticks{ margin-top:20px; }

/* ------------------------------------------------------------
   Two schools, two smaller tracks
   ------------------------------------------------------------
   There used to be one wide scroll of six moments standing for the
   whole campus, and a separate proportional ribbon carrying the two
   real timetables. The ribbon was the one telling the truth, so the
   timetables moved into these cards and the ribbon went away.

   Two tracks means two pins in a row, so everything here is smaller
   than the single scroll was: a shorter pin, narrower cards, less to
   read on each. What each card keeps from the ribbon is its colour —
   the rule above it is the ribbon's own key for that kind of hour, so
   the shape of the day is still legible as colour alone.
   ------------------------------------------------------------ */
/* The pin keeps the base 100svh. Anything shorter and the next track
   shows below the one being read, which reads as an unfinished screen
   rather than a smaller one. Smaller is bought on the cards instead. */
.dayh--duo .dayh__head{ padding-top:clamp(44px,6vh,72px); }
.dayh--duo .dayh__head .h2{ font-size:clamp(1.7rem,3.2vw,2.6rem); }
.dayh--duo .dayh__track{ gap:clamp(11px,1.4vw,22px); }
.dayh--duo .dmoment{
  width:clamp(152px,14vw,196px);
  gap:7px; padding-top:18px;
}
.dayh--duo .dmoment h3{ font-size:clamp(1rem,1.5vw,1.16rem); line-height:1.24; }

.dmoment__t i{
  font-style:normal; font-size:.38em; letter-spacing:.06em;
  margin-left:.18em; color:var(--ink-mute);
}
.dmoment__span{
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal;
  font-size:.92rem; letter-spacing:.1em; color:var(--ink-mute);
}

/* The six kinds of hour, as the ribbon coloured them. */
.dmoment--wake{   border-top-color:var(--sage); }
.dmoment--active{ border-top-color:var(--brand); }
.dmoment--spirit{ border-top-color:var(--label); }
.dmoment--meal{   border-top-color:var(--gold); }
.dmoment--study{  border-top-color:var(--dark); }
.dmoment--rest{   border-top-color:var(--decoration-mute); }

/* The key, which sits with the introduction rather than with either
   track, because it reads both of them. */
.daylegend{
  display:flex; flex-wrap:wrap; gap:8px 16px;
  margin:var(--space-5) 0 0; font-size:.8rem; color:var(--ink-soft);
}
.daykey{ display:inline-flex; align-items:center; gap:7px; }
.daykey::before{ content:""; width:11px; height:11px; border-radius:2px; flex:none; }
.daykey--wake::before{   background:var(--sage); }
.daykey--active::before{ background:var(--brand); }
.daykey--spirit::before{ background:var(--label); }
.daykey--meal::before{   background:var(--gold); }
.daykey--study::before{  background:var(--dark); }
.daykey--rest::before{   background:var(--decoration-mute); }

/* ============================================================
   News track — pinned horizontal reel of highlighted stories
   Same pin-and-scrub mechanism as Day above (see tools/build-site.py
   for none of this, it's all newsTrack() in cirs.js), reused rather
   than duplicated because the two are the same trick: a fixed-height
   viewport with an inner flex row scrubbed by scroll progress, and a
   native swipe track wherever that trick cannot run.
   ============================================================ */
.newstrack{ position:relative; background:var(--paper); }
.newstrack__pin{ min-height:92svh; display:flex; flex-direction:column; justify-content:center; overflow:hidden; }
.newstrack__head{ padding-top:clamp(70px,9vh,110px); }
.newstrack__hint{
  margin-top:10px; font-family:var(--font-body); font-style:italic;
  color:var(--ink-mute); font-size:.98rem;
}
.newstrack__viewport{ overflow:hidden; padding-block:clamp(24px,3.5vh,48px); }
.newstrack__track{
  display:flex; align-items:stretch; gap:clamp(18px,2.4vw,32px);
  padding-inline:var(--gut);
  will-change:transform;
}
.newstrack__track .newsitem{ flex:none; width:clamp(280px,32vw,420px); }

.newstrack__rail{ position:relative; margin:0 var(--gut); height:1px; background:var(--rule); }
.newstrack__fill{ position:absolute; left:0; top:0; height:1px; width:0%; background:var(--gold); }
.newstrack__count{
  display:block; margin:12px var(--gut) 0;
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal;
  font-size:.92rem; letter-spacing:.12em; color:var(--ink-mute);
}
.newstrack__count b{ color:var(--gold); font-weight:400; }

/* Fallback when the pin cannot run: a native swipe track, exactly Day's. */
.newstrack.is-static .newstrack__pin{ min-height:0; }
.newstrack.is-static .newstrack__viewport{ overflow-x:auto; scroll-snap-type:x proximity; }
.newstrack.is-static .newstrack__track .newsitem{ scroll-snap-align:start; }

/* ============================================================
   Campus band — duotone
   ============================================================ */
.band{ position:relative; background:var(--dark-ink); overflow:hidden; }
.band__media{ position:absolute; inset:0; }
.band__media img{ width:100%; height:100%; object-fit:cover; }
.band__media::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(102deg, rgba(24,24,21,.90) 0%, rgba(24,24,21,.76) 52%, rgba(24,24,21,.58) 100%);
}
.band__inner{ position:relative; z-index:2; padding-block:clamp(60px,7.5vw,116px); }
.facilities{
  display:grid; gap:0 clamp(20px,2.6vw,44px);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));
  margin-top:clamp(30px,3.4vw,52px);
}
.facilities > div{
  position:relative; padding:20px 0; border-top:1px solid var(--rule-dark);
  transition:transform .45s var(--e);
}
.facilities > div::after{
  content:""; position:absolute; left:0; top:-1px; height:1px; width:0;
  background:var(--gold); transition:width .5s var(--e);
}
.facilities > div:hover{ transform:translateY(-4px); }
.facilities > div:hover::after{ width:100%; }
.facilities h3{ font-family:var(--font-display); font-size:1.3rem; color:#fff; margin-bottom:6px; }
.facilities p{ font-size:var(--fs-sm); color:var(--on-dark-soft); }

/* ============================================================
   Record — large editorial figures
   ============================================================ */
.record{ display:grid; }
.record > div{
  display:grid; gap:8px clamp(28px,4vw,64px);
  padding-block:clamp(26px,3vw,44px);
  border-bottom:1px solid var(--rule-dark);
  align-items:baseline;
}
.record > div:first-child{ border-top:1px solid var(--rule-dark); }
@media (min-width:820px){ .record > div{ grid-template-columns:minmax(0,.36fr) minmax(0,1fr); } }
.record__fig{
  font-family:var(--font-display); font-size:clamp(3rem,6.4vw,5.6rem); line-height:.9;
  color:var(--gold-lit); letter-spacing:-.03em;
  font-variant-numeric:oldstyle-nums;
}
.record__fig sup{ font-size:.36em; vertical-align:super; letter-spacing:0; }
.record p{ color:var(--on-dark-soft); font-size:var(--fs-lead); line-height:1.5; max-width:50ch; }
.record p b{ color:#fff; font-weight:500; }

/* ============================================================
   Pathways chart
   ============================================================ */
.chart{ border:1px solid var(--rule); background:var(--white); overflow-x:auto; }
.chart svg{ width:100%; height:auto; min-width:680px; }
.chart .grat{ stroke:#E3DCCB; stroke-width:.6; fill:none; }
.chart .arc{ fill:none; stroke:var(--gold); stroke-width:.9; opacity:.7; }
.chart .node circle{ fill:var(--dark); transition:fill .25s var(--e); }
.chart .node text{ font-family:var(--font-ui); font-size:6.6px; font-weight:500; fill:#5A6771; }
.chart .node:hover circle,.chart .node:focus circle{ fill:var(--label); }
.chart .node:hover text,.chart .node:focus text{ fill:var(--label); }
.chart .origin circle{ fill:var(--gold); }
.chart .origin text{ fill:var(--label); font-weight:700; }

/* ============================================================
   Admissions
   ============================================================ */
.steps{ counter-reset:step; border-top:2px solid var(--dark); }
.step{
  display:grid; gap:6px 36px; padding-block:clamp(24px,2.8vw,40px);
  border-bottom:1px solid var(--rule-soft); align-items:start;
}
@media (min-width:880px){ .step{ grid-template-columns:78px 1fr 240px; } }
.step__n{
  counter-increment:step;
  font-family:var(--font-display); font-size:2.1rem; color:var(--gold);
  line-height:.9; font-variant-numeric:oldstyle-nums;
}
.step__n::before{ content:counter(step,decimal-leading-zero); }
.step h3{ margin-bottom:8px; color:var(--dark); }
.step p{ color:var(--ink-soft); font-size:var(--fs-sm); max-width:54ch; }
.step__aside{
  font-size:var(--fs-sm); color:var(--ink-mute); line-height:1.95;
  border-left:1.5px solid var(--gold); padding-left:16px;
}
.step__aside b{ color:var(--dark); font-weight:600; }
@media (max-width:879px){ .step__aside{ margin-top:12px; } }

.adm-cta{
  display:flex; flex-wrap:wrap; gap:14px 26px; align-items:center;
  margin-top:clamp(28px,3.2vw,46px); padding-top:26px; border-top:1px solid var(--rule);
}
.adm-cta__contact{ font-size:var(--fs-sm); color:var(--ink-mute); }
.adm-cta__contact a{ color:var(--dark); font-weight:500; }

/* ============================================================
   Leadership quote — a placeholder portrait (initials, not a
   photograph) until the school supplies one.
   ============================================================ */
/* ============================================================
   Official film panel — cinematic full-bleed banner between the
   hero and the Principal's message; links out to YouTube rather
   than embedding a player.
   ============================================================ */
.filmsec{ position:relative; background:var(--dark-ink); overflow:hidden; }
.filmsec__media{ position:absolute; inset:0; }
.filmsec__media img{ width:100%; height:100%; object-fit:cover; opacity:.34; }
.filmsec__media::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(180deg, rgba(17,17,15,.74) 0%, rgba(17,17,15,.95) 100%);
}
.filmsec__inner{ position:relative; z-index:2; padding-block:clamp(64px,7.5vw,120px); }
.filmsec .lead{ color:var(--on-dark-soft); }

.filmwin{
  display:block; position:relative; margin:clamp(36px,5vw,56px) auto 0; max-width:920px;
  aspect-ratio:16/9; overflow:hidden; border-radius:6px; border:1px solid var(--rule-dark);
  background:var(--dark-deep); cursor:pointer;
}
.filmwin__bg{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.filmwin__scrim{
  position:absolute; inset:0;
  background:linear-gradient(180deg, rgba(17,17,15,.18) 0%, rgba(17,17,15,.72) 100%);
}
.filmwin__play{
  position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
  width:76px; height:76px; border-radius:50%; display:grid; place-items:center;
  background:var(--gold); color:var(--dark-ink);
  transition:transform .3s var(--e), background .3s var(--e);
}
.filmwin:hover .filmwin__play{ transform:translate(-50%,-50%) scale(1.08); background:var(--gold-lit); }
.filmwin__play svg{ margin-left:3px; }
.filmwin__label{
  position:absolute; left:20px; bottom:16px; z-index:2; color:#fff;
  font-family:var(--font-body); font-size:var(--fs-sm); letter-spacing:.01em;
}
.filmwin__label b{ font-weight:600; }
.filmwin__badge{
  position:absolute; right:18px; top:16px; z-index:2;
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal; letter-spacing:.09em; font-size:.9rem;
  color:var(--on-dark-soft); border:1px solid var(--rule-dark);
  padding:4px 12px; border-radius:99px;
}

.filmsec__social{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
  gap:9px 22px; margin-top:clamp(26px,3.2vw,38px);
}
.filmsec__socialtag{ color:var(--gold-lit); margin-right:2px; }
.filmsec__social a{ color:var(--on-dark-soft); font-family:var(--font-ui); font-size:var(--fs-sm); }
.filmsec__social a:hover{ color:var(--gold-lit); }
/* The icon row, drawn as the Enquire panel's social row is. Without a size
   the four links collapsed to nothing: invisible, yet still keyboard stops. */
.filmsec__sociallinks{ display:flex; flex-wrap:wrap; justify-content:center; gap:10px; }
.filmsec__sociallinks a{
  display:grid; width:44px; height:44px; place-items:center; border-radius:50%;
  border:1px solid var(--rule-dark);
  transition:background .22s var(--e), color .22s var(--e), border-color .22s var(--e), transform .22s var(--e);
}
.filmsec__sociallinks svg{ width:21px; height:21px; overflow:visible; }
.filmsec__sociallinks svg :is(rect,circle){ fill:none; stroke:currentColor; stroke-width:1.65; }
.filmsec__sociallinks svg path,
.filmsec__sociallinks svg .social-dot{ fill:currentColor; stroke:none; }
.filmsec__sociallinks svg .social-play{ fill:var(--dark-ink); }
.filmsec__sociallinks a:hover,
.filmsec__sociallinks a:focus-visible{
  background:var(--gold-lit); border-color:var(--gold-lit); color:var(--dark-ink);
  transform:translateY(-2px);
}
.filmsec__sociallinks a:hover .social-play,
.filmsec__sociallinks a:focus-visible .social-play{ fill:var(--gold-lit); }

.quote{ background:var(--paper); }
.quote__grid{
  display:grid; grid-template-columns:minmax(280px,38%) 1fr; align-items:stretch;
}
.quote__photo{
  position:relative; overflow:hidden; min-height:460px;
  background:var(--dark-deep); margin:0;
}
.quote__photo img{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; object-position:center 12%;
}
.quote__panel{
  display:flex; align-items:center;
  padding:clamp(48px,6.4vw,96px) clamp(28px,6vw,84px);
}
.quote__inner{ max-width:640px; }
.quote__rule{ display:block; width:52px; height:2px; background:var(--gold); margin-bottom:var(--space-4); }
.quote__rule--btm{ margin-top:var(--space-4); margin-bottom:var(--space-3); }
@media (max-width:799px){
  .quote__grid{ grid-template-columns:1fr; }
  .quote__photo{ aspect-ratio:3/4; min-height:0; }
  .quote__photo img{ object-position:center top; }
}
.quote__text{
  font-family:var(--font-quote); font-style:italic; color:var(--ink);
  font-size:clamp(1.15rem,1.9vw,1.55rem); line-height:1.5;
}
.quote__text + .quote__text{ margin-top:.85em; }
.quote__attr{
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal; letter-spacing:.1em; font-size:1rem; color:var(--ink-mute);
}
.quote__attr b{ color:var(--dark); font-weight:600; }
/* ============================================================
   Feature panel — an alternating two-column component reused for
   every top-level destination (Why CIRS, Junior/Senior School,
   Athletics, Arts …), the same pattern repeated once per section.
   ============================================================ */
.feature{ padding-block:clamp(var(--space-8),7vw,var(--space-9)); }
.feature__inner{ display:grid; gap:var(--space-6); align-items:center; }
@media (min-width:900px){
  .feature__inner{ grid-template-columns:1.05fr .95fr; gap:var(--space-8); }
  .feature--reverse .feature__inner{ grid-template-columns:.95fr 1.05fr; }
  .feature--reverse .feature__media{ order:2; }
  .feature--reverse .feature__text{ order:1; }
}
.feature__media{ position:relative; aspect-ratio:4/5; overflow:hidden; background:var(--dark-deep); }
.feature__media img{ width:100%; height:100%; object-fit:cover; }
.feature__media.is-placeholder{ display:grid; place-items:center; }
.feature__ph{
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal; letter-spacing:.06em;
  color:var(--on-dark-mute); text-align:center; padding:var(--space-4);
  border:1px dashed var(--rule-dark);
}
/* ============================================================
   Our People — board of directors grid, reusing the .feature__media
   photo/placeholder pattern at 4:5, plus the full staff photo below.
   ============================================================ */
.peoplegrid{
  display:grid; grid-template-columns:repeat(auto-fill,minmax(230px,1fr));
  gap:40px 28px; margin-top:clamp(36px,4vw,56px);
}
.peopletile .feature__media{ aspect-ratio:4/5; }
.peopletile .feature__media img{ object-position:center top; }
.peopletile__body{ margin-top:16px; }
.peopletile__role{ color:var(--dark); margin:4px 0 10px; }
.peopletile__bio{ font-size:var(--fs-sm); color:var(--ink-mute); }

.teamphoto{
  margin:clamp(48px,5.6vw,72px) 0 0;
}
.teamphoto img{
  display:block; width:100%; height:auto; border-bottom:3px solid var(--gold);
}
.teamphoto figcaption{
  margin-top:14px; font-family:var(--font-ui); font-style:italic;
  font-size:var(--fs-sm); color:var(--ink-mute);
}

.feature__tag{
  font-family:var(--font-ui); font-style:italic; color:var(--label);
  font-size:1.08rem; margin:var(--space-2) 0 var(--space-3);
}
.feature__cta{ margin-top:var(--space-5); }

/* ============================================================
   Closing CTA band
   ============================================================ */
.finalcta{ position:relative; background:var(--dark-ink); overflow:hidden; }
.finalcta__media{ position:absolute; inset:0; }
.finalcta__media img{ width:100%; height:100%; object-fit:cover; opacity:.5; }
.finalcta__media::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(180deg, rgba(24,24,21,.55) 0%, rgba(24,24,21,.94) 100%);
}
.finalcta__inner{
  position:relative; z-index:2; text-align:center;
  max-width:760px; margin-inline:auto;
  padding-block:clamp(var(--space-9),10vw,var(--space-10));
}
.finalcta h2{ color:#fff; margin-bottom:var(--space-4); }
.finalcta .lead{ color:rgba(255,255,255,.82); margin-inline:auto; }
.finalcta__cta{ display:flex; flex-wrap:wrap; gap:var(--space-3); justify-content:center; margin-top:var(--space-6); }

/* ============================================================
   Footer
   ============================================================ */
.footer{ background:var(--brand-deep); color:var(--on-dark-soft); }
.footer__main{ display:grid; gap:clamp(28px,3.4vw,52px); padding-block:clamp(48px,5.4vw,80px); }
@media (min-width:900px){ .footer__main{ grid-template-columns:1.4fr 1fr 1fr 1fr 1fr; } }
.footer__utility{
  display:flex; flex-wrap:wrap; gap:var(--space-2) var(--space-5);
  padding-bottom:var(--space-5); font-size:var(--fs-xs);
}
.footer__utility a{ color:var(--on-dark-mute); }
.footer__utility a:hover{ color:#fff; }
/* Each column's label, one pattern for all four. */
.footer__main .sc{ margin-bottom:14px; }
.footer li a{ display:block; padding:5px 0; font-size:var(--fs-sm); transition:color .2s var(--e); }
.footer li a:hover{ color:#fff; }
.footer__brand{ display:flex; gap:14px; align-items:flex-start; margin-bottom:18px; }
.footer__brand img{ width:58px; flex:none; }
.footer__brand span{ font-family:var(--font-display); color:#fff; font-size:1.2rem; line-height:1.24; }
.footer address{ font-style:normal; font-size:var(--fs-sm); line-height:1.95; }
.footer address a{ color:var(--on-dark-soft); }
.footer address a:hover{ color:#fff; }
.footer__bar{
  display:flex; flex-wrap:wrap; gap:8px 28px; justify-content:space-between;
  padding-block:18px; border-top:1px solid var(--rule-dark);
  font-size:var(--fs-xs); color:var(--on-dark-mute);
}
/* Below 1366px the floating controls sit over the page, not beside it, and
   at the very end of a page that is over the footer's last lines. The bar
   keeps them clear: room for back-to-top, and on a page with an "On this
   page" index, for that button above it too. */
@media (max-width:1365px){
  .footer__bar{ padding-bottom:calc(18px + 48px + var(--float-edge)); }
  body:has(.jump) .footer__bar{ padding-bottom:calc(18px + 48px + 12px + 38px + var(--float-edge)); }
}

/* ============================================================
   Prototype notes
   ============================================================ */
.note{
  font-size:var(--fs-xs); color:var(--ink-mute); line-height:1.75;
  border-left:1.5px solid var(--rule); padding-left:14px; max-width:68ch; margin-top:24px;
}
.on-dark .note{ color:var(--on-dark-mute); border-left-color:var(--rule-dark); }

/* ============================================================
   Trailing cursor ring — fine pointers only, native cursor kept
   ============================================================ */
.ring{
  position:fixed; top:0; left:0; z-index:500;
  width:34px; height:34px; border-radius:50%;
  border:1px solid #fff; mix-blend-mode:difference;
  pointer-events:none; opacity:0;
  transform:translate(-50%,-50%);
  transition:width .3s var(--e), height .3s var(--e), opacity .3s var(--e);
  will-change:transform;
}
.ring.is-big{ width:62px; height:62px; }
@media (hover:none),(pointer:coarse){ .ring{ display:none; } }

/* ============================================================
   Credentials ticker
   ============================================================ */
.ticker{
  background:var(--dark-ink); color:var(--on-dark-soft);
  padding-block:15px; overflow:hidden;
  border-block:1px solid rgba(255,255,255,.10);
}
.ticker__track{ display:flex; width:max-content; will-change:transform; }
.ticker__set{ display:flex; align-items:center; flex:none; }
.ticker__set span{
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal;
  font-size:1.06rem; letter-spacing:.06em; white-space:nowrap;
  padding-inline:clamp(18px,2.4vw,38px);
}
.ticker__set i{ width:4px; height:4px; border-radius:50%; background:var(--gold); flex:none; }

/* ============================================================
   Back to top
   ============================================================ */
/* The corner the floating controls sit in. 24px at most, so back-to-top and
   the "On this page" button above it fit the margin beside the reading
   column from 1366px up instead of sitting over the text. */
:root{ --float-edge:clamp(16px,1.7vw,24px); --float-size:48px; }
/* On a phone the pair move closer to the edge and down to 44px, still a full
   touch target, so the lane cirs.js keeps clear of text for them ("Floating
   controls give way to the reading") costs the column 52px, not 66px. */
@media (max-width:560px){
  :root{ --float-edge:max(6px, env(safe-area-inset-right)); --float-size:44px; }
}
.totop{
  position:fixed; right:var(--float-edge); bottom:var(--float-edge);
  z-index:110; width:var(--float-size); height:var(--float-size); border-radius:50%;
  background:var(--dark); color:#fff;
  display:grid; place-items:center;
  opacity:0; visibility:hidden; transform:translateY(10px);
  transition:opacity .35s var(--e), transform .35s var(--e), visibility .35s, background .25s var(--e);
  box-shadow:0 6px 24px rgba(24,24,21,.28);
}
.totop.is-on{ opacity:1; visibility:visible; transform:none; }
.totop:hover{ background:var(--gold); color:var(--on-gold); }
.on-dark :focus-visible,.filmsec :focus-visible,.footer :focus-visible,.finalcta :focus-visible,.band :focus-visible{ outline-color:var(--gold-lit); }
/* Below 900px there is no margin beside the text for the two floating
   buttons, so cirs.js keeps a lane down the right-hand edge clear of text:
   it marks the wrappers that inset the text from that edge with
   .float-lane and the right padding each needs in --float-pad. Only the
   right padding changes, so a wrapper's background still runs to the edge.
   The buttons also step aside while the page is read downwards and return
   when it is scrolled back up, which keeps them off photographs and links
   in the lane too. Faded and out of the pointer's way, not hidden: a
   button reached with the keyboard comes straight back. */
@media (max-width:900px){
  .float-lane{ padding-right:var(--float-pad) !important; }
  /* A button that filled the old column wraps its words in the narrower
     one rather than running out into the lane. */
  .float-lane .btn{ max-width:100%; white-space:normal; }
  .jump{ transition:opacity .3s var(--e), transform .3s var(--e); }
  html.floats-tucked .totop.is-on:not(:focus-visible),
  html.floats-tucked .jump:not(:focus-within){
    opacity:0; transform:translateY(14px); pointer-events:none;
  }
}
@media (max-width:900px) and (prefers-reduced-motion:reduce){
  .jump{ transition:opacity .3s var(--e); }
  html.floats-tucked .totop.is-on:not(:focus-visible),
  html.floats-tucked .jump:not(:focus-within){ transform:none; }
}

/* ============================================================
   Footer reveal — content scrolls away over a fixed footer
   ============================================================ */
.footer-wrap{ position:sticky; bottom:0; z-index:0; }
/* A footer taller than the window cannot be revealed from underneath: pinned
   by its bottom edge, its top never comes into view. On a phone that was the
   address, the telephone and the first columns of links. cirs.js sets is-tall
   whenever the footer outgrows the window, and it then simply scrolls. */
.footer-wrap.is-tall{ position:relative; }
main{ position:relative; z-index:1; background:var(--paper); }

/* ============================================================
   Motion primitives
   ============================================================ */

/* Opening curtain. Removed from the document once it has played.
   One loading screen for every page: the home page's ivory, lettered in
   the roles that hold against it — --ink at 15.68:1, --ink-soft at 7.32:1.
   The progress hairline takes --gold-ink (4.48:1), because the bright gold
   is 2.1:1 on ivory and would read as an empty line for the whole load. */
.curtain{
  position:fixed; inset:0; z-index:400;
  background:var(--paper); color:var(--ink);
  display:grid; place-content:center; justify-items:center; gap:22px;
  text-align:center; padding:24px;
}
.curtain img{ width:72px; }
.curtain__deva{
  font-family:var(--deva); font-size:clamp(1.3rem,3.4vw,2.3rem);
  line-height:1.5; color:var(--ink);
}
.curtain__iast{
  margin-top:-14px;
  font-family:var(--font-quote); font-style:italic;
  font-size:clamp(1rem,1.5vw,1.2rem); line-height:1.3; color:var(--ink-soft);
}
.curtain__en{
  font-family:var(--font-body); font-variant-caps:normal;
  font-feature-settings:normal;
  font-size:.95rem; letter-spacing:.06em; color:var(--ink-soft);
}
.curtain__bar{ width:min(240px,50vw); height:1px; background:rgba(31,31,27,.16); overflow:hidden; }
.curtain__bar i{ display:block; height:1px; width:0%; background:var(--gold-ink); }
.curtain[hidden]{ display:none; }

/* Scroll progress hairline under the header */
.progress{
  position:fixed; top:0; left:0; height:2px; width:100%;
  transform:scaleX(0); transform-origin:left;
  background:var(--gold); z-index:120; pointer-events:none;
}

/* Line-split headings: each line rides up out of its own mask */
.line-mask{ display:block; overflow:hidden; }
.line-mask > span{ display:block; will-change:transform; }

/* Photographs are revealed by an opening clip, not a fade */
.img-reveal{ overflow:hidden; }
.img-reveal img{ will-change:transform; }

/* Figures rise out of a mask */
.fig-mask{ display:block; overflow:hidden; }
.fig-mask > span{ display:block; }

/* ============================================================
   Reveal — hidden only once JS confirms it can reveal again
   ============================================================ */
/* GSAP sets the start state itself via from(), so nothing is hidden in CSS.
   If the library never loads, the page simply renders. */
.rv{ transition:opacity .8s var(--e), transform .8s var(--e); }
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{ animation-duration:.001ms !important; transition-duration:.001ms !important; }
  .rv{ opacity:1 !important; transform:none !important; }
}

/* ============================================================
   Mobile
   ============================================================ */
@media (max-width:768px){
  :root{ --measure:58ch; }
  .hero__inner{ padding-block:56px 34px; }
  .hero__media img, .hero__media video{ object-position:center 44%; }
  .about{ grid-template-columns:1fr; }
  .dropcap::first-letter{ font-size:3.4em; }
  .chart{ overflow-x:auto; }
}

/* ============================================================
   The opening sequence
   ============================================================
   A 180vh track with a 100svh stage stuck to the top of it. The
   stage stands still through the 80vh past the first screen and
   that travel is the sequence's scrub distance.

   Pinning is `position: sticky` and nothing else. ScrollTrigger's
   own pin rewrites the document with a spacer, which on this site
   fights Lenis and moves the boundary the header's scroll state
   watches. Sticky costs neither.
   ============================================================ */
.hseq{ position:relative; background:var(--dark-ink); }
/* The track is the stage plus the travel. A 100svh stage in a 180svh
   track stands still for 80svh, and that 80 is the whole of the
   sequence's scrub. The plate reaches its frame at .62 of that — about
   half a screen of scrolling, which is the pace the opening always had
   — and the remaining 30svh is the hold: at a bare doubling the plate
   arrived on the same pixel the stage started leaving on, so the
   composition the sequence builds was never once seen at rest.

   It was 260svh when the plate had a second leg to travel. It has one
   destination now, so a shorter track carries it; leaving the old
   length in place would have spread the same movement over three times
   the scrolling and read as drag. */
.hseq__track{ height:180svh; height:180vh; }
.hseq__stage{
  position:sticky; top:0;
  height:100svh; height:100vh;
  overflow:hidden; isolation:isolate;
}

/* The two positions. These boxes are laid out and never painted;
   the script reads them and scrubs the plate between them, which is
   why a breakpoint can move the sequence without the script knowing
   a thing about it. Keep them in the stylesheet. */
.hseq__marks{ position:absolute; inset:0; z-index:0; pointer-events:none; visibility:hidden; }
.hseq__mark{ position:absolute; }
.hseq__mark--p0{ inset:0; }
/* The frame the sequence settles on: the photograph drawn in off all
   four edges, still wide, with the headline across the foot of it. The
   opening zooms out to here and stops. */
.hseq__mark--p1{ inset:4vh 6vw 10vh; }

/* The plate is always the full stage. The script reveals it through a
   clip-path and moves the photograph inside it with a transform, so the
   sequence never changes the size of a box: it used to scrub the plate's
   top, right, bottom and left, which re-laid-out the plate, resized the
   decoding video and counted as layout shift on every scroll frame. */
.hseq__plate{
  position:absolute; z-index:1;
  overflow:hidden;
  border-radius:0;
  inset:0;
}
/* Before the script has measured anything the video covers the plate by
   object-fit, which is P0 exactly. Once it has, the script gives the element
   the rectangle that cover would have drawn (same ratio, so nothing is
   cropped or stretched) and scales it from its own top-left. */
.hseq__video{
  width:100%; height:100%;
  max-width:none;
  object-fit:cover; object-position:center 42%;
  transform-origin:0 0;
  will-change:transform;
}

/* Lighter than a legible-at-any-cost wash: the campus is the point of
   the panel. It holds the lower third, where the marker and headline
   sit, and lets the ridge line through nearly clean. Measured against
   the painted pixels by tools/check-contrast.py, not guessed. */
.hseq__scrim{
  position:absolute; inset:0; z-index:2; pointer-events:none;
  transform-origin:0 0;
  will-change:transform, opacity;
  background:
    linear-gradient(to top, rgba(24,24,21,.95) 0%, rgba(24,24,21,.86) 18%,
                    rgba(24,24,21,.64) 38%, rgba(24,24,21,.20) 70%,
                    rgba(24,24,21,.32) 100%);
}

/* The type is positioned against the plate's own box, not the window,
   so the headline holds its relationship to the photograph at every
   viewport instead of drifting away from it as the plate insets. */
.hseq__type{
  position:absolute; z-index:3;
  left:clamp(20px,3vw,48px);
  bottom:clamp(24px,4vw,48px);
  width:min(1100px,92vw);
  will-change:transform, opacity;
}
.hseq__type .marker{ margin-bottom:var(--space-4); }
.hseq__type .sc{ color:var(--gold-lit); font-size:.92rem; }
.hseq__type .marker::after{ background:rgba(255,255,255,.28); max-width:120px; }
.hseq__type h1{ font-size:var(--fs-mega); color:#fff; line-height:.98; letter-spacing:-.02em; }
.hseq__type h1 em{ color:var(--gold-lit); }

/* Narrow: a phone has less height to spend on a margin than a desktop
   window has, and the headline below the frame needs the foot of the
   stage, so the inset pulls in on every edge. */
@media (max-width:900px){
  .hseq__mark--p1{ inset:2vh 4vw 8vh; }
}

/* Motion off, or no script: the sequence is one still full-bleed panel.
   The track collapses to a single screen so there is no empty scroll to
   cross, and nothing sticks. */
@media (prefers-reduced-motion:reduce){
  .hseq__track{ height:auto; }
  .hseq__stage{ position:relative; }
}
.hseq.is-static .hseq__track{ height:auto; }
.hseq.is-static .hseq__stage{ position:relative; }
.hseq.is-static .hseq__plate{ inset:0; border-radius:0; clip-path:none; }

/* ---- assets/css/pages.css ---- */
/* ============================================================
   Page-level components
   ------------------------------------------------------------
   assets/css/cirs.css is the design system, and it comes out of
   the Claude artifact — a single-page design. It has no notion of
   a site with ten pages in it, so the two components that only a
   multi-page site needs live here instead, in the repository,
   maintained by hand.

   Everything below is built from the tokens cirs.css already
   defines. Nothing here redefines a colour, a font or a spacing
   step of its own.
   ============================================================ */

/* ------------------------------------------------------------
   Page header — the banner that replaces the hero on every page
   except the home page. It carries .on-dark as well, so it
   inherits the dark-ground treatment already defined there:
   the gold small caps, the softened body copy, the hairline
   rules. It should not need a single colour of its own.
   ------------------------------------------------------------ */
.pagehead{
  position:relative;
  /* Clears the fixed header, which is about 76px tall, then adds
     the section's own breathing room underneath it. */
  padding-block:calc(76px + clamp(40px,5.5vw,84px)) clamp(40px,5.5vw,84px);
  overflow:hidden;
  background-image:
    radial-gradient(120% 140% at 50% -20%, rgba(201,169,97,.10) 0%, rgba(201,169,97,0) 60%);
}
.pagehead__inner{ max-width:820px; }
.pagehead h1{
  font-size:clamp(2.3rem,5vw,4.2rem);
  line-height:1.02;
  letter-spacing:-.018em;
  color:#fff;
}
.pagehead h1 em{ color:var(--gold-lit); }
.pagehead .lead{ margin-top:var(--space-4); }



/* ------------------------------------------------------------
   Under construction — the standing note at the foot of every
   page, so a visitor understands that what they are reading is
   not yet the finished thing.

   Deliberately quiet: a hairline, small caps and one line of
   italic serif. It has to be honest without looking like an
   error message on a school's front door.
   ------------------------------------------------------------ */
.uc{
  border-top:1px solid var(--rule);
  background:var(--paper);
}
.uc__inner{
  display:flex; align-items:flex-start; gap:var(--space-4);
  padding-block:clamp(30px,4vw,52px);
  max-width:var(--measure);
  margin-inline:auto;
  text-align:left;
}
.uc__mark{
  flex:none; width:38px; height:38px; border-radius:50%;
  display:grid; place-items:center;
  border:1px solid var(--gold);
  color:var(--gold-ink);
}
.uc__label{
  font-family:var(--font-body);
  font-variant-caps:normal;
  font-feature-settings:normal;
  letter-spacing:.06em; font-size:1rem;
  color:var(--label);
  line-height:1;
  margin-bottom:7px;
}
.uc__text{
  font-family:var(--font-body); font-style:italic;
  font-size:1.06rem; line-height:1.5; color:var(--ink-soft);
}
.uc__text a{ color:var(--dark); font-style:normal; font-weight:500; border-bottom:1px solid var(--rule); }
.uc__text a:hover{ border-bottom-color:var(--gold); }

@media (max-width:560px){
  .uc__inner{ gap:var(--space-3); }
  .uc__mark{ width:32px; height:32px; }
}

/* ------------------------------------------------------------
   Header, menu and Enquire: assets/css/drawer.css.
   ------------------------------------------------------------ */

/* ------------------------------------------------------------
   News
   ------------------------------------------------------------
   A lead story set large, then the rest as a grid of entries, then
   the term's diary. Built from the same rules the rest of the site
   uses: a 2px charcoal rule over each entry, oldstyle figures for
   dates, small caps for labels.
   ------------------------------------------------------------ */
.newslead{
  border-top:2px solid var(--dark);
  padding-top:var(--space-5);
}
.newslead__date,
.newsitem__date{
  font-family:var(--font-ui);
  font-variant-caps:normal;
  font-feature-settings:normal;
  font-variant-numeric:oldstyle-nums;
  letter-spacing:.06em; font-size:1rem; line-height:1;
  color:var(--label);
  margin-bottom:var(--space-3);
}
.newslead h2{ margin-bottom:var(--space-4); }
.newslead .copy{ max-width:64ch; }

.newsgrid{
  display:grid; gap:var(--space-6) clamp(24px,3vw,40px);
  grid-template-columns:repeat(auto-fill,minmax(min(100%,300px),1fr));
  margin-top:clamp(40px,5vw,64px);
}
/* A real card — this used to be a bare column under a rule. It is the
   same card used inside the horizontal .newstrack carousel below, so a
   story looks the same whether it landed in the grid or the highlights
   reel; .newstrack__track gives it a fixed width there. */
.newsitem{
  display:flex; flex-direction:column;
  background:var(--white); border:1px solid var(--rule); border-radius:20px;
  overflow:hidden;
  box-shadow:0 16px 36px rgba(17,17,15,.05);
  transition:transform .4s var(--e), box-shadow .4s var(--e);
}
.newsitem:hover{ transform:translateY(-5px); box-shadow:0 26px 52px rgba(17,17,15,.09); }
.newsitem__media{ aspect-ratio:16/10; }
.newsitem__body{ display:flex; flex-direction:column; flex:1; padding:var(--space-5) var(--space-5) var(--space-6); }
.newsitem__tag{
  align-self:flex-start;
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal; letter-spacing:.1em; font-size:.98rem;
  color:var(--dark); background:var(--gold);
  padding:3px 12px; border-radius:99px; margin-bottom:var(--space-3);
}
.newsitem__date{ display:block; margin-bottom:6px; }
.newsitem h3{ margin-bottom:var(--space-3); color:var(--dark); }
.newsitem p{ color:var(--ink-soft); font-size:var(--fs-sm); }
.newsitem__src{
  margin-top:auto; padding-top:var(--space-4);
  font-size:var(--fs-xs); color:var(--ink-mute);
}
.newsitem__src a{ color:var(--dark); font-weight:500; border-bottom:1px solid var(--rule); }
.newsitem__src a:hover{ border-bottom-color:var(--gold); }

/* The one clearly-marked slot for the next story: dashed rather than
   solid, and muted, so an editor can tell at a glance it is a template
   and not a published item. */
.newsitem--placeholder{
  background:none; border:1.5px dashed var(--rule); box-shadow:none;
}
.newsitem--placeholder:hover{ transform:none; box-shadow:none; }
.newsitem--placeholder .newsitem__body{ justify-content:center; text-align:center; flex:1; }
.newsitem--placeholder .newsitem__tag{ align-self:center; background:none; border:1px dashed var(--rule); color:var(--ink-mute); }
.newsitem--placeholder h3{ color:var(--ink-mute); font-style:italic; }
.newsitem--placeholder p{ color:var(--ink-mute); }

/* The diary. Dark ground, so the labels come out gold by the rule
   already defined for .on-dark. */
.diary{ border-top:1px solid var(--rule-dark); margin-top:clamp(30px,4vw,52px); }
.diary__row{
  display:grid; gap:4px var(--space-6); align-items:baseline;
  padding-block:var(--space-4);
  border-bottom:1px solid var(--rule-dark);
}
@media (min-width:720px){ .diary__row{ grid-template-columns:minmax(0,.34fr) minmax(0,1fr); } }
.diary__when{
  font-family:var(--font-ui);
  font-size:1.2rem; line-height:1.2;
  font-variant-numeric:oldstyle-nums;
  color:var(--gold-lit);
}
.diary__what{ color:var(--on-dark-soft); }

/* ------------------------------------------------------------
   Page hero — a banner in the home page's register
   ------------------------------------------------------------
   Most inner pages open with the flat .pagehead band. A page that
   has to sell something rather than inform gets this instead: the
   home hero's ingredients at two-thirds the height — full-bleed
   media, a scrim, the masked CIRS monogram, the small-caps eyebrow
   on a hairline, and the headline in the display face with the second
   clause in gold italic.
   ------------------------------------------------------------ */
.pagehero{
  position:relative;
  /* Full height: this banner is the page's opening, not a strip above it. */
  min-height:100svh;
  display:flex; flex-direction:column; justify-content:flex-end;
  background:var(--dark-ink);
  overflow:hidden;
}
/* Merge into the scroll rather than stopping at a hard edge. The section
   below is .advert, whose ground is --dark-deep, so that is what the
   banner has to arrive at: an earlier version faded to --paper and left a
   pale band stranded between two dark surfaces, which read as haze rather
   than a join.

   It also sits below .pagehero__inner (z-index 3) rather than above it. At
   z-index 4 the ramp veiled the dates it was passing over. */
.pagehero::after{
  content:""; position:absolute; left:0; right:0; bottom:0;
  height:clamp(160px,24vh,320px);
  z-index:2; pointer-events:none;
  background:linear-gradient(to bottom,
    rgba(24,24,21,0)    0%,
    rgba(24,24,21,.20) 30%,
    rgba(24,24,21,.48) 52%,
    rgba(24,24,21,.74) 70%,
    rgba(24,24,21,.92) 85%,
    var(--dark-deep) 100%);
}
.pagehero__media{ position:absolute; inset:0; z-index:0; background:center/cover no-repeat; }
.pagehero__media img{ width:100%; height:100%; object-fit:cover; }

/* Where the finished artwork is not in yet, the media slot carries a
   labelled placeholder rather than a stand-in photograph that someone
   might mistake for the real thing. */
.pagehero__ph{
  position:absolute; inset:0; display:grid;
  /* Top right, clear of the fixed header — the headline owns the lower
     left, and a placeholder should not compete with it. */
  place-items:start end;
  padding:calc(76px + clamp(18px,3vh,34px)) clamp(20px,4vw,64px) 0;
  background:
    radial-gradient(120% 130% at 50% 0%, #1F1F1B 0%, var(--dark-ink) 70%);
}
.pagehero__ph span{
  font-family:var(--font-ui);
  font-variant-caps:normal;
  font-feature-settings:normal;
  letter-spacing:.06em; font-size:1rem; line-height:1.7;
  color:var(--on-dark-mute); text-align:center;
  border:1px dashed var(--rule-dark);
  padding:var(--space-5) var(--space-6);
  max-width:min(90%,460px);
}

.pagehero__scrim{
  position:absolute; inset:0; z-index:2; pointer-events:none;
  /* The lower third carries the eyebrow, headline, lead, buttons and dates,
     so it is held dark; the middle stays open so the campus is still legible
     as a photograph. Measured, not guessed — tools/check-contrast.py samples
     the pixels behind each line and the lead was at 2.32:1 before this. */
  background:linear-gradient(to top,
    rgba(17,17,15,.94) 0%,
    rgba(17,17,15,.78) 34%,
    rgba(17,17,15,.30) 68%,
    rgba(17,17,15,.58) 100%);
}
.pagehero__inner{
  position:relative; z-index:3;
  padding-block:0 clamp(var(--space-7),6vw,var(--space-9));
  max-width:min(1000px,92vw);
}
.pagehero .marker{ margin-bottom:var(--space-4); }
.pagehero .marker::before{ border-color:var(--gold-lit); }
.pagehero .marker::after{ background:rgba(255,255,255,.28); max-width:120px; }
.pagehero h1{
  font-size:clamp(2.6rem,6.4vw,5.4rem);
  line-height:1.0; letter-spacing:-.02em; color:#fff;
}
.pagehero h1 em{ color:var(--gold-lit); }
.pagehero .lead{ color:rgba(255,255,255,.94); margin-top:var(--space-4); }
.pagehero__cta{ display:flex; flex-wrap:wrap; gap:var(--space-3); margin-top:var(--space-6); }

/* The dates, carried in the banner because the standing notice box that
   used to hold them is gone. */
.pagehero__dates{
  display:flex; flex-wrap:wrap; gap:var(--space-4) clamp(24px,3.4vw,52px);
  margin-top:var(--space-6);
  padding-top:var(--space-5);
  border-top:1px solid rgba(255,255,255,.20);
}
.pagehero__dates div{ min-width:0; }
.pagehero__dates dt{
  font-family:var(--font-ui);
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.06em; font-size:.92rem; color:var(--gold-lit); line-height:1;
  margin-bottom:7px;
}
.pagehero__dates dd{
  margin:0; color:#fff; font-size:var(--fs-lead); line-height:1.2;
  font-variant-numeric:oldstyle-nums;
}
.pagehero__dates dd small{ display:block; font-size:.8rem; color:rgba(255,255,255,.62); margin-top:5px; letter-spacing:.02em; }

/* The banner sits under the fixed header, so its content needs to clear it. */
.pagehero__inner{ padding-top:96px; }

/* ------------------------------------------------------------
   The headline reel — News, under the hero's buttons
   ------------------------------------------------------------
   One headline at a time, cycled by newsFlash() in cirs.js. The
   items are stacked in a single grid cell rather than positioned
   absolutely, so the strip is as tall as its tallest headline and
   nothing has to guess a min-height for the phone, where these wrap
   to two lines. Hidden items use visibility, which takes their links
   out of the tab order and off the accessibility tree — the reel is a
   way into stories the page already carries in full below, so a
   screen reader meets the one that is up and none of the rest.
   ------------------------------------------------------------ */
.newsflash{
  display:flex; align-items:center; gap:clamp(14px,2vw,26px);
  margin-top:var(--space-6); padding-top:var(--space-5);
  border-top:1px solid rgba(255,255,255,.20);
}
.newsflash__label{
  flex:none; display:inline-flex; align-items:center; gap:9px;
  padding:5px 14px; border-radius:99px;
  background:var(--gold); color:var(--dark);
  font-family:var(--font-body);
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.06em; font-size:.95rem; line-height:1;
}
.newsflash__dot{
  width:7px; height:7px; border-radius:50%; background:var(--dark);
  animation:flashpulse 1.8s var(--e) infinite;
}
@keyframes flashpulse{
  0%,100%{ opacity:1; transform:scale(1); }
  50%    { opacity:.35; transform:scale(.72); }
}
.newsflash__items{ display:grid; flex:1; min-width:0; }
.newsflash__item{
  grid-area:1/1; min-width:0;
  opacity:0; visibility:hidden; transform:translateY(9px);
  transition:opacity .55s var(--e), transform .55s var(--e);
}
.newsflash__item.is-on{ opacity:1; visibility:visible; transform:none; }
.newsflash__when{
  display:block; margin-bottom:5px;
  font-family:var(--font-ui);
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.06em; font-size:.86rem; line-height:1; color:var(--gold-lit);
  font-variant-numeric:oldstyle-nums;
}
.newsflash__what{
  font-family:var(--font-display); font-size:clamp(1.06rem,1.7vw,1.5rem);
  line-height:1.2; color:#fff; text-decoration:none;
  border-bottom:1px solid transparent; transition:border-color .3s var(--e);
}
.newsflash__what:hover, .newsflash__what:focus-visible{ border-bottom-color:var(--gold); }

@media (max-width:640px){
  .newsflash{ flex-direction:column; align-items:flex-start; gap:var(--space-3); }
}
@media (prefers-reduced-motion:reduce){
  .newsflash__item{ transition:none; transform:none; }
  .newsflash__dot{ animation:none; }
}

/* ------------------------------------------------------------
   The campaign panel
   ------------------------------------------------------------
   The school's admissions creative is a square graphic. Rather than
   drop it in as a foreign object, it sits on the site's own dark
   ground beside the claims it makes, set as real text — searchable,
   selectable, and readable to anyone the image never reaches.
   ------------------------------------------------------------ */
.advert{ position:relative; background:var(--dark-deep); overflow:hidden; }
.advert__inner{
  display:grid; gap:clamp(28px,4vw,64px); align-items:center;
  padding-block:clamp(48px,6vw,96px);
}
@media (min-width:900px){ .advert__inner{ grid-template-columns:1fr .9fr; } }

.advert__art{
  position:relative; aspect-ratio:1/1; overflow:hidden;
  background:var(--dark-ink);
  border:1px solid var(--rule-dark);
  display:grid; place-items:center;
}
.advert__art img{ width:100%; height:100%; object-fit:cover; }
.advert__art span{
  font-family:var(--font-ui);
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.06em; font-size:.98rem; line-height:1.7;
  color:var(--on-dark-mute); text-align:center;
  border:1px dashed var(--rule-dark); padding:var(--space-5); margin:var(--space-5);
}
.advert__tag{
  display:inline-flex; align-items:center; gap:9px;
  padding:8px 17px; border-radius:99px;
  background:var(--gold); color:var(--dark-ink);
  font-size:var(--fs-sm); font-weight:700; letter-spacing:.02em;
  margin-bottom:var(--space-4);
}
.advert__tag i{ width:7px; height:7px; border-radius:50%; background:var(--dark-ink); flex:none; }
.advert h2{ color:#fff; margin-bottom:var(--space-3); }
.advert__sub{
  font-family:var(--font-editorial); font-style:italic;
  font-size:clamp(1.1rem,1.7vw,1.4rem); color:var(--gold-lit);
  margin-bottom:var(--space-5);
}
.advert__claims{ border-top:1px solid var(--rule-dark); }
.advert__claims > div{
  display:flex; gap:var(--space-4); align-items:baseline;
  padding-block:var(--space-4); border-bottom:1px solid var(--rule-dark);
}
.advert__fig{
  flex:none; min-width:4.6ch;
  font-family:var(--font-display); font-size:clamp(1.5rem,2.4vw,2.1rem); line-height:1;
  color:var(--gold-lit); font-variant-numeric:oldstyle-nums;
}
.advert__claims p{ color:var(--on-dark-soft); font-size:var(--fs-sm); }
.advert__claims p b{ color:#fff; font-weight:600; }

/* ------------------------------------------------------------
   Admissions announcement — the panel shown on opening the page
   ------------------------------------------------------------ */
.pop{
  position:fixed; inset:0; z-index:300;
  display:grid; place-items:center;
  padding:var(--space-5);
  background:rgba(17,17,15,.72);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  opacity:0; visibility:hidden;
  transition:opacity .3s var(--e), visibility .3s;
}
/* Visible at once on opening, so the close button can take focus straight
   away; it is only on closing that visibility waits for the fade. */
.pop.is-open{ opacity:1; visibility:visible; transition:opacity .3s var(--e), visibility 0s; }
.pop__card{
  position:relative; width:min(100%,460px);
  /* Translucent rather than solid paper, so the photograph behind it stays
     part of the page — but only just translucent: at .93 the body text is
     still effectively black on near-white whatever is underneath. */
  background:rgba(250,249,243,.93); color:var(--ink);
  -webkit-backdrop-filter:blur(30px) saturate(1.4);
  backdrop-filter:blur(30px) saturate(1.4);
  padding:clamp(28px,4vw,44px);
  border-radius:22px; overflow:hidden;
  border:1px solid rgba(255,255,255,.55);
  box-shadow:0 30px 80px rgba(17,17,15,.5);
  transform:translateY(14px) scale(.98);
  transition:transform .34s var(--e2);
}
/* The gold rule that used to be a square border-top, now following the
   curve rather than cutting across it. */
.pop__card::before{
  content:""; position:absolute; top:0; left:0; right:0; height:3px;
  background:var(--gold);
}
.pop.is-open .pop__card{ transform:none; }
.pop__close{
  position:absolute; top:10px; right:10px;
  width:38px; height:38px; display:grid; place-items:center;
  color:var(--ink-mute); border-radius:50%;
  transition:background .2s var(--e), color .2s var(--e);
}
.pop__close:hover{ background:var(--paper-3); color:var(--dark); }
.pop__label{
  font-family:var(--font-body);
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.06em; font-size:1rem; color:var(--label); line-height:1;
  margin-bottom:var(--space-3);
}
.pop h2{ font-size:clamp(1.4rem,2.4vw,1.9rem); color:var(--dark); margin-bottom:var(--space-2); }
.pop__note{ color:var(--ink-soft); font-size:var(--fs-sm); margin-bottom:var(--space-5); }
.pop__row{
  display:flex; align-items:center; gap:var(--space-4);
  padding-block:var(--space-4); border-top:1px solid var(--rule);
}
.pop__row svg{ flex:none; color:var(--gold); }
.pop__row a{ color:var(--dark); font-weight:600; font-size:1.06rem; word-break:break-word; }
.pop__row a:hover{ color:var(--label); }
.pop__row small{ display:block; font-size:var(--fs-xs); color:var(--ink-mute); font-weight:400; letter-spacing:.02em; }
@media (prefers-reduced-motion:reduce){
  .pop, .pop__card{ transition-duration:.001ms; }
}

/* ------------------------------------------------------------
   On this page — an index that opens above the back-to-top button
   ------------------------------------------------------------
   A long page needs a way to reach the middle of it. The index is a
   native <details>: its summary is the button and comes before the
   list, so Tab goes from the button into the first link, and it opens
   with no script at all. It sits in the bottom-right corner, directly
   above back-to-top, at every width. It used to be centred on the
   right edge with its hidden panel counted in its height, which on a
   short screen (200% zoom, a phone on its side) dropped the button
   onto back-to-top and pushed the open list under the header. The
   list now opens upwards from the button and scrolls within itself
   when the screen is short.
   ------------------------------------------------------------ */
.jump{
  position:fixed; z-index:95;
  /* In line above the back-to-top button, 12px clear of it. */
  right:var(--float-edge);
  bottom:calc(var(--float-edge) + var(--float-size) + 12px);
}
.jump__toggle{
  display:inline-flex; align-items:center; justify-content:center; gap:9px;
  /* The icon alone, in a circle the size of back-to-top: a full-sized
     touch target rather than a sliver. */
  width:var(--float-size); height:var(--float-size); padding:0; border-radius:99px; cursor:pointer;
  list-style:none;
  background:rgba(24,24,21,.62);
  -webkit-backdrop-filter:blur(14px) saturate(1.3);
          backdrop-filter:blur(14px) saturate(1.3);
  border:1px solid rgba(255,255,255,.20);
  color:#fff; font-size:var(--fs-sm); font-weight:600; white-space:nowrap;
  box-shadow:0 6px 26px rgba(17,17,15,.30);
  transition:background .25s var(--e), border-color .25s var(--e), color .25s var(--e);
}
.jump__toggle::-webkit-details-marker{ display:none; }
.jump__toggle::marker{ content:""; }
.jump__toggle:hover,
.jump__details[open] > .jump__toggle{
  background:var(--gold); border-color:var(--gold); color:var(--dark-ink);
}
.jump__toggle svg{ flex:none; }
/* The label needs more room than the margin beside the reading column
   has below 1600px, so there the button is its icon alone and the
   words stay with screen readers — never over the text it indexes. */
.jump__label{
  position:absolute; width:1px; height:1px; overflow:hidden;
  clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap;
}
@media (min-width:1600px){
  .jump__toggle{ width:auto; height:auto; padding:11px 17px; }
  .jump__label{ position:static; width:auto; height:auto; overflow:visible; clip:auto; clip-path:none; }
}
.jump__panel{
  position:absolute; right:0; bottom:calc(100% + 10px);
  min-width:230px; max-width:min(78vw,300px);
  /* Never taller than the room between the header and the button. */
  max-height:calc(100vh - var(--float-edge) - 2 * var(--float-size) - 12px - 10px - 96px);
  max-height:calc(100dvh - var(--float-edge) - 2 * var(--float-size) - 12px - 10px - 96px);
  overflow-y:auto; overscroll-behavior:contain;
  padding:var(--space-4) var(--space-4) var(--space-3);
  border-radius:14px;
  /* Dense enough to hold its gold and ivory lettering over a light page:
     at .62 over ivory the glass measured #6E6E69, where gold was 2.3:1. */
  background:rgba(24,24,21,.9);
  -webkit-backdrop-filter:blur(18px) saturate(1.3);
          backdrop-filter:blur(18px) saturate(1.3);
  border:1px solid rgba(255,255,255,.20);
  box-shadow:0 14px 44px rgba(17,17,15,.42);
  transform-origin:bottom right;
  animation:jump-in .26s var(--e);
}
@keyframes jump-in{ from{ opacity:0; transform:translateY(8px) scale(.98); } }
.jump__panel p{
  font-family:var(--font-body);
  font-variant-caps:normal;
  font-feature-settings:normal;
  letter-spacing:.06em; font-size:.95rem; line-height:1;
  color:var(--gold-lit);
  padding-bottom:10px; margin-bottom:6px;
  border-bottom:1px solid rgba(255,255,255,.18);
}
.jump__panel a{
  display:block; padding:8px 0;
  font-size:var(--fs-sm); color:rgba(255,255,255,.84);
  transition:color .2s var(--e), padding-left .2s var(--e);
}
.jump__panel a:hover,
.jump__panel a:focus-visible{ color:var(--gold-lit); padding-left:5px; }
.jump__panel a[aria-current="true"]{ color:var(--gold); font-weight:600; }

@media (prefers-reduced-motion:reduce){
  .jump__panel{ animation:none; }
}

/* ------------------------------------------------------------
   Admissions — the pieces that make a procedure page readable
   ------------------------------------------------------------ */

/* The standing notice: what is open, and the one action to take. */
.notice{
  display:grid; gap:var(--space-4) var(--space-6); align-items:center;
  padding:clamp(22px,3vw,34px) clamp(22px,3.4vw,40px);
  background:var(--dark); color:var(--on-dark);
  background-image:radial-gradient(120% 160% at 12% -30%, rgba(201,169,97,.16) 0%, rgba(201,169,97,0) 62%);
}
@media (min-width:880px){ .notice{ grid-template-columns:1fr auto; } }
.notice__label{
  font-family:var(--font-body);
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.06em; font-size:1rem; color:var(--gold-lit);
  margin-bottom:8px; line-height:1;
}
.notice h2{ font-size:clamp(1.5rem,2.6vw,2.2rem); color:#fff; line-height:1.14; }
.notice p{ color:var(--on-dark-soft); font-size:var(--fs-sm); margin-top:10px; max-width:60ch; }
.notice__cta{ display:flex; flex-wrap:wrap; gap:var(--space-3); }

/* The examination tables. Tables are the honest form for a grid of
   subjects against a grade, so they stay tables — each in its own
   scroller so a phone never scrolls the page sideways. */
.tablewrap{ overflow-x:auto; border:1px solid var(--rule); background:var(--white); max-width:100%; }
/* A grid item defaults to min-width:auto, so it refuses to shrink below its
   content and the 520px table pushes the whole page sideways instead of
   scrolling inside .tablewrap. Letting the item shrink hands the overflow
   back to the scroller, where it belongs. */
.prog > *{ min-width:0; }
.tbl{ width:100%; border-collapse:collapse; min-width:520px; }
.tbl caption{
  text-align:left; padding:var(--space-4) var(--space-5) 0;
  font-family:var(--font-ui); font-style:italic; color:var(--ink-mute);
  font-size:var(--fs-sm);
}
.tbl th, .tbl td{
  text-align:left; padding:14px var(--space-5);
  border-bottom:1px solid var(--rule-soft);
  font-size:var(--fs-sm); vertical-align:top;
}
.tbl thead th{
  font-family:var(--font-ui);
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.12em; font-size:1rem; font-weight:400;
  color:var(--dark); border-bottom:2px solid var(--dark);
}
.tbl tbody th{ color:var(--dark); font-weight:600; white-space:nowrap; }
.tbl td{ color:var(--ink-soft); }
.tbl tbody tr:last-child th, .tbl tbody tr:last-child td{ border-bottom:0; }

/* The Important Documents list on School Information: titles only, grouped
   by category — the click-through to view or download lives on the portal
   page itself (.docportal, below), so this stays a scannable index rather
   than 22 repeated buttons. */
.docgrid{
  display:grid; gap:var(--space-7) clamp(24px,3vw,44px);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));
  margin-top:clamp(30px,3.4vw,52px);
}
.docgroup h3{ color:var(--dark); margin-bottom:var(--space-3); }
.doclist{ display:grid; gap:var(--space-2); }
.doclist li{
  position:relative; padding-left:var(--space-4);
  color:var(--ink-soft); font-size:var(--fs-sm); line-height:1.5;
}
.doclist li::before{
  content:""; position:absolute; left:0; top:.65em;
  width:5px; height:5px; border-radius:50%; background:var(--gold);
}

/* The Important Documents portal itself: every document, grouped, each a
   .step row (title, one line on what it covers, and a view/download button
   or an "awaiting upload" notice in the aside slot). */
.docportal__group{ margin-top:clamp(34px,3.6vw,56px); }
.docportal__group:first-child{ margin-top:0; }
.docportal__group .steps{ margin-top:var(--space-4); }
.docportal__jump{ margin-bottom:var(--space-7); }
.docportal__note{ margin-top:var(--space-8); }
.docportal__jump a,.docportal__note a{ color:var(--dark); font-weight:600; text-decoration:underline; text-underline-offset:.22em; }
.docportal__jump a{ white-space:nowrap; }

/* Testimonials. Portraits are placeholders until the school supplies
   them, and the quotes are marked as placeholders too — a made-up
   endorsement on a school's admissions page is not a placeholder,
   it is a lie, so these say plainly that they are waiting. */
.voices{
  display:grid; gap:var(--space-6) clamp(24px,3vw,44px);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,290px),1fr));
  margin-top:clamp(34px,4vw,54px);
}
.voice{
  display:flex; flex-direction:column;
  border-top:2px solid var(--dark); padding-top:var(--space-5);
}
.voice__mark{
  font-family:var(--font-display); font-size:3rem; line-height:.7;
  color:var(--gold); margin-bottom:var(--space-3);
}
.voice__text{
  font-family:var(--font-body); font-style:italic;
  font-size:1.12rem; line-height:1.5; color:var(--ink);
}
.voice__who{
  display:flex; align-items:center; gap:var(--space-3);
  margin-top:auto; padding-top:var(--space-5);
}
.voice__face{
  flex:none; width:46px; height:46px; border-radius:50%;
  display:grid; place-items:center;
  background:var(--paper-3); border:1px dashed var(--rule);
  font-family:var(--font-ui); font-size:.72rem; letter-spacing:.06em;
  color:var(--ink-mute); text-align:center; line-height:1;
}
.voice__name{ font-weight:600; color:var(--dark); font-size:var(--fs-sm); }
.voice__role{ font-size:var(--fs-xs); color:var(--ink-mute); }

/* A strip of photo slots, so the page has somewhere obvious for
   pictures to land. */
/* Three columns, so six tiles are two whole rows. auto-fit gave five
   columns at 1440px and four at 1280px, which left the last row part-empty
   and the grid looking broken rather than composed. */
.strip{
  display:grid; gap:clamp(12px,1.6vw,20px);
  grid-template-columns:repeat(3,1fr);
  margin-top:clamp(30px,3.6vw,48px);
}
@media (max-width:860px){ .strip{ grid-template-columns:repeat(2,1fr); } }
@media (max-width:520px){ .strip{ grid-template-columns:1fr; } }
.strip figure{
  margin:0; aspect-ratio:4/3; display:grid; place-items:center;
  background:var(--dark-deep); overflow:hidden;
}
/* Filled tiles: the photograph covers the tile whatever its own shape, so a
   4:3 and a square sit in the same grid without letterboxing either. */
.strip figure img{ width:100%; height:100%; object-fit:cover; display:block; }
.strip span{
  font-family:var(--font-ui);
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.06em; font-size:.92rem; line-height:1.6;
  color:var(--on-dark-mute); text-align:center;
  border:1px dashed var(--rule-dark); padding:var(--space-3) var(--space-4);
  margin:var(--space-4);
}

/* ------------------------------------------------------------
   Accents on the new dark grounds
   ------------------------------------------------------------
   cirs.css turns the label-purple small caps gold on every dark section
   it knows about. It cannot know about .pagehero and .advert,
   which are defined here — and left out, the eyebrow renders
   purple on near-black at 1.9:1, the exact failure that list was
   written to prevent. Any dark component added to this file has
   to be added here too.
   ------------------------------------------------------------ */
:is(.pagehero, .advert) :is(.sc, .feature__tag, .dmoment__i){ color:var(--gold-lit); }

/* The Admissions hero carries a looping video rather than a still. It sizes
   exactly like the image it replaced; the poster shows until the first frame
   arrives, and remains if the video is blocked or the connection gives up. */
.pagehero__video{ width:100%; height:100%; object-fit:cover; display:block; }
@media (prefers-reduced-motion:reduce){
  /* Honour the setting: the still behind the video is its own poster, set
     on .pagehero__media by hero_html(), so each hero keeps its picture. */
  .pagehero__video{ display:none; }
  .pagehero__media{ background-position:center; background-size:cover; background-repeat:no-repeat; }
}

/* ============================================================
   Film lightbox
   ------------------------------------------------------------
   Above the admissions popup (300) and below the opening curtain
   (400), so the film can never appear over the intro.
   ============================================================ */
.lightbox{ position:fixed; inset:0; z-index:350; display:grid; place-items:center; width:100%; height:100%; max-width:none; max-height:none; margin:0; padding:0; border:0; background:transparent; color:inherit; }
.lightbox::backdrop{ background:transparent; }
.lightbox[hidden]{ display:none; }
.lightbox__back{
  position:absolute; inset:0;
  background:rgba(7,7,6,.88);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
}
.lightbox__panel{
  position:relative;
  /* The height-derived width keeps 16:9 intact on short landscape screens. */
  width:min(1120px, 92vw, 145.7vh);
  aspect-ratio:16/9; max-height:82vh;
  background:#000;
  border:1px solid var(--rule-dark);
  border-radius:8px; overflow:hidden;
  box-shadow:0 40px 120px rgba(0,0,0,.6);
}
.lightbox__frame{ position:absolute; inset:0; }
.lightbox__frame iframe{ width:100%; height:100%; border:0; display:block; }
.lightbox__close{
  position:absolute; top:10px; right:10px; z-index:2;
  width:38px; height:38px; display:grid; place-items:center;
  border-radius:50%; cursor:pointer;
  background:rgba(17,17,15,.68);
  border:1px solid rgba(250,249,243,.24);
  color:var(--on-dark);
  transition:background .22s var(--e), color .22s var(--e);
}
.lightbox__close:hover{ background:var(--gold); color:var(--dark-ink); border-color:var(--gold); }
body.has-lightbox{ overflow:hidden; }
.lightbox__hint{
  position:absolute; left:16px; right:16px; bottom:clamp(10px, 3.2vh, 30px);
  margin:0; text-align:center; pointer-events:none;
  font-family:var(--font-ui); font-size:.8rem; letter-spacing:.04em;
  color:rgba(245,238,242,.62);
}
.lightbox__hint-touch{ display:none; }
.lightbox__exit,.lightbox__fallback{ pointer-events:auto; color:inherit; text-decoration:underline; text-underline-offset:.18em; }
.lightbox__exit{ padding:0; border:0; background:none; font:inherit; cursor:pointer; }
@media (pointer:coarse){
  .lightbox__hint-key{ display:none; }
  .lightbox__hint-touch{ display:inline; }
}

/* The window is a link, and a link that opens a player should say so. */
.filmwin{ cursor:pointer; }

/* ============================================================
   Glimpses of CIRS — the collage
   ------------------------------------------------------------
   Three bands of the school's own photographs, drifting in
   alternating directions, with individual frames cross-fading
   to others from the same pool. Two motions rather than one:
   the drift gives it the feel of film running through a gate,
   the fades stop any single frame from being the picture you
   remember.

   The drift is a CSS keyframe, not a script. GSAP arrives from
   a CDN and may not arrive at all; this section is the loudest
   thing on the page and must never sit still because a script
   failed. The fades are scripted, and their absence just leaves
   a moving wall — which is still the point.

   Every tile is 100% of the row's height and takes its width
   from an aspect ratio, so one square source serves a dozen
   shapes and the mosaic never letterboxes.
   ============================================================ */
.glimpse{
  position:relative;
  background:var(--dark-ink);
  padding-block:clamp(56px,7vw,104px);
  overflow:hidden;
}
.glimpse__head{ margin-bottom:clamp(28px,3.4vw,46px); max-width:760px; }
.glimpse__head .lead{ color:var(--on-dark-soft); }
.glimpse__head h2{ color:#fff; }

.glimpse__rows{
  display:grid; gap:clamp(8px,1vw,14px);
  /* The bands run off both edges rather than stopping at a border. */
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 5%,#000 95%,transparent 100%);
          mask-image:linear-gradient(90deg,transparent 0,#000 5%,#000 95%,transparent 100%);
}
.glimpse__row{ height:clamp(104px,13vw,178px); overflow:hidden; }
.glimpse__track{
  display:flex; width:max-content; height:100%;
  will-change:transform;
  animation:glimpse-drift 220s linear infinite;
}
/* The gap lives inside each set, so the track is exactly two sets wide and
   -50% lands on the seam. With the gap on the track it would not. */
.glimpse__set{ display:flex; gap:clamp(8px,1vw,14px); padding-right:clamp(8px,1vw,14px); flex:none; height:100%; }
.glimpse__row--b .glimpse__track{ animation-duration:265s; animation-direction:reverse; }
.glimpse__row--c .glimpse__track{ animation-duration:240s; }
@keyframes glimpse-drift{ from{ transform:translateX(0); } to{ transform:translateX(-50%); } }

/* Stop under the pointer, so anything worth a second look can have one. */
.glimpse__row:hover .glimpse__track{ animation-play-state:paused; }

.gt{
  position:relative; margin:0; flex:none; height:100%;
  overflow:hidden; border-radius:3px;
  background:var(--dark-deep);
  /* mix-blend-mode below must not reach past the tile. */
  isolation:isolate;
}
.gt--w1{ aspect-ratio:1/1; }
.gt--w2{ aspect-ratio:4/3; }
.gt--w3{ aspect-ratio:3/4; }
.gt img{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; display:block;
  /* Drained here and tinted by the overlay: a real duotone rather than a
     tinted sheet laid over a colour photograph. */
  filter:grayscale(1) contrast(1.14) brightness(.97);
  transition:filter .55s var(--e);
}

/* Every tile holds two frames and swings A -> B -> A for ever, the way
   make-honeycomb.py pairs each cell with a second photograph and crosses
   between them across the loop. Each tile's delay is set in the markup,
   staggered seven ways, so no two neighbours turn together and the wall is
   never all mid-fade at once. Nothing is swapped in or out while visible,
   so there is no moment where a frame appears rather than arrives. */
.gt__b{ animation:gt-cross 16s ease-in-out infinite; }
@keyframes gt-cross{
  0%   { opacity:0; }
  42%  { opacity:1; }
  58%  { opacity:1; }
  100% { opacity:0; }
}

/* The duotone, and the colour underneath it.
   The wall reads as one warm monochrome surface until you point at it; the tile you
   are looking at returns to the photograph it actually is. Hovering also
   pauses the band, so the two gestures are the same gesture. */
.gt::after{
  content:""; position:absolute; inset:0; z-index:2; pointer-events:none;
  background:linear-gradient(155deg, #4A4944 0%, var(--dark) 58%, var(--dark-ink) 100%);
  mix-blend-mode:color;
  opacity:.95;
  transition:opacity .55s var(--e);
}
.gt::before{
  content:""; position:absolute; inset:0; z-index:3; pointer-events:none;
  background:linear-gradient(155deg, rgba(232,217,181,.42) 0%, rgba(232,217,181,.10) 48%, transparent 78%);
  mix-blend-mode:soft-light;
  transition:opacity .55s var(--e);
}
.gt:hover::after,
.gt:hover::before{ opacity:0; }
.gt:hover img{ filter:none; }
.gt:hover{ z-index:4; }

@media (prefers-reduced-motion:reduce){
  .glimpse__track{ animation:none; }
  .gt__b{ animation:none; opacity:0; }
}

/* ============================================================
   Parent Portal — a page that is honest about being unbuilt
   ------------------------------------------------------------
   The small .uc notice at the foot of other pages says a page is
   still growing. Here the whole page is the notice, so it is
   stated at full size: a visitor who came looking for a login
   should know within a second that there isn't one, without
   reading a paragraph to find out.

   It stays on the site's dark charcoal with the gold accent, so
   it reads as part of the school rather than an error page.
   ============================================================ */
/* The page is short and opens on a small badge, so the section's usual
   top padding left a stretch of empty dark ground under the banner. */
.ucpage{ background:var(--dark-deep); padding-block-start:clamp(38px,4.4vw,60px); }
.ucpage__inner{ max-width:760px; }

.ucpage__badge{
  display:inline-flex; align-items:center; gap:10px;
  margin:0 0 var(--space-5);
  padding:9px 18px 9px 14px;
  border:1px solid rgba(201,169,97,.42);
  border-radius:99px;
  background:rgba(201,169,97,.10);
  color:var(--gold-lit);
  font-family:var(--font-ui);
  font-variant-caps:normal;
  font-feature-settings:normal;
  letter-spacing:.06em; font-size:1rem; line-height:1;
}
.ucpage__dot{
  width:9px; height:9px; border-radius:50%; background:var(--gold); flex:none;
  animation:ucpulse 2.4s ease-in-out infinite;
}
@keyframes ucpulse{ 0%,100%{ opacity:1; transform:scale(1); } 50%{ opacity:.45; transform:scale(.82); } }
@media (prefers-reduced-motion:reduce){ .ucpage__dot{ animation:none; } }

.ucpage__head{
  color:#fff;
  font-size:clamp(2.1rem,4.6vw,3.5rem);
  line-height:1.08; margin:0 0 var(--space-4);
}
.ucpage__head em{ color:var(--gold-lit); }
.ucpage .lead{ color:var(--on-dark-soft); margin:0 0 var(--space-4); }

/* The doors out to the systems that are already running. They are the one
   thing on these pages a visitor may have come to use, so they are buttons
   rather than another row in a list — and the note under them says where
   they lead, because a login screen on a different domain with the school's
   name on it is exactly what a visitor should be taught to distrust. */
.ucpage__doors{
  display:flex; flex-wrap:wrap; gap:var(--space-3);
  margin:0 0 var(--space-3);
}
.ucpage__doornote{
  color:var(--on-dark-mute); font-size:.82rem; letter-spacing:.03em;
  margin:0 0 var(--space-4);
}

.ucpage__ph{
  color:var(--on-dark-mute); font-size:.95rem;
  border-left:2px solid var(--rule-dark);
  padding-left:var(--space-4); margin:0;
}
.ucpage__rule{
  height:1px; background:var(--rule-dark);
  margin:clamp(30px,4vw,48px) 0;
}

.ucpage__reachlabel{ color:var(--gold-lit); margin:0 0 var(--space-4); letter-spacing:.06em; }
.ucpage__rows{ display:grid; gap:var(--space-2); }
.ucpage__row{
  display:flex; align-items:center; gap:var(--space-4);
  padding:14px 16px; margin:0 -16px;
  border-radius:7px; color:var(--on-dark);
  transition:background .22s var(--e), color .22s var(--e);
}
.ucpage__ico{ display:grid; place-items:center; color:var(--gold-lit); flex:none; }
.ucpage__txt{ display:block; min-width:0; }
.ucpage__txt b{ display:block; font-weight:500; font-size:1.04rem; overflow-wrap:anywhere; }
.ucpage__txt small{
  display:block; margin-top:3px; font-size:.78rem; letter-spacing:.04em;
  color:var(--on-dark-soft);
}
.ucpage__row:hover,
.ucpage__row:focus-visible{ background:rgba(201,169,97,.13); color:#fff; }
.ucpage__row:hover .ucpage__ico{ color:var(--gold); }

.ucpage__foot{
  margin:clamp(30px,4vw,48px) 0 0;
  color:var(--on-dark-soft); font-size:.95rem;
}
.ucpage__foot a{ color:var(--gold-lit); text-decoration:underline; text-underline-offset:3px; }
.ucpage__foot a:hover{ color:#fff; }

/* ============================================================
   School History — the timeline
   ------------------------------------------------------------
   A vertical spine, because a history reads downwards and a
   phone has height to spare where it has no width. Nothing is
   hidden at any width: every milestone's year, heading and text
   are in the page from the start, and scrolling only *activates*
   them. That is the difference between an archive and a slide
   show — a reader who cannot hover, cannot scroll, or has
   JavaScript off still gets the whole history.

   Hovering or focusing a milestone brings its frame forward.
   On a touch screen there is no hover, so the same emphasis is
   applied by the script as each milestone reaches the middle of
   the screen.
   ============================================================ */
.tl{ background:var(--dark-deep); }
.tl .lead{ color:var(--on-dark-soft); }
.tl__body{ position:relative; margin-top:clamp(32px,4vw,56px); }

/* The spine and the line that fills as you go. */
.tl__spine{
  position:absolute; left:7px; top:6px; bottom:6px; width:2px;
  background:var(--rule-dark); border-radius:2px;
}
.tl__fill{
  display:block; width:100%; height:0;
  background:linear-gradient(180deg, var(--gold) 0%, var(--gold-lit) 60%, rgba(201,169,97,.35) 100%);
  border-radius:2px;
  box-shadow:0 0 14px rgba(201,169,97,.35);
}
@media (min-width:900px){ .tl__spine{ left:120px; } }

.tl__list{ list-style:none; margin:0; padding:0; display:grid; gap:clamp(28px,3.4vw,52px); }
.tl__item{ position:relative; padding-left:40px; }
@media (min-width:900px){
  .tl__item{ padding-left:0; display:grid; grid-template-columns:120px 1fr; align-items:start; gap:clamp(28px,3vw,48px); }
}

.tl__node{
  position:absolute; left:0; top:7px;
  width:16px; height:16px; border-radius:50%;
  background:var(--dark-deep);
  border:2px solid var(--rule-dark);
  transition:border-color .45s var(--e), box-shadow .45s var(--e), background .45s var(--e);
}
@media (min-width:900px){ .tl__node{ left:113px; } }
.tl__item.is-on .tl__node{
  border-color:var(--gold);
  background:var(--gold);
  box-shadow:0 0 0 5px rgba(201,169,97,.16);
}

.tl__when{
  margin:0 0 var(--space-3);
  font-family:var(--font-ui);
  font-variant-caps:normal;
  font-feature-settings:normal;
  letter-spacing:.1em; font-size:1.06rem; line-height:1.2;
  color:var(--on-dark-mute);
  transition:color .45s var(--e);
}
@media (min-width:900px){ .tl__when{ text-align:right; padding-right:var(--space-6); margin:0; } }
.tl__item.is-on .tl__when{ color:var(--gold-lit); }

.tl__card{
  display:grid; gap:var(--space-4);
  padding:var(--space-4);
  border:1px solid var(--rule-dark);
  border-radius:8px;
  background:rgba(255,255,255,.022);
  opacity:.55;
  transform:translateY(10px);
  transition:opacity .6s var(--e), transform .6s var(--e),
             border-color .45s var(--e), background .45s var(--e);
}
@media (min-width:620px){ .tl__card{ grid-template-columns:190px 1fr; align-items:center; } }
.tl__item.is-on .tl__card{ opacity:1; transform:none; }
.tl__item:hover .tl__card,
.tl__item:focus-within .tl__card{
  border-color:rgba(201,169,97,.34);
  background:rgba(201,169,97,.05);
}

/* The archival slot. Swap the <span> for an <img> and it needs no other
   change — the frame already holds a 4:3 box and crops with object-fit. */
.tl__shot{
  margin:0; aspect-ratio:4/3; overflow:hidden; border-radius:5px;
  display:grid; place-items:center;
  background:
    repeating-linear-gradient(135deg, transparent 0 7px, rgba(250,249,243,.045) 7px 14px),
    var(--dark-ink);
  border:1px solid var(--rule-dark);
}
.tl__shot img{ width:100%; height:100%; object-fit:cover; display:block; }
.tl__shot span{
  font-family:var(--font-ui);
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.11em; font-size:.8rem; line-height:1.6; text-align:center;
  color:var(--on-dark-mute); padding:var(--space-3);
}
.tl__text h3{ color:#fff; margin:0 0 var(--space-2); }
.tl__text .copy{ color:var(--on-dark-soft); margin:0; }

/* A milestone with no archival frame owed to it is text alone, and sits
   tighter than the founding years that carry one. */
.tl__card--text{ padding-block:var(--space-3) var(--space-4); }
@media (min-width:620px){ .tl__card--text{ grid-template-columns:1fr; } }

/* The eras: a label on the spine, not a milestone. It keeps the long run
   from 1979 to now readable as three chapters rather than one list. */
.tl__era{ position:relative; padding-left:40px; margin-top:var(--space-4); }
.tl__era:first-child{ margin-top:0; }
.tl__era .sc{ font-size:.98rem; letter-spacing:.12em; }
.tl__era::before{
  content:""; position:absolute; left:3px; top:50%;
  width:10px; height:10px; transform:translateY(-50%) rotate(45deg);
  border:1px solid var(--gold-lit); background:var(--dark-deep);
}
@media (min-width:900px){
  .tl__era{ padding-left:calc(120px + clamp(28px,3vw,48px)); }
  .tl__era::before{ left:116px; }
}

/* Nothing moves, and nothing waits to be activated. */
@media (prefers-reduced-motion:reduce){
  .tl__card{ opacity:1; transform:none; transition:none; }
  .tl__node, .tl__when{ transition:none; }
}
/* Same, when the script never runs at all. */
.tl.is-static .tl__card{ opacity:1; transform:none; }
.tl.is-static .tl__node{ border-color:var(--gold); background:var(--gold); }
.tl.is-static .tl__when{ color:var(--gold-lit); }

/* ============================================================
   School History — the closing panel
   ============================================================ */
.more{ background:var(--dark-ink); }
.more__inner{ max-width:720px; }
.more__badge{
  display:inline-flex; align-items:center; gap:10px;
  margin:0 0 var(--space-5); padding:8px 16px 8px 13px;
  border:1px solid rgba(201,169,97,.38); border-radius:99px;
  background:rgba(201,169,97,.09); color:var(--gold-lit);
  font-family:var(--font-ui);
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.06em; font-size:.94rem; line-height:1;
}
.more__dot{ width:8px; height:8px; border-radius:50%; background:var(--gold); flex:none;
  animation:ucpulse 2.4s ease-in-out infinite; }
@media (prefers-reduced-motion:reduce){ .more__dot{ animation:none; } }
.more__head{ color:#fff; font-size:clamp(1.9rem,4vw,3rem); line-height:1.12; margin:0 0 var(--space-4); }
.more__head em{ color:var(--gold-lit); }
.more .lead{ color:var(--on-dark-soft); margin:0 0 var(--space-4); }
.more__ph{
  color:var(--on-dark-mute); font-size:.95rem; margin:0;
  border-left:2px solid var(--rule-dark); padding-left:var(--space-4);
}
.more__cta{ margin:clamp(26px,3.4vw,40px) 0 0; color:var(--on-dark-soft); font-size:.98rem; }
.more__cta a{ color:var(--gold-lit); text-decoration:underline; text-underline-offset:3px; }
.more__cta a:hover{ color:#fff; }

/* ============================================================
   Crossroads — the magazine archive
   ------------------------------------------------------------
   This page is the one place on the site that is allowed to
   behave like a publication rather than a school page: an
   oversized masthead, a statement set at billboard scale, and a
   wall of covers. It still sets in the site's own faces, on the
   site's own spacing steps and in the site's own charcoal and
   gold — the editorial confidence is in the scale and the
   asymmetry, not in a second brand.
   ============================================================ */

/* --- Masthead ------------------------------------------------ */
.crhero{
  position:relative; overflow:hidden;
  background:var(--dark-ink);
  display:flex; align-items:flex-end;
  min-height:100svh; min-height:100vh;
  padding-top:clamp(120px,16vh,190px);
}

/* The covers themselves are the banner. Five columns drift past at
   walking pace, neighbours in opposite directions, and they turn
   round when the reader scrolls the other way — the archive moving
   under its own masthead rather than a photograph of a magazine.
   assets/js/cirs.js drives the transform; the keyframe below is what
   runs before it does, and without it. */
.crwall{
  position:absolute; inset:0; z-index:0; pointer-events:none;
  display:flex; gap:clamp(8px,1vw,18px);
  padding:0 clamp(8px,1vw,18px);
}
.crwall__col{ flex:1 1 0; overflow:hidden; }
.crwall__run{
  display:block;
  /* Promoted to its own layer: transformed every frame, and without
     this the repaint reads as jitter on the headline beside it. */
  will-change:transform; backface-visibility:hidden;
  animation:crwall-drift 56s linear infinite;
}
.crwall__run[data-dir="-1"]{ animation-direction:reverse; }
/* Two copies of the run stacked, so one copy's worth of travel lands
   exactly where it started and the loop has no seam to hide. */
@keyframes crwall-drift{
  from{ transform:translate3d(0,0,0); }
  to{ transform:translate3d(0,-50%,0); }
}
.crwall__cell{
  display:block; width:100%; height:auto;
  margin-bottom:clamp(8px,1vw,18px);
}
/* Every other column starts part of a cover out of step, or the five
   read as one grid sliding rather than five columns drifting. */
.crwall__col:nth-child(2) .crwall__run{ transform:translate3d(0,-18%,0); animation-delay:-9s; }
.crwall__col:nth-child(3) .crwall__run{ transform:translate3d(0,-34%,0); animation-delay:-21s; }
.crwall__col:nth-child(4) .crwall__run{ transform:translate3d(0,-11%,0); animation-delay:-34s; }
.crwall__col:nth-child(5) .crwall__run{ transform:translate3d(0,-27%,0); animation-delay:-44s; }
/* Below this the columns are too narrow for a cover to be a cover. */
@media (max-width:719px){ .crwall__col:nth-child(n+4){ display:none; } }
@media (prefers-reduced-motion:reduce){ .crwall__run{ animation:none; } }

/* Charcoal over the whole wall, deepest where the words are. The covers
   are 29 different colour schemes at once, so this has to carry the
   headline over any of them, not over an average of them — the
   readings are in tools/check-contrast.py, sampled across the drift. */
.crhero__scrim{
  position:absolute; inset:0; z-index:1; pointer-events:none;
  background:
    linear-gradient(to top,
      rgba(17,17,15,.97) 0%, rgba(17,17,15,.95) 26%,
      rgba(17,17,15,.88) 46%, rgba(24,24,21,.74) 72%,
      rgba(24,24,21,.80) 100%),
    linear-gradient(to right,
      rgba(31,31,27,.62) 0%, rgba(31,31,27,.30) 58%, rgba(91,42,114,.34) 100%);
}
.crhero__inner{ position:relative; z-index:2; padding-bottom:clamp(44px,6vh,84px); }
.crhero .marker{ margin-bottom:var(--space-4); }
.crhero .sc{ color:var(--gold-lit); font-size:.92rem; }
.crhero .marker::after{ background:rgba(255,255,255,.26); max-width:150px; }

.crhero__word{
  font-family:var(--font-display);
  /* The one element on the site set at true billboard scale. */
  font-size:clamp(3.1rem,13.4vw,11rem);
  line-height:.86; letter-spacing:-.035em;
  color:#fff; margin:0;
  text-transform:none;
}
.crhero__lead{
  margin-top:clamp(18px,2.6vh,32px);
  font-family:var(--font-editorial); font-style:italic;
  font-size:clamp(1.16rem,2.1vw,1.7rem); line-height:1.3;
  color:var(--gold-lit); max-width:24ch;
}
.crhero__note{
  margin-top:var(--space-4); max-width:58ch;
  color:rgba(255,255,255,.80); font-size:var(--fs-sm); line-height:1.6;
}

.crmeter{
  /* Block-level, or the scroll cue below rides up onto the same line. */
  display:flex; width:fit-content; align-items:center; gap:var(--space-4);
  margin-top:clamp(26px,3.4vh,44px);
  padding-top:var(--space-5); border-top:1px solid rgba(255,255,255,.22);
}
.crmeter__n{
  font-family:var(--font-display); font-size:clamp(2.6rem,5vw,4.2rem); line-height:.85;
  color:var(--gold); font-variant-numeric:lining-nums;
}
.crmeter__t{
  font-family:var(--font-ui);
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.06em; font-size:.96rem; line-height:1.45;
  color:rgba(255,255,255,.76);
}
.crhero__scroll{
  display:inline-flex; align-items:center; gap:var(--space-3);
  margin-top:clamp(22px,3vh,38px);
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal;
  font-size:.92rem; letter-spacing:.06em; color:rgba(255,255,255,.7);
}
.crhero__scroll svg{ animation:hero-bob 1.8s ease-in-out infinite; }
@media (prefers-reduced-motion:reduce){ .crhero__scroll svg{ animation:none; } }

/* --- The statement ------------------------------------------ */
.crstate{
  background:var(--paper); color:var(--ink);
  padding-block:clamp(72px,13vw,190px);
}
.crstate__line{
  font-family:var(--font-display);
  font-size:clamp(2.5rem,10vw,8rem); line-height:.93; letter-spacing:-.035em;
  color:var(--dark); margin:0;
}
.crstate__line em{ font-style:italic; color:var(--label); }
.crstate__line--b{ text-align:right; color:var(--ink); }

/* --- What it is --------------------------------------------- */
.crabout{ display:grid; gap:clamp(36px,5vw,72px); align-items:start; }
@media (min-width:940px){ .crabout{ grid-template-columns:1.15fr .85fr; } }
.crquote{
  margin:0; padding:clamp(26px,3.4vw,44px);
  background:var(--dark-deep); color:#fff;
  border-left:3px solid var(--gold);
}
.crquote blockquote{ margin:0; }
.crquote .pull{ color:#fff; }
.crquote .pull em{ color:var(--gold-lit); }
.crquote__by{
  margin-top:var(--space-5);
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal;
  letter-spacing:.06em; font-size:.98rem; color:var(--gold-lit);
}

/* --- The wall ----------------------------------------------- */
.crgrid{
  display:grid; gap:clamp(28px,3.6vw,56px) clamp(20px,2.6vw,40px);
  grid-template-columns:1fr;
  margin-top:clamp(40px,5vw,68px);
}
@media (min-width:620px){ .crgrid{ grid-template-columns:repeat(2,1fr); } }
@media (min-width:1024px){
  .crgrid{ grid-template-columns:repeat(3,1fr); }
  /* The middle column rides low, so the wall reads as a spread
     rather than a spreadsheet. */
  .crgrid > :nth-child(3n+2){ transform:translateY(clamp(20px,3vw,52px)); }
}

.crcard{ position:relative; display:flex; flex-direction:column; }
.crcard__link{
  display:flex; flex-direction:column; text-decoration:none; color:inherit;
}
.crcover{
  position:relative; display:flex; flex-direction:column;
  aspect-ratio:5/7; overflow:hidden;
  padding:clamp(16px,1.8vw,26px);
  background:var(--dark-deep);
  box-shadow:0 18px 40px rgba(17,17,15,.16);
  transition:transform .5s var(--e), box-shadow .5s var(--e);
}
.crcover__img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.crcover__mast{
  position:relative; z-index:1;
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal;
  letter-spacing:.06em; font-size:.8rem; color:var(--gold-lit);
}
.crcover__num{
  position:relative; z-index:1; flex:1;
  display:flex; align-items:center; justify-content:center;
  font-family:var(--font-display); font-size:clamp(3.6rem,9vw,6.4rem); line-height:.8;
  color:#fff; letter-spacing:-.04em; font-variant-numeric:lining-nums;
}
.crcover__sub{
  position:relative; z-index:1;
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal;
  letter-spacing:.06em; font-size:.76rem; color:rgba(255,255,255,.62);
}

/* Four compositions on a cycle: where the number sits and what it
   hangs from. Same system, different page — which is what a run of
   a magazine actually looks like on a shelf. */
.crcard--v1 .crcover{ background:linear-gradient(165deg, #1F1F1B 0%, var(--dark-ink) 100%); }
.crcard--v2 .crcover{ background:linear-gradient(200deg, var(--dark) 0%, var(--dark-ink) 86%); }
.crcard--v2 .crcover__num{ align-items:flex-end; justify-content:flex-start; font-size:clamp(4.4rem,11vw,8rem); color:var(--gold); }
.crcard--v3 .crcover{
  background:var(--dark-ink);
  background-image:repeating-linear-gradient(to bottom, rgba(255,255,255,.08) 0 1px, transparent 1px 34px);
}
.crcard--v3 .crcover__num{ align-items:flex-start; justify-content:flex-end; }
.crcard--v4 .crcover{ background:linear-gradient(145deg, #1F1F1B 0%, var(--dark-ink) 78%); }
.crcard--v4 .crcover__num{ color:transparent; -webkit-text-stroke:1.5px var(--gold); }

.crcard--latest .crcover::after{
  content:"Latest"; position:absolute; z-index:2; top:0; right:0;
  padding:7px 14px; background:var(--gold); color:var(--dark);
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal; letter-spacing:.06em; font-size:.86rem;
}

.crcard__foot{
  display:flex; align-items:baseline; flex-wrap:wrap;
  gap:6px var(--space-3); padding-top:var(--space-4);
  border-top:1px solid var(--rule);
  margin-top:var(--space-4);
}
.crcard__label{ margin-right:auto; }
.crcard__label{
  font-family:var(--font-body); font-variant-caps:normal;
  font-feature-settings:normal;
  letter-spacing:.12em; font-size:1.04rem; color:var(--dark);
}
.crcard__state{
  font-size:var(--fs-xs); color:var(--ink-mute); text-align:right;
  transition:color .3s var(--e);
}
.crcard.is-pending .crcard__state{ font-style:italic; }

/* Hover belongs to the cover, not to a scale on the whole card:
   the sheet lifts off the shelf and the line under it wakes up. */
.crcard__link:hover .crcover,
.crcard__link:focus-visible .crcover{
  transform:translateY(-8px);
  box-shadow:0 30px 60px rgba(17,17,15,.26);
}
.crcard__state{ text-decoration:none; }
.crcard:hover .crcard__state,
.crcard__state:focus-visible{ color:var(--label); }
.crcard:hover .crcard__label{ color:var(--label); }
.crcard__state:focus-visible,
.crcard__dl:focus-visible{ outline:2px solid var(--gold); outline-offset:3px; }
.crcard__link:focus-visible{ outline:2px solid var(--gold); outline-offset:6px; }

/* --- Where you are in the run -------------------------------- */
.crprog{
  position:sticky; top:96px; z-index:4;
  float:right; margin:0 0 var(--space-4) var(--space-4);
  display:none; align-items:baseline; gap:8px;
  padding:9px 16px; border:1px solid var(--rule);
  background:rgba(255,255,255,.86); backdrop-filter:blur(8px);
  font-family:var(--font-ui); font-variant-numeric:lining-nums;
}
@media (min-width:1024px){ .crprog{ display:inline-flex; } }
.crprog__n{ font-size:1.5rem; line-height:1; color:var(--dark); }
.crprog__d{
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.06em; font-size:.86rem; color:var(--ink-mute);
}

/* --- Closing -------------------------------------------------- */
.crend{
  background:var(--dark-deep); color:var(--on-dark);
  padding-block:clamp(72px,11vw,150px);
}
.crend .sc{ color:var(--gold-lit); }
.crend .marker::after{ background:var(--rule-dark); max-width:150px; }
.crend__head{
  font-family:var(--font-display);
  font-size:clamp(2.4rem,7.6vw,6rem); line-height:.94; letter-spacing:-.03em;
  color:#fff; margin:var(--space-4) 0 0;
}
.crend__head em{ color:var(--gold-lit); }
.crend__note{
  margin-top:var(--space-5); max-width:52ch;
  color:var(--on-dark-soft); font-size:var(--fs-sm); line-height:1.65;
}
.crend__cta{ display:flex; flex-wrap:wrap; gap:var(--space-3); margin-top:var(--space-6); }

/* ============================================================
   Download controls
   ------------------------------------------------------------
   A PDF link opens a browser tab; it does not save the file, and
   right-clicking is not an interface. Every document on the site
   therefore carries an explicit download beside whatever opens it.
   ============================================================ */
.crcard{ position:relative; }
.crcard__dl{
  display:inline-flex; align-items:center; gap:6px;
  padding:5px 11px 6px; border-radius:99px;
  border:1px solid var(--rule);
  color:var(--dark); text-decoration:none;
  font-size:.74rem; letter-spacing:.04em; line-height:1;
  transition:background .25s var(--e), border-color .25s var(--e),
             color .25s var(--e);
}
.crcard__dl:hover,
.crcard__dl:focus-visible{
  background:var(--dark); border-color:var(--dark); color:var(--on-dark);
}
@media (prefers-reduced-motion:reduce){ .crcard__dl{ transition:none; } }

.doclist__dl{
  margin-left:8px; font-size:.76rem; letter-spacing:.03em;
  color:var(--dark); text-decoration:underline; text-underline-offset:3px;
  white-space:nowrap;
}
.doclist__dl:hover{ color:var(--label); }
.doclist__await{
  margin-left:8px; font-size:.74rem; letter-spacing:.04em; color:var(--ink-mute);
  white-space:nowrap;
}
.step__aside .btn + .btn{ margin-left:6px; }

/* When a document is from, or until when it holds — both document pages.
   An expired certificate, or an edition the school has not replaced, is
   set in the label colour so it cannot be read as current at a glance. */
.docmeta{
  display:block; margin-top:4px;
  font-size:.8rem; letter-spacing:.01em; line-height:1.45; color:var(--ink-soft);
}
.docmeta--expired, .docmeta--stale{ color:var(--label); }
.doclist__actions{ display:inline-flex; flex:none; align-items:baseline; gap:6px; }

/* ============================================================
   Alumni voices — what alumni say about the school, in their
   own words. Three short quotations, so they sit side by side
   rather than stacking into a column of pull-quotes.
   ============================================================ */
.voices{
  display:grid; gap:clamp(20px,2.6vw,32px);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr));
  margin-top:clamp(30px,3.4vw,52px);
}
.voice{
  margin:0; padding:clamp(24px,2.8vw,36px);
  background:var(--dark-deep); color:#fff;
  border-left:3px solid var(--gold);
  display:flex; flex-direction:column; justify-content:space-between;
  gap:var(--space-5);
}
.voice .pull{ color:#fff; margin:0; }
.voice .pull em{ color:var(--gold-lit); font-style:italic; }
.voice__by{
  font-family:var(--font-ui); font-variant-caps:normal;
  font-feature-settings:normal;
  letter-spacing:.06em; font-size:.95rem; color:var(--gold);
}

/* Notable alumni biographies need more room than the short facts elsewhere. */
#notable .factrail > div{
  display:grid;
  grid-template-columns:minmax(160px, 25%) minmax(0, 1fr);
  align-items:start;
  gap:clamp(16px, 3vw, 48px);
  padding:clamp(22px, 2.5vw, 36px) 0;
}
#notable .factrail dd{
  max-width:75ch;
  text-align:left;
  line-height:1.6;
  font-weight:400;
}
#notable .factrail dd a{
  color:inherit;
  text-decoration:underline;
  text-underline-offset:.2em;
}
@media (max-width:700px){
  #notable .factrail > div{ grid-template-columns:1fr; gap:10px; }
}

/* ============================================================
   About CIRS — the editorial scroll
   ------------------------------------------------------------
   The page used to be three walls of prose. It is now a run of
   photographs, each carrying one line and one way in: "Know
   more" opens a translucent panel with the detail that used to
   sit on the page. The photograph and the line are the page;
   everything else is a click away.
   ============================================================ */
.saga{
  position:relative; isolation:isolate;
  min-height:min(88vh,760px);
  display:grid; align-items:end;
  overflow:hidden;
}
/* The opening frame is the page's hero now that the dark plate above it
   is gone, so it takes the whole window rather than most of it, and the
   photograph runs under the transparent header to the very top. Its scrim
   already lifts to .48 at the top of the frame, which is what keeps the
   header's white lettering legible over a bright corridor. */
.saga--open{ min-height:100svh; min-height:100vh; align-items:center; }
.saga__media{ position:absolute; inset:0; z-index:0; }
.saga__media img{ width:100%; height:100%; object-fit:cover; display:block; }
/* The opening frame is a full window now, so on anything taller than the
   photograph is wide, cover has to take something. Anchored high, what it
   takes is the empty ground at the foot rather than the tops of the heads. */
.saga--open .saga__media img{ object-position:center 32%; }
/* A 1.6 photograph in a phone's 0.46 window is filled on its height, and
   everything cover then takes comes off the sides — at a full 100svh only
   the middle 29% of the frame survives, which is two students and none of
   the lesson. A shorter opening frame scales the photograph down, so less
   of its width has to go: at 82svh it keeps 38%. The frame still starts at
   the very top of the page; it just ends sooner. */
@media (max-width:760px){
  .saga--open{ min-height:82svh; min-height:82vh; }
}
/* Dark at the foot where the words sit, clearing towards the top so the
   photograph is still a photograph. */
.saga__media::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(to top,
    rgba(17,17,15,.92) 0%, rgba(17,17,15,.78) 26%,
    rgba(17,17,15,.42) 58%, rgba(17,17,15,.18) 100%);
}
.saga--open .saga__media::after{
  background:linear-gradient(to top,
    rgba(17,17,15,.88) 0%, rgba(17,17,15,.72) 34%,
    rgba(17,17,15,.58) 70%, rgba(17,17,15,.48) 100%);
}
.saga__inner{
  position:relative; z-index:1;
  padding-block:clamp(48px,7vw,104px);
  max-width:1040px;
}
.saga__eyebrow{
  font-family:var(--font-ui);
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.06em; font-size:1rem; color:var(--gold);
  margin:0 0 var(--space-4);
}
.saga__line{
  margin:0; color:#fff;
  font-family:var(--font-display); font-weight:500;
  font-size:clamp(2rem,5.2vw,4.1rem); line-height:1.06;
  letter-spacing:-.015em; text-wrap:balance;
  max-width:19ch;
}
.saga__line em{ font-style:italic; color:var(--gold-lit); }
.saga--open .saga__line{ font-size:clamp(2.2rem,6vw,4.9rem); max-width:22ch; }
.saga__by{
  margin:var(--space-5) 0 0; color:rgba(255,255,255,.82);
  font-family:var(--font-ui); font-style:italic; font-size:var(--fs-lead);
}
.saga__more{
  display:inline-flex; align-items:center; gap:10px;
  margin-top:clamp(24px,3vw,38px);
  font-family:var(--font-ui); font-size:var(--fs-sm); font-weight:600;
  letter-spacing:.06em; color:#fff;
  padding:12px 22px; border-radius:999px;
  border:1px solid rgba(255,255,255,.42);
  background:rgba(255,255,255,.08);
  -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px);
  cursor:pointer; transition:background .28s var(--e), border-color .28s var(--e);
}
.saga__more::after{ content:"\2192"; transition:transform .28s var(--e); }
.saga__more:hover{ background:rgba(255,255,255,.18); border-color:#fff; }
.saga__more:hover::after{ transform:translateX(4px); }
.saga__more:focus-visible{ outline:2px solid var(--gold); outline-offset:3px; }

/* ---- the translucent detail panel ---------------------------------- */
.panel{
  position:fixed; inset:0; z-index:320;
  display:grid; place-items:center;
  padding:clamp(16px,3vw,40px);
  background:rgba(17,17,15,.58);
  -webkit-backdrop-filter:blur(14px); backdrop-filter:blur(14px);
  opacity:0;
  transition:opacity .34s var(--e);
}
/* The closed state is the hidden attribute, not visibility. Transitioning
   visibility means the panel is not focusable at the instant it opens, and
   the close button silently refuses focus — which leaves a keyboard reader
   on the button outside, tabbing through the page behind the panel. */
.panel[hidden]{ display:none; }
.panel.is-open{ opacity:1; }
.panel__card{
  position:relative; width:min(100%,660px);
  max-height:min(86vh,760px); overflow:auto; overscroll-behavior:contain;
  border-radius:22px;
  /* Translucent, but far enough towards paper that the text on it stays
     black on near-white however busy the photograph behind it is. */
  background:rgba(250,249,243,.93);
  -webkit-backdrop-filter:blur(30px) saturate(1.4);
  backdrop-filter:blur(30px) saturate(1.4);
  border:1px solid rgba(255,255,255,.55);
  box-shadow:0 40px 90px rgba(17,17,15,.55);
  padding:clamp(30px,4vw,52px);
  transform:translateY(16px) scale(.985);
  transition:transform .38s var(--e2);
}
.panel.is-open .panel__card{ transform:none; }
.panel__label{
  font-family:var(--font-body);
  font-variant-caps:normal; font-feature-settings:normal;
  letter-spacing:.06em; font-size:1rem; color:var(--label);
  margin:0 0 var(--space-3);
}
.panel__card h2{
  font-family:var(--font-display); font-weight:500; color:var(--dark);
  font-size:clamp(1.5rem,2.8vw,2.2rem); line-height:1.12;
  margin:0 0 var(--space-4);
}
.panel__card h2 em{ font-style:italic; }
.panel__card .copy{ color:var(--ink-soft); }
.panel__card .copy + .copy{ margin-top:var(--space-4); }
.panel__card .pull{ color:var(--dark); margin:0 0 var(--space-4); }
.panel__close{
  position:absolute; top:12px; right:12px;
  width:40px; height:40px; display:grid; place-items:center;
  color:var(--ink-mute); border-radius:50%; border:0; cursor:pointer;
  background:rgba(255,255,255,.6);
  transition:background .2s var(--e), color .2s var(--e);
}
.panel__close:hover{ background:#fff; color:var(--dark); }
.panel__close:focus-visible{ outline:2px solid var(--gold); outline-offset:2px; }

@media (prefers-reduced-motion: reduce){
  .panel, .panel__card, .saga__more, .saga__more::after{ transition:none; }
}

/* A page in preparation ends with the way onward — the finished pages nearest
   to it — so the new menu structure can be carried before every page under it
   is written, without any of it dead-ending. */
.soon__onward{
  display:flex; flex-wrap:wrap; gap:12px;
  margin-top:clamp(22px,3vw,32px);
  padding-top:clamp(20px,2.6vw,28px);
  border-top:1px solid var(--rule);
}

/* ============================================================
   Student Life — the hero
   ------------------------------------------------------------
   A line of oversized lettering running across the screen, and a
   deck of photographs shuffling up through it. Each card rises
   from below at a tilt and lands square on top of the one before,
   so scrolling deals the school's day out a card at a time.

   The division of labour is the Crossroads wall's: the drift is a
   CSS keyframe so the lettering moves before GSAP arrives and
   without it, and cirs.js takes over the deal and the scrub once
   it is there. Below 700px there is no pin at all — the deck is a
   swipe track, which is what a deck wants to be on a phone.
   ============================================================ */
.slhero{
  position:relative;
  /* Off-white, not the site's charcoal. The lettering is the subject here and
     it wants a page to sit on, not a night sky; and the photographs carry
     all the colour the screen needs. The header cannot float over this in
     white, so the page sets body.litehead — see build-site.py. */
  background:#FAF9F3;
  color:var(--ink);
}
.slhero__pin{
  position:relative;
  min-height:100svh; min-height:100vh;
  overflow:hidden;
  display:flex; flex-direction:column; justify-content:flex-end;
}

/* ---------------------------------------------------- the lettering */
.slhero__type{
  position:absolute; left:0; right:0; top:44%;
  transform:translateY(-50%);
  z-index:1;
  overflow:hidden;
  pointer-events:none;
  -webkit-mask-image:linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
          mask-image:linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}
.slhero__push{ will-change:transform; }
.slhero__run{
  display:flex; align-items:center; gap:clamp(20px,3vw,54px);
  width:max-content;
  will-change:transform; backface-visibility:hidden;
  animation:slhero-drift 44s linear infinite;
}
/* The run is printed twice, so one copy's travel lands exactly where it
   started and the loop has no seam to hide. */
@keyframes slhero-drift{
  from{ transform:translate3d(0,0,0); }
  to{ transform:translate3d(-50%,0,0); }
}
.slhero__run span{
  font-family:var(--font-display);
  font-size:clamp(4rem,13vw,12rem);
  line-height:.86;
  letter-spacing:-.035em;
  white-space:nowrap;
  /* Dark enough to be the thing you notice, pale enough that a photograph
     landing on it always wins. */
  color:rgba(42,41,37,.17);
}
.slhero__run i{
  font-style:normal;
  font-size:clamp(2rem,5vw,4rem);
  color:var(--label);
  opacity:.34;
}

/* --------------------------------------------------------- the deck */
.slhero__deck{
  /* Lifted off the floor of the section, and pushed off the left column, so
     a photograph rising into place does not climb through the headline. The
     pile centres at about three fifths across; the words have the rest. */
  position:absolute; inset:0 0 17% 20%; z-index:2;
  display:grid; place-items:center;
  pointer-events:none;
}
/* Ten different shapes, not ten cards. A deck of identical rectangles reads
   as a slideshow in a frame; a tall one, then a wide one, then a square one
   reads as photographs. Each frame carries its own width, its own shape and
   a small offset from centre, set on the element in the page — so the pile
   is data rather than ten more rules here. */
.slcard{
  grid-area:1 / 1;
  margin:0;
  width:var(--w, 26vw);
  max-width:min(88vw, 620px);
  aspect-ratio:var(--ar, 3 / 4);
  translate:var(--dx, 0) var(--dy, 0);
  overflow:hidden;
  border-radius:2px;
  background:var(--paper-3);
  /* The frames land on nearly the same spot, so stacked shadows would
     compound into a smudge. cirs.js draws only the top two. */
  box-shadow:0 22px 54px rgba(31,31,27,.28), 0 2px 8px rgba(31,31,27,.14);
  will-change:transform;
  transform:translateY(0);
}
.slcard img{ width:100%; height:100%; object-fit:cover; display:block; }

/* ------------------------------------------------------- the words */
.slhero__say{
  position:relative; z-index:3;
  width:100%;
  padding-bottom:clamp(40px,7vh,86px);
  padding-top:clamp(200px,42vh,420px);
}
.slhero__say h1{
  font-size:clamp(2.3rem,5vw,4.2rem);
  line-height:1.02;
  letter-spacing:-.018em;
  color:var(--dark);
  margin-top:var(--space-3);
}
.slhero__say h1 em{ color:var(--label); font-style:italic; }
.slhero__say .marker::after{ background:var(--rule); }
.slhero__say .lead{ margin-top:var(--space-4); max-width:34ch; }

/* ------------------------------- no pin: a deck you swipe instead */
.slhero.is-static .slhero__pin{ min-height:0; padding-top:clamp(96px,14vh,150px); }
.slhero.is-static .slhero__type{ position:relative; top:auto; transform:none; }
.slhero.is-static .slhero__deck{
  position:relative; inset:auto;
  display:flex; gap:clamp(10px,2vw,20px);
  overflow-x:auto;
  scroll-snap-type:x proximity;
  scroll-padding-inline-start:var(--gut);
  padding:clamp(22px,4vh,40px) var(--gut);
  pointer-events:auto;
}
.slhero.is-static .slcard{
  grid-area:auto;
  flex:none;
  scroll-snap-align:start;
  transform:none !important;
  opacity:1 !important;
}
.slhero.is-static .slhero__say{ padding-top:0; }

@media (prefers-reduced-motion:reduce){
  .slhero__run{ animation:none; }
}

/* ============================================================
   Student Life — the campus band
   ------------------------------------------------------------
   Where the hero lets go. The deck finishes, the pin releases,
   and the next thing on the screen is one photograph at full
   height with the headline lying along the bottom of it.

   The gradient is a layer of the section rather than something
   baked into the picture, so the photograph can be swapped for
   another without re-grading anything — and so the darkness sits
   exactly where the words are and nowhere else.
   ============================================================ */
.lifeband{
  position:relative;
  min-height:100svh; min-height:100vh;
  display:flex; align-items:flex-end;
  overflow:hidden;
  background:var(--dark-ink);
  isolation:isolate;
}
.lifeband__img{
  position:absolute; inset:0; z-index:0;
  width:100%; height:100%; object-fit:cover;
  /* Pulled towards the palette the way every photograph here is, and held
     a little back so the type has somewhere to land. */
  filter:saturate(.92) brightness(.96);
}
.lifeband__veil{
  position:absolute; inset:0; z-index:1; pointer-events:none;
  background:
    linear-gradient(to top,
      rgba(6,6,5,.96) 0%,
      rgba(6,6,5,.90) 18%,
      rgba(9,9,7,.72) 36%,
      rgba(17,17,15,.34) 58%,
      rgba(17,17,15,.10) 78%,
      rgba(17,17,15,.16) 100%);
}
.lifeband__say{
  position:relative; z-index:2;
  width:100%;
  padding-block:clamp(48px,9vh,110px);
  color:var(--on-dark);
}
.lifeband__say .sc{ color:var(--gold-lit); }
.lifeband__say .marker::after{ background:rgba(255,255,255,.26); max-width:190px; }
.lifeband__say h2{
  font-size:clamp(2.2rem,5.4vw,4.6rem);
  line-height:1.02;
  letter-spacing:-.02em;
  color:#fff;
  margin-top:var(--space-3);
  max-width:19ch;
}
.lifeband__say h2 em{ color:var(--gold-lit); font-style:italic; }
.lifeband__say .copy{
  margin-top:var(--space-4);
  max-width:56ch;
  color:var(--on-dark-soft);
}
.lifeband__cta{ margin-top:var(--space-5); }

@media (max-width:700px){
  .lifeband{ min-height:86svh; }
  .lifeband__say h2{ max-width:none; }
}


/* Touch: "Read issue" on a Crossroads card is small type at the card's
   foot. It takes a 44px hit box without moving anything. */
@media (pointer:coarse){
  .crcard__state{ position:relative; }
  .crcard__state::after{ content:""; position:absolute; inset:-11px -6px; }
}

/* ---- assets/css/home.css ---- */
/* Homepage colour direction
   The home page wears the Founder page's scheme rather than the site's
   deep purple: parchment grounds, warm charcoal for the photographic dark
   scenes, and the bright school gold. The purple roles are re-pointed here,
   on body.home only, so every shared component on the page (the ticker,
   the footer, the closing scene, the buttons) follows without being
   restyled one by one. Lettering keeps the ratios measured in cirs.css:
   --ink 15.68:1 and --ink-soft 7.32:1 on ivory; white on the charcoal
   is 16.5:1 or better. The local names below are aliases of those roles. */

body.home{
  /* The Founder page's charcoal (founder-journey.css), in place of purple. */
  --dark:       #2A2925;
  --dark-mid:   #1F1F1B;
  --dark-deep:  #1F1F1B;
  --dark-ink:   #11110F;
  --brand:      #2A2925;
  --brand-mid:  #1F1F1B;
  --brand-deep: #1F1F1B;
  --on-gold:    var(--ink);        /* 10.28:1 on --gold */
  --label:      var(--ink-soft);   /* the Founder page's meta lettering */

  --home-gold:var(--gold-lit);
  --home-gold-lit:var(--gold-pale);
  --home-gold-deep:var(--gold);
  --home-ivory:var(--paper);
  --home-parchment:var(--paper-2);
  --home-ink:var(--dark-deep);
  --home-night:var(--brand-deep);
  /* The Founder page's dark scene: charcoal lit warm from above. */
  --home-night-glow:radial-gradient(circle at 72% 22%, #2A2925, #1F1F1B 52%, #11110F 100%);
}

/* The opening's stage, behind the inset plate. The headline is white over it. */
body.home .hseq{ background:var(--home-night-glow); }

/* The lower hero wash remains dark enough for the white headline. Gold is a
   low-opacity light within the wash, not an opaque colour sheet over campus. */
body.home .hero{ background:var(--home-night); }
body.home .hero__scrim{
  background:
    linear-gradient(to top,
      rgba(17,17,15,.94) 0%, rgba(17,17,15,.84) 18%,
      rgba(17,17,15,.58) 38%, rgba(17,17,15,.15) 70%,
      rgba(17,17,15,.25) 100%),
    radial-gradient(95% 54% at 48% 100%,
      rgba(var(--gold-rgb),.17) 0%, rgba(var(--gold-rgb),.07) 42%,
      rgba(var(--gold-rgb),0) 76%);
}

/* Horizontal passage: gold ground with dark text at the opening. At the
   midpoint, JS brings in the ivory plate and moves every text role to a
   contrast-safe gold stop. Images and their depth transforms are unchanged. */
body.home .hrun{
  background:var(--home-gold-deep);
  color:var(--run-ink, var(--home-ink));
}
body.home .hrun__pin{
  position:relative;
  isolation:isolate;
  --run-ivory:0;
  --run-ink:var(--dark-deep);
  --run-soft:#3A3934;
  --run-accent:#3A3934;
  --run-ghost:var(--dark-deep);
  background:
    radial-gradient(105% 82% at 10% 0%, rgba(244,240,230,.34), transparent 58%),
    radial-gradient(82% 76% at 92% 100%, rgba(232,217,181,.20), transparent 64%),
    var(--home-gold-deep);
}
body.home .hrun__pin::before{
  content:"";
  position:absolute;
  inset:0;
  z-index:0;
  pointer-events:none;
  background:
    radial-gradient(86% 72% at 82% 18%, rgba(216,188,122,.10), transparent 64%),
    var(--home-ivory);
  opacity:var(--run-ivory);
  will-change:opacity;
}
body.home .hrun__viewport{ position:relative; z-index:1; }
body.home .hsay__big{ color:var(--run-ink); }
body.home .hsay__sub,
body.home .hframe figcaption{ color:var(--run-soft); }
body.home .hsay__eyebrow,
body.home .hframe__n{
  color:var(--run-accent);
  opacity:1;
  font-size:1rem;
  font-weight:600;
  font-variant-numeric:lining-nums tabular-nums;
}
body.home .hframe figcaption{ font-size:1rem; }
body.home .hghost{ color:var(--run-ghost); opacity:.09; }
body.home .hframe img{
  box-shadow:0 30px 80px rgba(42,42,38,.24), 0 0 0 1px rgba(255,255,255,.18);
}

/* The pinned gallery has a direct exit for readers who have seen enough. */
body.home .hrun__skip{
  position:absolute;
  z-index:4;
  left:clamp(18px,3vw,48px);
  bottom:clamp(18px,3vw,42px);
  display:inline-flex;
  align-items:center;
  gap:12px;
  min-height:44px;
  padding:10px 16px;
  border:1px solid rgba(24,24,21,.3);
  border-radius:999px;
  background:rgba(250,249,243,.94);
  color:var(--dark-deep);
  font-size:.9rem;
  font-weight:600;
  box-shadow:0 8px 28px rgba(24,24,21,.16);
}
body.home .hrun__skip:hover,
body.home .hrun__skip:focus-visible{ background:#fff; border-color:var(--dark-deep); }
body.home .hrun__skip:focus-visible{ outline:2px solid var(--dark-deep); outline-offset:3px; }
@media(max-width:899px){
  body.home .hrun__skip{top:12px;bottom:auto;left:var(--gut)}
  body.home .hrun.is-static .hrun__pin{padding-top:76px}
}

/* Keep the factual grade range intact when the marker wraps on a phone. */
body.home .hseq__grades{ white-space:nowrap; }
body.home .hseq__type .sc{ font-size:1rem; }
body.home .hseq__type h1 em{ font-family:"Newsreader",serif; font-weight:500; }
@media(max-width:600px){
  body.home .hseq__type{
    bottom:calc(var(--float-edge) + 2 * var(--float-size) + 28px);
    width:calc(100% - 2 * var(--gut));
  }
}

/* The remaining homepage fades use warm neutral density plus quiet gold
   illumination. None of these layers exceeds 18% gold opacity. */
body.home .filmsec,
body.home .finalcta,
body.home .footer{
  background-color:var(--home-night);
}

/* The credentials ticker is a band of the bright gold, lettered in ink. */
body.home .ticker{
  background:var(--gold); color:var(--ink);
  border-block-color:rgba(31,31,27,.14);
}
body.home .ticker__set i{ background:var(--ink); }

body.home .filmsec__media::after{
  background:
    linear-gradient(180deg, rgba(17,17,15,.72) 0%, rgba(17,17,15,.94) 100%),
    radial-gradient(80% 70% at 50% 100%, rgba(var(--gold-rgb),.12), transparent 68%);
}
body.home .filmwin__scrim{
  background:
    linear-gradient(180deg, rgba(17,17,15,.14) 0%, rgba(17,17,15,.72) 100%),
    radial-gradient(70% 65% at 50% 100%, rgba(var(--gold-rgb),.10), transparent 72%);
}
body.home .filmwin{ max-width:1120px; background:var(--home-night); }

body.home .motto{
  background:
    radial-gradient(90% 120% at 50% -10%, rgba(var(--gold-rgb),.16), transparent 62%),
    var(--home-parchment);
  color:var(--ink);
}
/* The motto on parchment: the Devanagari is display-sized, so the dark gold
   reads (4.3:1 on parchment, large text); the transliteration beneath it is
   body-sized and takes --ink-soft (6.9:1). */
body.home .motto__deva{ color:var(--gold-ink); }
body.home .motto__iast{ color:var(--ink-soft); }
body.home .motto__en{
  color:var(--ink-soft);
}
body.home .motto__rule{
  background:rgba(128,96,0,.45);
}

/* Photo crossfades keep their own stagger. Tone uses one class on the section,
   so hundreds of tiles do not each run a separate blend-mode animation. */
body.home .glimpse{
  background:var(--home-parchment);
}
body.home .glimpse__head h2{ color:var(--ink); }
body.home .glimpse__head h2 em{ color:var(--gold-ink); }
body.home .glimpse__head .lead{ color:var(--ink-soft); }
body.home .glimpse .marker .sc{
  color:var(--ink-soft);
}
body.home .glimpse .marker::before{ border-color:var(--gold-ink); }
/* The tone alternates between neighbours every few seconds. It is a filter on
   the tile, so without a transition half the wall changed between colour and
   grey in a single frame; with one the change is the same dissolve the frames
   themselves make, at the pace the shared sheet gives a hovered tile. */
body.home .glimpse .gt{
  background:var(--paper-3);
  transition:filter .55s var(--e);
}
body.home .glimpse .gt img{
  filter:none;
}
body.home .glimpse .gt::before,
body.home .glimpse .gt::after{
  opacity:0;
}
body.home .glimpse:not(.is-tone-flipped) .gt:nth-child(even),
body.home .glimpse.is-tone-flipped .gt:nth-child(odd){
  filter:grayscale(1);
}
body.home .glimpse:not(.is-tone-flipped) .gt:nth-child(even):hover,
body.home .glimpse.is-tone-flipped .gt:nth-child(odd):hover{
  filter:none;
}

body.home .finalcta__media::after{
  background:
    linear-gradient(180deg, rgba(17,17,15,.46) 0%, rgba(17,17,15,.92) 100%),
    radial-gradient(85% 68% at 50% 100%, rgba(var(--gold-rgb),.14), transparent 72%);
}
body.home .totop{ background:var(--gold); color:var(--on-gold); box-shadow:0 6px 24px rgba(17,17,15,.24); }

@media (prefers-reduced-motion:reduce){
  body.home .hrun__pin::before{ transition:none; }
}

/* ---- Phones: "A day at CIRS" as a deck of cards ----------------------
   cirs.js (homeRun) adds .is-deck under 900px when motion is allowed. The
   section is given a height; the pin sticks for its length and the script
   sets each card's transform from the scroll. Desktop is untouched. */
@media (max-width:899px){
  body.home .hrun.is-deck .hrun__pin{
    position:sticky; top:0; height:100svh; height:100vh; overflow:hidden;
  }
  body.home .hrun.is-deck .hrun__viewport{
    height:100%; overflow:visible; perspective:1100px; perspective-origin:50% 45%;
    touch-action:pan-y;
  }
  body.home .hrun.is-deck .hrun__viewport:focus-visible{ outline:2px solid var(--dark-deep); outline-offset:-6px; }
  body.home .hrun.is-deck .hrun__stage{
    display:block; width:100%; height:100%; min-width:0; padding:0; transform:none !important;
  }
  body.home .hrun.is-deck .hghost{ display:none; }
  body.home .hrun.is-deck .hframe,
  body.home .hrun.is-deck .hsay{
    position:absolute; inset:auto !important;
    left:50% !important; top:54% !important;
    margin:0; flex:none;
    width:min(84vw,340px);
    border-radius:22px;
    transform-origin:50% 110%;
    will-change:transform, opacity;
    backface-visibility:hidden;
  }
  body.home .hrun.is-deck .hframe{
    padding:12px 12px 14px;
    background:#FAF9F3;
    box-shadow:0 22px 50px rgba(24,24,21,.28), 0 0 0 1px rgba(24,24,21,.06);
  }
  body.home .hrun.is-deck .hframe--portrait{ width:min(74vw,300px); }
  body.home .hrun.is-deck .hframe--tall{ width:min(66vw,270px); }
  body.home .hrun.is-deck .hframe img{
    width:100%; border-radius:14px; border:0; box-shadow:none;
  }
  body.home .hrun.is-deck .hframe__n{ margin-bottom:8px; color:var(--ink-soft); font-size:.85rem; }
  body.home .hrun.is-deck .hframe figcaption{
    margin-top:10px; color:var(--dark-deep); font-size:.95rem; font-weight:500;
  }
  body.home .hrun.is-deck .hsay{
    padding:28px 24px 30px;
    background:linear-gradient(160deg, #FAF9F3 0%, #F1EAD8 100%);
    box-shadow:0 22px 50px rgba(24,24,21,.26), inset 0 0 0 1px rgba(143,110,47,.22);
  }
  body.home .hrun.is-deck .hsay > *{ transform:none; }
  body.home .hrun.is-deck .hsay__eyebrow{ color:var(--gold-ink); font-size:.9rem; margin-bottom:14px; }
  body.home .hrun.is-deck .hsay__big{
    color:var(--dark-deep); font-size:clamp(1.65rem,7.4vw,2.2rem); text-shadow:none;
  }
  body.home .hrun.is-deck .hsay__sub{ color:var(--ink-soft); font-size:1rem; line-height:1.5; margin-top:14px; }
  body.home .hrun.is-deck .hrun__skip{ top:auto; bottom:18px; left:var(--gut); }

  body.home .hrun__count{
    position:absolute; z-index:4; right:var(--gut); bottom:28px; margin:0;
    font-family:var(--font-ui); font-size:.85rem; font-weight:600; letter-spacing:.06em;
    font-variant-numeric:tabular-nums; color:var(--run-ink);
  }
  body.home .hrun__cue{
    position:absolute; z-index:4; left:50%; bottom:84px; margin:0;
    transform:translate(-50%,12px); opacity:0; pointer-events:none;
    display:flex; flex-direction:column; align-items:center; gap:4px;
    font-family:var(--font-ui); font-size:.85rem; font-weight:600; letter-spacing:.08em;
    text-transform:uppercase; color:var(--run-ink);
    transition:opacity .35s ease, transform .35s ease;
  }
  body.home .hrun__cue span{ font-size:1.2rem; animation:hrun-cue 1.4s ease-in-out infinite; }
  body.home .hrun__cue.is-on{ opacity:1; transform:translate(-50%,0); }
  @keyframes hrun-cue{ 0%,100%{ transform:translateY(0); } 50%{ transform:translateY(7px); } }

  /* Motion off or no GSAP: the phone layout is a vertical column, not a
     sideways track that has to be swiped. */
  body.home .hrun.is-static .hrun__viewport{ overflow:visible; }
  body.home .hrun.is-static .hrun__stage{
    flex-direction:column; align-items:center; gap:44px;
  }
  body.home .hrun.is-static .hframe--wide,
  body.home .hrun.is-static .hsay{ width:min(88vw,560px); }
  body.home .hrun.is-static .hframe--portrait{ width:min(76vw,420px); }
  body.home .hrun.is-static .hframe--tall{ width:min(70vw,380px); }
}
@media (max-width:899px) and (prefers-reduced-motion:reduce){
  body.home .hrun__cue span{ animation:none; }
}

/* The opening photograph on a portrait screen: the cover crop keeps the
   portico and the ridge behind it at the centre of the frame instead of
   the left-hand wing. */
@media (max-aspect-ratio:4/5){
  body.home .hseq__video{ object-position:69% 40%; }
}

/* ---- assets/css/typography.css ---- */
/* Type roles. Loaded after all page-specific sheets.
   Families are named once, in cirs.css :root; this sheet assigns them.
   Mona Sans carries English body, interface, labels, captions, data and
   the film titles. Bodoni Moda carries display lettering; Literata and
   EB Garamond retain the editorial and quotation roles. */
:root{
  --weight-body:350;
  --weight-display:600;
  --weight-section:500;
  --weight-subheading:500;
  --weight-nav:450;
  --weight-control:600;
  --weight-label:500;
  --fs-body:1.0625rem;
  --fs-sm:.9375rem;
  --fs-xs:.875rem;
}
html{ font-synthesis:none; font-optical-sizing:auto; }
body, input, select, textarea, button, code, pre, kbd, samp, svg text{ font-family:var(--font-body); }
input, select, textarea{ font-size:inherit; }

/* Genuine variable weights, independent of legacy page-specific heading rules. */
body{ font-weight:var(--weight-body); }
body :is(h1, .h1){ font-weight:var(--weight-display); }
/* Homepage hero retains the requested regular weight. */
body .hero__inner > h1{ font-weight:400; }
body :is(h2, .h2){ font-weight:var(--weight-section); }
body :is(h3, h4, .h3, .h4){ font-weight:var(--weight-subheading); }
body.wall .p1-hero-text{ font-weight:var(--weight-display); }
/* The one line on a scrubbed-film opening — CIRS Captures, Our Sports,
   CIRS Theatre — is built on genuinely thin lettering. Mona Sans's lightest
   weight, a little expanded, keeps that airy line; font-stretch selects
   the width-axis cut, which only these pages fetch. Stated here because
   this file is loaded after every page sheet and would otherwise overrule it. */
body .film__title{ font-weight:200; font-stretch:105%; }
body :is(.nv-tab, .nv-enq__close, .nv-menu__utility a, .nv-cta--quiet, .jump__toggle){ font-weight:var(--weight-nav); }
body .btn{ font-weight:var(--weight-control); }
body :is(.sc, .art__flag, .art__issue, .art__by, .nx-tag, .nx-meta, .fmeta, .fnav__label){ font-weight:var(--weight-label); }

/* Only these two existing introductions use the editorial family. */
.crhero__lead, .advert__sub{ font-family:var(--font-editorial); }

/* Quotations and expressive emphasis; attribution stays in the interface face. */
blockquote, .quote__text, .fhero__say, .motto__iast, .fmotto__roman,
body :is(h1, h2, h3, h4, .h1) em, .saga__line em{
  font-family:var(--font-quote);
  font-style:italic;
  font-weight:400;
}
blockquote p{ font-family:inherit; font-style:inherit; }
blockquote cite, blockquote footer, figcaption{ font-family:var(--font-ui); }

/* :lang also covers descendants inheriting a Sanskrit/Hindi language tag. */
body :is(:lang(hi), :lang(sa), .deva){
  font-family:var(--deva);
  font-weight:400;
  font-style:normal;
  font-stretch:normal;
  line-height:1.5;
  letter-spacing:normal;
  text-transform:none;
}

/* Keep small labels readable with the new English face. */
.art__flag, .art__issue, .nx-tag, .nx-meta,
.fmeta, .fhero__sig, .fhero__cue, .fnav__label{ font-size:var(--fs-xs); }
.sc{ line-height:1.3; }
.btn{ line-height:1.35; }

/* Retain the gallery's gold palette without painting a gradient through text. */
body.wall .p1-hero-text{
  background:none;
  -webkit-background-clip:border-box;
  background-clip:border-box;
  color:var(--gold-lit);
}

/* Metric-specific composition corrections; keep mobile sizing intact. */
.founder .fcvp .fsec__head{ max-width:42rem; }
.dmoment h3{ text-wrap:balance; }
@media (min-width:701px){
  .hrun.is-static .hsay--open{ width:min(80vw,470px); }
  .hrun.is-static .hsay--open .hsay__big{ font-size:clamp(2.1rem,3.3vw,3rem); }
}

/* ---- assets/css/footer.css ---- */
/* Shared campus closing scene and practical footer. */
.closing-scene{
  position:relative;
  z-index:1;
  display:flex;
  min-height:100vh;
  min-height:100svh;
  overflow:hidden;
  isolation:isolate;
  color:var(--on-dark);
  background:var(--dark-ink);
}
.closing-scene__picture{
  position:absolute;
  z-index:-2;
  inset:-1.5%;
  overflow:hidden;
}
.closing-scene__image{
  width:100%;
  height:100%;
  object-fit:cover;
  object-position:50% 55%;
  filter:brightness(.82) saturate(.78) sepia(.08);
  transform:translate3d(var(--scene-shift-x, 0px),var(--scene-shift-y, 0px),0) scale(1.055);
  transition:transform .75s var(--e);
}
.closing-scene__grade{
  position:absolute;
  z-index:-1;
  inset:0;
  pointer-events:none;
  background:
    linear-gradient(90deg,rgba(17,17,15,.67) 0%,rgba(17,17,15,.38) 48%,rgba(17,17,15,.16) 100%),
    linear-gradient(180deg,rgba(24,24,21,.30) 0%,rgba(24,24,21,.12) 32%,rgba(17,17,15,.22) 60%,var(--dark-ink) 100%),
    linear-gradient(0deg,rgba(143,110,47,.25),transparent 58%);
}
.closing-scene__inner{
  position:relative;
  z-index:1;
  display:flex;
  align-items:center;
  width:100%;
  min-height:inherit;
  padding-block:clamp(128px,17vh,190px) clamp(100px,13vh,144px);
}
.closing-scene__content{ width:min(100%,900px); }
.closing-scene__title{
  max-width:100%;
  color:var(--on-dark);
  font-family:var(--font-display);
  font-size:clamp(3rem,6.4vw,6rem);
  font-weight:400;
  letter-spacing:-.025em;
  line-height:.98;
  text-wrap:balance;
  text-shadow:0 2px 24px rgba(17,17,15,.2);
}
.closing-scene__title span{ display:block; }
.closing-scene__title span + span{ color:inherit; }
.closing-scene__links{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:14px 28px;
  margin-top:clamp(28px,4vh,42px);
}
.closing-scene__admissions{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-height:56px;
  padding:14px 24px;
  border:1px solid var(--gold-pale);
  background:var(--gold-pale);
  color:var(--on-gold);
  font-size:1rem;
  font-weight:600;
  line-height:1.25;
  transition:background .2s var(--e),border-color .2s var(--e),color .2s var(--e),transform .2s var(--e);
}
.closing-scene__admissions:hover{
  transform:translateY(-2px);
  border-color:var(--gold-pale);
  background:var(--gold-pale);
}
.closing-scene__contact{
  display:inline-flex;
  align-items:center;
  min-height:48px;
  color:var(--on-dark);
  font-size:1rem;
  text-decoration:underline;
  text-decoration-color:rgba(var(--gold-rgb),.75);
  text-decoration-thickness:1px;
  text-underline-offset:5px;
  transition:color .2s var(--e),text-decoration-color .2s var(--e);
}
.closing-scene__contact:hover{ color:var(--gold-lit); text-decoration-color:currentColor; }
.closing-scene :focus-visible,
.footer :focus-visible{
  outline:2px solid var(--gold-lit);
  outline-offset:4px;
}

/* Motion is enabled only after the shared script loads; without scripting the
   closing links stay visible and available. */
html.has-footer-scene-motion .closing-scene__content{
  opacity:0;
  transform:translateY(18px);
  transition:opacity .8s var(--e2),transform .8s var(--e2);
}
html.has-footer-scene-motion .closing-scene.is-visible .closing-scene__content{
  opacity:1;
  transform:none;
}

.footer{ background:var(--dark-ink); color:var(--on-dark-soft); }
.footer__main{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:34px 26px;
  padding-block:48px 42px;
}
.footer__identity{ grid-column:1/-1; }
.footer__brand{ display:flex; align-items:center; gap:18px; margin-bottom:20px; }
.footer__brand img{ width:clamp(58px,6vw,74px); height:auto; flex:none; }
.footer__brand span{
  color:var(--on-dark);
  font-family:var(--font-display);
  font-size:clamp(1.25rem,1.7vw,1.55rem);
  line-height:1.2;
}
.footer__address{
  display:grid;
  gap:8px;
  font-size:var(--fs-sm);
  font-style:normal;
  line-height:1.7;
}
.footer__address a{ color:var(--on-dark-soft); text-decoration:underline; text-decoration-color:rgba(255,255,255,.32); text-underline-offset:3px; }
.footer__address a:hover{ color:var(--on-dark); text-decoration-color:var(--gold-lit); }
.footer__heading{
  margin:0 0 12px;
  color:var(--gold-lit);
  font-family:var(--font-ui);
  font-size:1rem;
  font-weight:500;
  line-height:1.35;
}
.footer__group ul{ display:grid; gap:4px; }
.footer__group li a{
  display:inline-block;
  padding-block:2px;
  color:var(--on-dark-soft);
  font-size:var(--fs-sm);
  line-height:1.45;
  text-decoration:underline;
  text-decoration-color:transparent;
  text-underline-offset:3px;
  transition:color .2s var(--e),text-decoration-color .2s var(--e);
}
.footer__group li a:hover{ color:var(--on-dark); text-decoration-color:var(--gold-lit); }
.footer__bar{
  display:flex;
  flex-wrap:wrap;
  gap:8px 24px;
  justify-content:space-between;
  padding-block:16px 20px;
  border-top:1px solid var(--rule-dark);
  color:var(--on-dark-mute);
  font-size:var(--fs-xs);
  line-height:1.5;
}

/* Keep the page index and back-to-top control clear of the final two sections. */
html.footer-zone-active .jump,
html.footer-zone-active .totop{
  opacity:0;
  visibility:hidden;
  pointer-events:none;
}

@media (min-width:740px){
  .footer__main{ grid-template-columns:repeat(3,minmax(0,1fr)); gap:38px 30px; }
  .footer__identity{ grid-column:1/-1; }
}
@media (min-width:1280px){
  .footer__main{
    grid-template-columns:minmax(290px,1.75fr) repeat(5,minmax(0,1fr));
    gap:24px;
    padding-block:62px 48px;
  }
  .footer__identity{ grid-column:auto; }
}
@media (max-width:739px){
  .closing-scene{ min-height:88svh; }
  .closing-scene__picture{ inset:-1%; }
  .closing-scene__image{
    object-position:53% 48%;
    filter:brightness(.74) saturate(.76) sepia(.10);
    transform:scale(1.025);
    transition:none;
  }
  .closing-scene__grade{
    background:
      linear-gradient(90deg,rgba(17,17,15,.42),rgba(17,17,15,.14)),
      linear-gradient(180deg,rgba(24,24,21,.22),rgba(17,17,15,.28) 40%,var(--dark-ink) 100%),
      linear-gradient(0deg,rgba(143,110,47,.20),transparent 58%);
  }
  .closing-scene__inner{
    align-items:flex-end;
    padding-block:120px 86px;
  }
  .closing-scene__content{ max-width:560px; }
  .closing-scene__title{ font-size:clamp(2.65rem,11vw,4.1rem); max-width:11ch; }
  .closing-scene__links{ gap:8px 20px; margin-top:28px; }
  .closing-scene__admissions{ min-height:52px; padding-inline:19px; }
  .footer__bar{ flex-direction:column; gap:5px; }
}
@media (prefers-reduced-motion:reduce){
  .closing-scene__image,
  html.has-footer-scene-motion .closing-scene__content,
  .closing-scene__admissions,
  .closing-scene__contact,
  .footer__group li a,
  .footer__address a{
    transition:none;
    transform:none;
  }
  html.has-footer-scene-motion .closing-scene__content{ opacity:1; }
}

/* ---- assets/css/drawer.css ---- */
/* ============================================================
   The site's navigation — header, full-screen menu, Enquire.
   Type follows the roles in typography.css: the school's name and the
   category words in the display face, everything else in the interface
   and body face at the navigation weight.
   Markup: tools/partials/header.html, tools/partials/drawer.html and
   nav_html() in tools/build-site.py. Behaviour: "Header, menu and
   Enquire" in assets/js/cirs.js. Worked out first as the prototype in
   previews/navigation/, whose README records the brief.

   Colour: none of its own. Every colour below is a role from the top
   of assets/css/cirs.css, read as it stands:
     --paper    signature ivory   header, category area, Enquire
     --paper-2  alternate ivory   destination area
     --ink / --ink-soft / --ink-mute   lettering
     --rule     hairlines
     --gold     rules, markers and the one filled button — never
                lettering on ivory
     --on-gold  lettering on the gold fill
     --focus    the keyboard ring
   The bar carries the recovered purple as a restrained glass surface.
   Menu and Enquire sheets remain opaque ivory for longer reading.
   ============================================================ */

:root{
  --nv-hh:76px;                         /* the header's height */
  --nv-crest:48px;                      /* the crest in the open bar */
  --nv-split:52%;                       /* category area | destination area */
  --nv-num:3.25rem;                     /* the category number column */
  --nv-cat-size:clamp(2.5rem, min(4.3vw, 7.4vh), 4.25rem);
  --nv-cat-pad:clamp(6px, 1.5vh, 16px);
  --nv-dest-size:clamp(1.375rem, min(1.95vw, 3.5vh), 1.85rem);
}
.nv-sr{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

/* ------------------------------------------------------------
   Header — original Enquire and Home left, crest centred, News and Menu
   right. Two states, chosen by the controller in cirs.js:

     hero     over a full-screen opening, no surface at all. The controls
              sit on the picture in white (or in ink, where the page's
              opening is pale: data-header-tone="light"), held off bright
              skies by a soft shadow rather than by a bar.
     content  a compact, translucent ivory pill floating clear of the edges,
              lettered in ink. Every page without a full-screen opening
              starts here; the others gather into it on the first scroll.

   The <header> itself is only the fixed frame and takes no pointer: the
   bar inside it is what morphs, so the air around the pill stays live.
   Gold appears in the News dot and the rule under a hovered or open control.
   ------------------------------------------------------------ */
.nv-header{
  position:fixed; top:0; left:0; right:0; z-index:118;
  height:var(--nv-hh);
  --nv-pill-inset:10px;                           /* air around the pill */
  --nv-pill-h:max(50px, calc(var(--nv-hh) - 18px)); /* 58px, 50px on phones */
  --nv-pill-max:1180px;
  --nv-morph:.5s var(--e2);
  --nav-name:#fff;
  --nav-sub:rgba(255,255,255,.9);
  --nav-text:#fff;
  --nav-icon:rgba(255,255,255,.9);
  --nav-hover:var(--gold-lit);
  --nav-lift:drop-shadow(0 1px 8px rgba(17,17,15,.45));
  background:transparent;
  pointer-events:none;
  transition:opacity .35s var(--e), visibility .35s;
}
.nv-header[data-header-tone="light"]{
  --nav-name:var(--ink);
  --nav-sub:var(--ink-mute);
  --nav-text:var(--ink);
  --nav-icon:var(--ink-soft);
  --nav-hover:var(--ink);
  --nav-lift:none;
}
.nv-header__bar{
  display:grid; grid-template-columns:1fr auto 1fr; align-items:center;
  gap:var(--space-4);
  width:100%; height:var(--nv-hh);
  margin:0 auto;
  padding-inline:var(--gut);
  pointer-events:auto;
  background-color:transparent;
  border:1px solid transparent;
  border-radius:0;
  box-shadow:none;
  transition:width var(--nv-morph), height var(--nv-morph), margin var(--nv-morph),
             padding var(--nv-morph), border-radius var(--nv-morph),
             background-color .35s var(--e), border-color .35s var(--e), box-shadow .35s var(--e),
             -webkit-backdrop-filter .35s var(--e), backdrop-filter .35s var(--e);
}
/* Over the opening the lettering carries its own shadow instead of a bar. */
.nv-header[data-header-mode="hero"] :is(.nv-brand, .nv-tab){ filter:var(--nav-lift); }

/* The pill: on scroll and by default on pages without a full-screen opening.
   Enquire adds its reading surface without moving the trigger: gathering the
   hero bar under a stationary pointer caused repeated mouseleave/open loops. */
.nv-header[data-header-mode="content"],
.nv-header:has(.nv-enq.is-open){
  --nav-name:var(--ink);
  --nav-sub:var(--ink-mute);
  --nav-text:var(--ink);
  --nav-icon:var(--ink-soft);
  --nav-hover:var(--ink);
  --nav-lift:none;
}
.nv-header[data-header-mode="content"] .nv-header__bar{
  width:min(calc(100% - 2 * var(--nv-pill-inset)), var(--nv-pill-max));
  height:var(--nv-pill-h);
  margin-top:var(--nv-pill-inset);
  padding-inline:clamp(14px, 2vw, 28px);
  border-radius:999px;
}
.nv-header[data-header-mode="content"] .nv-header__bar,
.nv-header:has(.nv-enq.is-open) .nv-header__bar{
  background-color:rgba(250,249,243,.95);
  border-color:rgba(31,31,27,.08);
  box-shadow:0 10px 32px rgba(17,17,15,.14), 0 1px 3px rgba(17,17,15,.08);
}
@supports ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){
  .nv-header[data-header-mode="content"] .nv-header__bar,
  .nv-header:has(.nv-enq.is-open) .nv-header__bar{
    background-color:rgba(250,249,243,.74);
    -webkit-backdrop-filter:blur(18px) saturate(1.5);
    backdrop-filter:blur(18px) saturate(1.5);
  }
}
/* Compact: the crest steps down and the sub-line folds away inside the pill. */
.nv-header[data-header-mode="content"] .nv-brand img{ width:calc(var(--nv-crest) * .8); }
.nv-header[data-header-mode="content"] .nv-brand__sub{ max-height:0; opacity:0; }

/* The menu is a full-screen ivory sheet under the bar, so while it is open
   the bar opens out to meet it edge to edge. */
body.menu-open .nv-header{
  --nav-name:var(--ink);
  --nav-sub:var(--ink-mute);
  --nav-text:var(--ink);
  --nav-icon:var(--ink-soft);
  --nav-hover:var(--ink);
}
body.menu-open .nv-header :is(.nv-brand, .nv-tab){ filter:none; }
body.menu-open .nv-header .nv-header__bar{
  width:100%; height:var(--nv-hh); margin-top:0;
  padding-inline:var(--gut);
  border-radius:0;
  background-color:var(--paper);
  border-color:transparent transparent var(--rule);
  box-shadow:0 3px 14px rgba(20,30,33,.07);
  -webkit-backdrop-filter:none;
  backdrop-filter:none;
}
@media (prefers-reduced-transparency:reduce){
  .nv-header[data-header-mode="content"] .nv-header__bar,
  .nv-header:has(.nv-enq.is-open) .nv-header__bar{
    background-color:var(--paper);-webkit-backdrop-filter:none;backdrop-filter:none;
  }
}
@media (prefers-reduced-motion:reduce){
  .nv-header{ --nv-morph:.01s linear; }
}
.nv-header :focus-visible{ outline-color:var(--gold-lit); }
.nv-header[data-header-tone="light"] :focus-visible,
.nv-header[data-header-mode="content"] :focus-visible,
.nv-header:has(.nv-enq.is-open) :focus-visible,
body.menu-open .nv-header :focus-visible{ outline-color:var(--focus); }
.nv-header.is-settling,.nv-header.is-settling *{ transition:none!important; }
body:has(#curtain) .nv-header,
body.founder:has(.gurudev-opening[data-phase="intro"]) .nv-header,
body.founder:has(.gurudev-opening[data-phase="leaving"]) .nv-header{
  opacity:0; visibility:hidden; pointer-events:none;
}
body:has(#curtain) .nv-header__bar,
body.founder:has(.gurudev-opening[data-phase="intro"]) .nv-header__bar,
body.founder:has(.gurudev-opening[data-phase="leaving"]) .nv-header__bar{
  pointer-events:none;
}
.nv-header__side{ display:flex; align-items:center; gap:var(--space-5); min-width:0; }
.nv-header__side--left{ justify-self:start; }
.nv-header__side--right{ justify-self:end; }

.nv-brand{ display:flex; align-items:center; gap:13px; min-width:0; justify-self:center; color:var(--nav-name); transition:color .3s var(--e); }
.nv-brand img{ width:var(--nv-crest); height:auto; flex:none; transition:width var(--nv-morph); }
.nv-brand__txt{ display:flex; flex-direction:column; gap:3px; min-width:0; }
.nv-brand__name{ font-family:var(--font-display); font-size:1.16rem; line-height:1.06; letter-spacing:-.005em; white-space:nowrap; }
.nv-brand__sub{ max-height:1em; overflow:hidden; font-family:var(--font-ui); font-size:.8rem; letter-spacing:.11em; line-height:1; color:var(--nav-sub); white-space:nowrap; transition:color .3s var(--e), max-height var(--nv-morph), opacity .3s var(--e); }
.nv-brand__short{ display:none; font-family:var(--font-display); font-size:1.2rem; letter-spacing:.08em; line-height:1; }

.nv-tab{
  position:relative;
  display:inline-flex; align-items:center; justify-content:center; gap:9px;
  min-height:44px; padding:0 2px;
  color:var(--nav-text);
  font-family:var(--font-ui);
  font-size:.92rem; letter-spacing:.06em; line-height:1; white-space:nowrap;
  transition:color .3s var(--e);
}
.nv-tab__icon{ display:grid; place-items:center; height:18px; color:var(--nav-icon); transition:color .2s var(--e); }
/* The one gold gesture in the bar: a short rule under the control on
   hover, which stays while its panel is open. */
.nv-tab::after{
  content:""; position:absolute; left:0; right:0; bottom:7px;
  height:1px; background:var(--gold);
  transform:scaleX(0); transform-origin:left;
  transition:transform .28s var(--e2);
}
.nv-tab[aria-expanded="true"]::after,
.nv-tab[aria-current="page"]::after{ transform:scaleX(1); }
@media (hover:hover){
  .nv-tab:hover::after{ transform:scaleX(1); }
  .nv-tab:hover .nv-tab__icon{ color:var(--nav-hover); }
}
.nv-tab--news .nv-tab__icon{ position:relative; }
.nv-tab--news .nv-tab__icon::after{
  content:""; position:absolute; top:-1px; right:-3px;
  width:5px; height:5px; border-radius:50%; background:var(--gold);
}

/* Menu ⇄ Close. Both words hold the same box, so the control never
   changes width; the two lines fold into a cross.

   The Menu control's rule sits under the word alone, never under the
   lines or the cross beside it. It draws in from the left as the menu
   opens (or under a hovering pointer) and, as it closes, retracts out to
   the right rather than snapping. After a click closes the menu the
   pointer is usually still over the control; .is-settling-rule holds the
   hover rule back until the pointer leaves, so nothing lingers beneath
   the control once the menu has gone. */
.nv-tab--menu::after{ content:none; }
.nv-tab--menu .nv-tab__label{ position:relative; display:inline-grid; }
.nv-tab--menu .nv-tab__label::after{
  content:""; position:absolute; left:0; right:0; bottom:-8px;
  height:1px; background:var(--gold);
  transform:scaleX(0); transform-origin:right;
  transition:transform .42s var(--e);
}
.nv-tab--menu[aria-expanded="true"] .nv-tab__label::after{
  transform:scaleX(1); transform-origin:left; transition:transform .36s var(--e2);
}
@media (hover:hover){
  .nv-tab--menu:not(.is-settling-rule):hover .nv-tab__label::after{
    transform:scaleX(1); transform-origin:left; transition:transform .36s var(--e2);
  }
}
@media (prefers-reduced-motion:reduce){
  .nv-tab--menu .nv-tab__label::after{ transition-duration:.01s; }
}
.nv-menu-word{ grid-area:1/1; text-align:right; transition:opacity .16s var(--e); }
.nv-menu-word--close{ opacity:0; }
.nv-tab--menu[aria-expanded="true"] .nv-menu-word--open{ opacity:0; }
.nv-tab--menu[aria-expanded="true"] .nv-menu-word--close{ opacity:1; }
.nv-lines{ position:relative; width:22px; height:12px; flex:none; }
.nv-lines i{
  position:absolute; left:0; right:0; height:1.4px; background:currentColor;
  transition:transform .3s var(--e2), top .3s var(--e2);
}
.nv-lines i:first-child{ top:2px; }
.nv-lines i:last-child{ top:9px; left:7px; }
.nv-tab--menu[aria-expanded="true"] .nv-lines i{ top:5.3px; left:0; }
.nv-tab--menu[aria-expanded="true"] .nv-lines i:first-child{ transform:rotate(45deg); }
.nv-tab--menu[aria-expanded="true"] .nv-lines i:last-child{ transform:rotate(-45deg); }

/* ------------------------------------------------------------
   Enquire — an opaque ivory sheet hung from the bar. Hierarchy
   does the work: a small ruled heading, the contact itself set
   large, what it is set small above it. It carries its own Close.
   ------------------------------------------------------------ */
.nv-enq{ position:relative; }
.nv-enq__panel{
  position:fixed; top:var(--nv-hh); left:var(--gut); z-index:110;
  width:min(620px, calc(100vw - 2 * var(--gut)));
  max-height:calc(100dvh - var(--nv-hh) - 24px); overflow-y:auto; overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
  padding:var(--space-4) var(--space-6) var(--space-5);
  background:var(--paper);
  border:1px solid var(--rule); border-top:0;
  box-shadow:var(--shadow-image);
  opacity:0; transform:translateY(-6px);
  visibility:hidden;
  transition:opacity .18s var(--e), transform .24s var(--e2), visibility 0s linear .24s;
}
.nv-enq__panel[hidden]{ display:none; }
.nv-enq.is-open .nv-enq__panel{
  opacity:1; transform:none; visibility:visible;
  transition:opacity .18s var(--e), transform .24s var(--e2), visibility 0s;
}
/* A bridge over the bar's lower half, so the pointer can travel from
   the tab into the sheet without passing through dead space. */
.nv-enq__panel::before{ content:""; position:absolute; left:0; right:0; top:-24px; height:24px; }

.nv-enq__head{
  display:flex; align-items:center; justify-content:space-between; gap:var(--space-4);
  min-height:44px; margin-bottom:var(--space-4);
  border-bottom:1px solid var(--rule);
}
.nv-enq__heading{ color:var(--ink); font-size:1.05rem; letter-spacing:.01em; }
.nv-enq__close{
  position:relative; min-height:44px; padding:0 2px;
  color:var(--ink); font-size:.92rem; letter-spacing:.06em;
}
.nv-enq__close::after{
  content:""; position:absolute; left:0; right:0; bottom:9px; height:1px;
  background:var(--gold); transform:scaleX(0); transform-origin:left;
  transition:transform .28s var(--e2);
}
.nv-enq__close:focus-visible::after{ transform:scaleX(1); }

.nv-enq__grid{
  display:grid; grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);
  gap:var(--space-6);
}
.nv-enq__title{
  display:flex; align-items:center; gap:10px;
  font-family:var(--font-ui);
  margin:0 0 var(--space-3);
  color:var(--ink-soft);
  font-size:.74rem; font-weight:500; letter-spacing:.16em; text-transform:uppercase; line-height:1;
}
.nv-enq__title::before{ content:""; width:18px; height:1px; background:var(--gold); flex:none; }

/* Both columns open on a hairline and are divided by hairlines; the
   rule above Follow CIRS closes them both. */
.nv-enq__contact{
  display:block;
  padding:var(--space-4) 0;
  border-top:1px solid var(--rule);
  color:var(--ink);
}
.nv-enq__meta{
  display:block; margin-bottom:6px;
  color:var(--ink-mute); font-size:.84rem; letter-spacing:.02em; line-height:1.3;
}
.nv-enq__value{
  position:relative; display:inline-block; max-width:100%;
  font-size:1.42rem; line-height:1.2; letter-spacing:-.01em;
  overflow-wrap:anywhere;
}
.nv-enq__value::after{
  content:""; position:absolute; left:0; right:0; bottom:-3px; height:1px;
  background:var(--gold); transform:scaleX(0); transform-origin:left;
  transition:transform .3s var(--e2);
}
.nv-enq__contact:focus-visible .nv-enq__value::after{ transform:scaleX(1); }

.nv-enq__doors{ border-top:1px solid var(--rule); }
.nv-enq__doors li + li{ border-top:1px solid var(--rule); }
.nv-enq__doors a{
  display:flex; align-items:center; justify-content:space-between; gap:var(--space-3);
  min-height:52px; padding:var(--space-2) 0;
  color:var(--ink); font-size:1.08rem;
}
.nv-enq__doors svg{ color:var(--ink-mute); flex:none; transition:transform .25s var(--e2), color .2s var(--e); }
.nv-enq__doors a:focus-visible svg{ color:var(--ink); transform:translateX(3px); }

.nv-enq__follow{
  display:flex; align-items:center; justify-content:space-between; gap:var(--space-4);
  flex-wrap:wrap;
  margin-top:var(--space-3); padding-top:var(--space-4);
  border-top:1px solid var(--rule);
}
.nv-enq__follow .nv-enq__title{ margin:0; }
.nv-enq__social{ display:flex; gap:8px; }
.nv-enq__social a{
  display:grid; place-items:center; width:44px; height:44px;
  border:1px solid var(--rule); border-radius:50%;
  color:var(--ink-soft);
  transition:background .2s var(--e), border-color .2s var(--e), color .2s var(--e);
}
.nv-enq__social svg{ width:20px; height:20px; overflow:visible; }
.nv-enq__social svg :is(rect,circle){ fill:none; stroke:currentColor; stroke-width:1.65; }
.nv-enq__social svg path{ fill:currentColor; stroke:none; }
.nv-enq__social svg .nv-dot{ fill:currentColor; stroke:none; }
.nv-enq__social svg .nv-play{ fill:var(--paper); }
.nv-enq__social a:focus-visible{
  background:var(--gold); border-color:var(--gold); color:var(--on-gold);
}
.nv-enq__social a:focus-visible .nv-play{ fill:var(--gold); }

/* ------------------------------------------------------------
   The full-screen menu. Two ivory grounds under the header: the
   signature ivory carries the five categories in one number
   column and one label column; the alternate ivory, past one
   fine rule, carries the pages of the category that is open.
   ------------------------------------------------------------ */
.nv-menu{
  position:fixed; inset:var(--nv-hh) 0 0 0; z-index:116;
  display:flex; flex-direction:column;
  overflow-x:hidden; overflow-y:auto; overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
  background:var(--paper);
  clip-path:inset(0 0 100% 0);
  visibility:hidden;
  transition:clip-path .26s var(--e), visibility 0s linear .26s;
}
.nv-menu[hidden]{ display:none; }
.nv-menu.is-open{
  clip-path:inset(0 0 0 0);
  visibility:visible;
  transition:clip-path .42s var(--e2), visibility 0s;
}
/* The destination ground, and the fine rule that divides the two. */
.nv-menu::before{
  content:""; position:absolute; top:0; bottom:0; left:var(--nv-split); right:0;
  background:var(--paper-2); z-index:0; pointer-events:none;
}
.nv-menu::after{
  content:""; position:absolute; top:0; bottom:0; left:var(--nv-split);
  width:1px; background:var(--rule); z-index:0; pointer-events:none;
}

.nv-menu__stage{ position:relative; z-index:1; flex:1 0 auto; display:flex; }
.nv-menu__nav{
  position:relative;
  flex:1;
  display:grid;
  grid-template-columns:var(--nv-split) minmax(0,1fr);
  grid-template-rows:repeat(5, auto);
  align-content:center;
  padding-block:clamp(20px, 5vh, 64px);
}
.nv-item{ display:contents; }
.nv-item:nth-child(1) .nv-cat{ grid-row:1; }
.nv-item:nth-child(2) .nv-cat{ grid-row:2; }
.nv-item:nth-child(3) .nv-cat{ grid-row:3; }
.nv-item:nth-child(4) .nv-cat{ grid-row:4; }
.nv-item:nth-child(5) .nv-cat{ grid-row:5; }

/* A category: one number column, one label column, on one baseline.
   Nothing about it moves when it becomes active — only its colour
   changes and the gold marker arrives beside it. */
.nv-cat{
  grid-column:1;
  position:relative;
  display:grid; grid-template-columns:var(--nv-num) minmax(0,1fr); align-items:baseline;
  width:100%;
  padding:var(--nv-cat-pad) clamp(24px,3vw,48px) var(--nv-cat-pad) var(--gut);
  color:var(--ink-mute);
  text-align:left;
  transition:color .2s var(--e);
}
.nv-cat__num{
  font-family:var(--font-ui);
  font-size:.8rem; letter-spacing:.08em; font-variant-numeric:lining-nums tabular-nums;
  line-height:1;
}
.nv-cat__word{
  font-family:var(--font-display); font-weight:400;
  font-size:var(--nv-cat-size);
  line-height:1.04; letter-spacing:-.03em;
  text-wrap:balance;
}
@media (hover:hover){ .nv-cat:hover{ color:var(--ink); } }
.nv-cat[aria-expanded="true"]{ color:var(--ink); }

/* The active marker: one short gold rule that travels between the
   categories rather than five that switch on and off. nav.js sets
   its position; without script the open category keeps its colour. */
.nv-marker{
  position:absolute; left:calc(var(--gut) - 22px); top:0;
  width:2px; height:calc(var(--nv-cat-size) * .7);
  background:var(--gold);
  opacity:0;
  transition:transform .26s var(--e2), opacity .2s var(--e);
  pointer-events:none;
}
.nv-marker.is-set{ opacity:1; }

/* Destinations. All five share one grid area, and the closed ones are
   laid out but invisible, so the area is always as tall as the
   longest list: changing category never moves anything on the page.
   The open list's heading sits on the first category's baseline. */
.nv-dest{
  grid-column:2; grid-row:1 / -1;
  align-self:start;
  width:100%; max-width:600px;
  padding:0 var(--gut) 0 clamp(32px,4vw,72px);
}
.nv-dest[hidden]{ display:block; visibility:hidden; }
.nv-dest__kicker{
  display:flex; align-items:center; gap:12px;
  margin:0 0 var(--space-4);
  color:var(--ink-soft);
  font-size:.74rem; font-weight:500; letter-spacing:.16em; text-transform:uppercase; line-height:1;
}
.nv-dest__kicker::before{ content:""; width:18px; height:1px; background:var(--gold); flex:none; }
.nv-dest__list{ border-top:1px solid var(--rule); }
.nv-dest__list li{ border-bottom:1px solid var(--rule); }
.nv-dest__list a{
  position:relative;
  display:grid; grid-template-columns:minmax(0,1fr) auto 24px; align-items:center; column-gap:var(--space-3);
  min-height:clamp(50px, 7vh, 64px); padding:8px 0;
  color:var(--ink);
}
.nv-dest__label{ grid-column:1; font-size:var(--nv-dest-size); line-height:1.2; letter-spacing:-.012em; }
.nv-dest__here{ grid-column:2; display:none; color:var(--ink-mute); font-size:.84rem; font-style:italic; letter-spacing:.01em; }
.nv-dest__arrow{
  grid-column:3; justify-self:end;
  color:var(--ink-mute);
  transition:transform .22s var(--e2), color .2s var(--e);
}
/* Hover draws a gold rule along the row's own hairline. */
.nv-dest__list a::after{
  content:""; position:absolute; left:0; right:0; bottom:-1px; height:1px;
  background:var(--gold); transform:scaleX(0); transform-origin:left;
  transition:transform .3s var(--e2);
}
/* Hover only where there is a pointer to hover with: a tap on a phone
   would otherwise leave the rule drawn under the row it touched. */
.nv-dest__list a:focus-visible .nv-dest__arrow{ color:var(--ink); transform:translateX(3px); }
.nv-dest__list a:focus-visible::after{ transform:scaleX(1); }
@media (hover:hover){
  .nv-dest__list a:hover .nv-dest__arrow{ color:var(--ink); transform:translateX(3px); }
  .nv-dest__list a:hover::after{ transform:scaleX(1); }
  .nv-enq__doors a:hover svg{ color:var(--ink); transform:translateX(3px); }
  .nv-enq__contact:hover .nv-enq__value::after{ transform:scaleX(1); }
  .nv-enq__social a:hover{ background:var(--gold); border-color:var(--gold); color:var(--on-gold); }
  .nv-enq__social a:hover .nv-play{ fill:var(--gold); }
  .nv-cta--quiet:hover{ text-decoration-color:var(--gold); }
  .nv-cta--quiet:hover svg{ color:var(--ink); transform:translateX(3px); }
  .nv-enq__close:hover::after{ transform:scaleX(1); }
}
/* The page being read stays a link. Its cue: a short gold rule in the
   gutter beside it, and two quiet words before the arrow. */
.nv-dest__list a[aria-current="page"] .nv-dest__here{ display:inline; }
.nv-dest__list a[aria-current="page"]::before{
  content:""; position:absolute; left:-18px; top:50%; width:2px; height:1.1em; margin-top:-.55em;
  background:var(--gold);
}

/* Foot of the menu: utility on the category side, the admissions
   action and the quieter visit link on the destination side. */
.nv-menu__foot{
  position:relative; z-index:1; flex:none;
  display:grid; grid-template-columns:var(--nv-split) minmax(0,1fr); align-items:center;
  border-top:1px solid var(--rule);
  min-height:84px;
}
.nv-menu__utility{
  display:flex; flex-wrap:wrap; gap:6px var(--space-5);
  padding:var(--space-4) var(--gut) var(--space-4) calc(var(--gut) + var(--nv-num));
  font-size:.92rem;
}
.nv-menu__utility a{ color:var(--ink-soft); }
.nv-menu__utility a:hover, .nv-menu__utility a:focus-visible{ color:var(--ink); text-decoration:underline; text-decoration-color:var(--gold); text-underline-offset:5px; }
.nv-menu__cta{
  display:flex; flex-wrap:wrap; align-items:center; gap:10px var(--space-5);
  padding:var(--space-4) var(--gut) var(--space-4) clamp(32px,4vw,72px);
}
.nv-cta{
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  min-height:46px; padding:11px 18px;
  font-size:.95rem; font-weight:500; white-space:nowrap;
  transition:background .2s var(--e), border-color .2s var(--e), color .2s var(--e);
}
.nv-cta--primary{ background:var(--gold); border:1px solid var(--gold); color:var(--on-gold); }
.nv-cta--primary:hover, .nv-cta--primary:focus-visible{ background:var(--gold-lit); border-color:var(--gold-lit); color:var(--on-gold); }
.nv-cta--quiet{
  min-height:44px; padding:0 2px;
  color:var(--ink); font-weight:400;
  text-decoration:underline; text-decoration-color:var(--rule); text-decoration-thickness:1px; text-underline-offset:6px;
}
.nv-cta--quiet svg{ color:var(--ink-mute); flex:none; transition:transform .22s var(--e2), color .2s var(--e); }
.nv-cta--quiet:focus-visible{ text-decoration-color:var(--gold); }
.nv-cta--quiet:focus-visible svg{ color:var(--ink); transform:translateX(3px); }

/* The opening: the grounds unroll from under the bar and the
   categories come up once, briefly. Nothing is withheld from the
   pointer while it plays, and nothing plays on a category change
   but a short fade of the incoming list. */
.nv-menu.is-open .nv-cat{
  animation:nv-rise .36s var(--e2) both;
  animation-delay:calc(60ms + var(--i) * 30ms);
}
.nv-item{ --i:0; }
.nv-menu.is-open .nv-menu__foot > *{ animation:nv-fade .3s var(--e) .16s both; }
.nv-dest.is-entering{ animation:nv-fade-up .2s var(--e2) both; }
@keyframes nv-rise{ from{ opacity:0; transform:translateY(8px); } to{ opacity:1; transform:none; } }
@keyframes nv-fade-up{ from{ opacity:0; transform:translateY(4px); } to{ opacity:1; transform:none; } }
@keyframes nv-fade{ from{ opacity:0; } to{ opacity:1; } }

/* The page behind is locked by body.is-locked (cirs.css) and Lenis, and
   keeps its place. The trailing cursor ring has nothing to do here. */
body.menu-open .ring, body.menu-closing .ring{ display:none; }

/* ------------------------------------------------------------
   Short windows: the rows tighten before anything scrolls.
   ------------------------------------------------------------ */
@media (max-height:720px) and (min-width:901px){
  .nv-menu__foot{ min-height:72px; }
  .nv-dest__kicker{ margin-bottom:var(--space-3); }
}

/* ------------------------------------------------------------
   Header below 1100px: the sub-line goes, and Home and News keep
   their marks with their names read out rather than shown.
   Enquire and Menu keep their words at every width.
   ------------------------------------------------------------ */
@media (max-width:1099px){
  .nv-brand__sub{ display:none; }
  .nv-brand__name{ font-size:1rem; }
  .nv-header__side{ gap:var(--space-3); }
  :is(.nv-tab--home, .nv-tab--news, .nv-tab--login) .nv-tab__label{
    position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap;
  }
  :is(.nv-tab--home, .nv-tab--news, .nv-tab--login){ min-width:40px; }
  :is(.nv-tab--home, .nv-tab--news, .nv-tab--login)::after{ left:10px; right:10px; }
}

/* ------------------------------------------------------------
   Tablet and phone: one column, an accordion. Each category opens
   its pages directly beneath it on the alternate ivory, with the
   links set on the category label column.
   ------------------------------------------------------------ */
@media (max-width:900px){
  :root{ --nv-hh:64px; --nv-num:2.5rem; --nv-crest:40px; }
  .nv-header{ --nv-pill-inset:8px; }

  .nv-menu::before, .nv-menu::after{ display:none; }
  .nv-menu__stage{ display:block; flex:none; }
  .nv-menu__nav{ display:block; padding:0; }
  .nv-marker{ display:none; }
  .nv-item{ display:block; border-bottom:1px solid var(--rule); }
  .nv-cat{
    position:relative;
    min-height:72px;
    padding:14px var(--gut);
    align-content:center;
  }
  .nv-cat__word{ font-size:clamp(1.75rem, 7vw, 2.5rem); line-height:1.08; }
  /* The marker has no rows to travel between here, so the open
     category carries its own. */
  .nv-cat[aria-expanded="true"]::before{
    content:""; position:absolute; left:calc(var(--gut) - 12px); top:50%;
    width:2px; height:1.4rem; margin-top:-.7rem; background:var(--gold);
  }
  .nv-dest{
    max-width:none;
    padding:4px var(--gut) var(--space-3) calc(var(--gut) + var(--nv-num));
    background:var(--paper-2);
    border-top:1px solid var(--rule);
  }
  .nv-dest[hidden]{ display:none; }
  .nv-dest__kicker{ display:none; }
  .nv-dest__list{ border-top:0; }
  .nv-dest__list li:last-child{ border-bottom:0; }
  .nv-dest__list a{ min-height:48px; padding:6px 0; }
  .nv-dest__label{ font-size:1.15rem; }
  .nv-dest__list a[aria-current="page"]::before{ left:-14px; }

  .nv-menu__foot{ display:flex; flex-direction:column; align-items:stretch; border-top:0; min-height:0; }
  .nv-menu__cta{ order:-1; padding:var(--space-5) var(--gut) var(--space-4); gap:var(--space-2) var(--space-5); }
  .nv-menu__cta .nv-cta--primary{ flex:1 1 220px; }
  .nv-menu__utility{
    display:grid; grid-template-columns:1fr 1fr; gap:10px var(--space-4);
    padding:var(--space-4) var(--gut) calc(var(--space-5) + env(safe-area-inset-bottom,0px));
    border-top:1px solid var(--rule);
  }

  .nv-enq__panel{
    left:0; right:0; width:auto;
    max-height:calc(100dvh - var(--nv-hh));
    padding:var(--space-2) var(--gut) var(--space-5);
    border-inline:0;
  }
  .nv-enq__grid{ grid-template-columns:1fr; gap:var(--space-5); }
}

/* Below 760px the crest and CIRS stand in for the full name, which the
   link still carries for assistive technology: set in the display face
   the full name needs about that much room beside the controls. */
@media (max-width:759px){
  .nv-brand{ gap:8px; }
  :root{ --nv-crest:34px; }
  .nv-brand__txt{ display:block; }
  .nv-brand__name{ display:none; }
  .nv-brand__short{ display:block; }
}
/* Phones: Enquire keeps its word and gives up its mark. */
@media (max-width:699px){
  .nv-enq__btn .nv-tab__icon{ display:none; }
  .nv-header__bar{ gap:var(--space-2); }
  .nv-header__side{ gap:var(--space-1); }
  .nv-tab{ font-size:.9rem; letter-spacing:.04em; }
}
/* The narrowest phones: the Menu mark goes (its word stays), the bar's
   gutter and the icon targets tighten, so Enquire, the lockup and Menu
   keep clear space between them down to 320px. */
@media (max-width:380px){
  .nv-lines{ display:none; }
  .nv-header__bar{ padding-inline:14px; }
  :root{ --nv-crest:30px; }
  .nv-brand__short{ font-size:1.02rem; letter-spacing:.06em; }
  :is(.nv-tab--home, .nv-tab--news, .nv-tab--login){ min-width:36px; }
  .nv-menu__utility{ grid-template-columns:1fr; }
}

/* A page with a fourth control — Student Life's Student Portal, linked
   nowhere else on that page. Its bar sizes each side to what it holds, so
   the extra control cannot push into the lockup; the crest sits centred
   between them rather than on the window's centre line. The portal keeps
   its word from 1280px, the full name from 900px, and below 440px the Home
   mark gives way to it (the crest still leads home). */
.nv-header__bar:has(.nv-tab--login){ grid-template-columns:auto minmax(0,1fr) auto; }
@media (max-width:1279px){
  .nv-tab--login .nv-tab__label{
    position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap;
  }
  .nv-tab--login{ min-width:40px; }
  .nv-tab--login::after{ left:10px; right:10px; }
}
@media (max-width:899px){
  .nv-header__bar:has(.nv-tab--login) .nv-brand{ gap:8px; }
  .nv-header__bar:has(.nv-tab--login) .nv-brand img{ width:34px; }
  .nv-header__bar:has(.nv-tab--login) .nv-brand__txt{ display:block; }
  .nv-header__bar:has(.nv-tab--login) .nv-brand__name{ display:none; }
  .nv-header__bar:has(.nv-tab--login) .nv-brand__short{ display:block; }
}
@media (max-width:440px){
  .nv-header__bar:has(.nv-tab--login) .nv-tab--home{ display:none; }
}

@media print{
  .nv-header, .nv-menu{ display:none !important; }
}

@media (prefers-reduced-motion:reduce){
  .nv-header,.nv-brand,.nv-brand__sub{ transition:none!important; }
  .nv-menu, .nv-menu.is-open, .nv-enq__panel, .nv-enq.is-open .nv-enq__panel{ transition:none !important; clip-path:none !important; transform:none !important; }
  .nv-menu *, .nv-enq *, .nv-tab, .nv-tab *, .nv-marker{ animation:none !important; transition:none !important; }
}
