/* ============================================================
   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; }
