/* ============================================================
   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 contact — 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;
}
.pop.is-open{ opacity:1; visibility:visible; }
.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; }
}
