/* ==========================================================================
   Ideal Higher Secondary School -- design layer
   Loaded after style.css. Holds the motifs that make this site its own:
   the arch, the copper rule, the teal stat band, and the whole motion system.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Motion system
   Everything reveals through one attribute, data-reveal, so a new section
   animates by naming it rather than by getting its own keyframes.
   -------------------------------------------------------------------------- */

/* Scoped to .js: without scripting nothing is hidden in the first place. */
.js [data-reveal] {
  opacity: 0;
  will-change: transform, opacity;
  transition:
    opacity .85s var(--ease-out),
    transform .85s var(--ease-out),
    clip-path .95s var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

.js [data-reveal="up"]    { transform: translate3d(0, 42px, 0); }
.js [data-reveal="down"]  { transform: translate3d(0, -32px, 0); }
.js [data-reveal="left"]  { transform: translate3d(-48px, 0, 0); }
.js [data-reveal="right"] { transform: translate3d(48px, 0, 0); }
.js [data-reveal="zoom"]  { transform: scale(.9); }
.js [data-reveal="arch"]  { transform: translate3d(0, 34px, 0); clip-path: inset(0 0 100% 0 round 999px 999px 22px 22px); }
.js [data-reveal="wipe"]  { clip-path: inset(0 100% 0 0); }
.js [data-reveal="tilt"]  { transform: perspective(1200px) rotateX(12deg) translate3d(0, 40px, 0); transform-origin: top center; }

.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
  clip-path: inset(0 0 0 0 round 0);
}

.js [data-reveal="arch"].is-in { clip-path: inset(0 0 0 0 round 999px 999px 22px 22px); }

/* Stagger: the parent hands each child an increasing delay, so a grid arrives
   as a run rather than all at once. */
[data-stagger] > * { --reveal-delay: calc(var(--i, 0) * 90ms); }

/* Headline that unrolls line by line. Each line sits in its own clipping row. */
.reveal-lines { display: block; }
.reveal-lines .rl-row { display: block; overflow: hidden; }
.js .reveal-lines .rl-row > span {
  display: block;
  transform: translateY(105%);
  transition: transform .9s var(--ease-out);
  transition-delay: calc(var(--i, 0) * 110ms);
}
.reveal-lines.is-in .rl-row > span { transform: translateY(0); }

@keyframes ideal-float   { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-14px); } }
@keyframes ideal-drift   { 0%,100% { transform: translate(0,0) rotate(0deg); } 50% { transform: translate(18px,-22px) rotate(6deg); } }
@keyframes ideal-pulse   { 0%,100% { box-shadow: 0 0 0 0 rgba(192,86,42,.45); } 70% { box-shadow: 0 0 0 16px rgba(192,86,42,0); } }
@keyframes ideal-spin    { to { transform: rotate(360deg); } }
@keyframes ideal-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes ideal-shine   { from { transform: translateX(-160%) skewX(-18deg); } to { transform: translateX(320%) skewX(-18deg); } }

.anim-float { animation: ideal-float 6s ease-in-out infinite; }
.anim-drift { animation: ideal-drift 14s ease-in-out infinite; }
.anim-spin-slow { animation: ideal-spin 26s linear infinite; }

/* Parallax layers get their offset from JS as a custom property, so the browser
   only ever composites a transform. */
[data-parallax] { transform: translate3d(0, var(--par-y, 0px), 0); will-change: transform; }

/* Anyone who has asked their system to stop animation gets the finished state. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal], .reveal-lines .rl-row > span {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
  [data-parallax] { transform: none !important; }
}

/* --------------------------------------------------------------------------
   2. Shared motifs
   -------------------------------------------------------------------------- */

/* The arch: a rounded top on an otherwise square frame. Used on campus photos,
   faculty portraits and album covers, and it is the shape the eye reads as
   "this site" more than any single colour does. */
.arch-frame {
  position: relative;
  border-radius: 999px 999px 24px 24px;
  overflow: hidden;
  isolation: isolate;
  background: var(--cream);
}
.arch-frame > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.1s var(--ease-out);
}
.arch-frame:hover > img { transform: scale(1.07); }
.arch-frame::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.35), inset 0 -70px 90px -50px rgba(11,61,65,.75);
  pointer-events: none;
}

/* Section eyebrow: a copper rule, a gold dot, then the word. */
.ideal-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: .7rem;
  font: 700 .74rem/1 var(--font-body);
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--copper);
  margin-bottom: 1rem;
}
.ideal-eyebrow::before {
  content: "";
  width: 34px;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--copper));
}
.ideal-eyebrow::after {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--gold);
  box-shadow: 0 0 0 4px rgba(221,178,76,.22);
}

.ideal-title {
  font-family: var(--font-head);
  font-weight: 600;
  color: var(--teal-deep);
  line-height: 1.15;
  letter-spacing: -.015em;
  margin: 0 0 1rem;
  font-size: clamp(1.85rem, 3.06vw, 2.85rem);
}
.ideal-title em {
  font-style: normal;
  color: var(--copper);
  position: relative;
  white-space: nowrap;
}
/* An underline that draws itself in once the heading has arrived. */
.ideal-title em::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -.12em;
  height: .16em;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--gold), var(--copper));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .9s .35s var(--ease-out);
}
.js [data-reveal].is-in .ideal-title em::after,
.ideal-title.is-in em::after { transform: scaleX(1); }

.ideal-lead {
  color: var(--muted);
  font-size: 1.03rem;
  line-height: 1.85;
  max-width: 62ch;
}

/* Section shell with a cream ground and a soft copper bloom in one corner. */
.ideal-section {
  position: relative;
  padding: clamp(3.6rem, 7vw, 6.5rem) 0;
  overflow: hidden;
}
.ideal-section.on-cream { background: var(--cream); }
.ideal-section.on-teal { background: var(--teal-deep); color: #eef6f6; }
.ideal-section.on-teal .ideal-title { color: #fff; }
.ideal-section.on-teal .ideal-lead { color: rgba(238,246,246,.78); }
.ideal-section.on-teal .ideal-eyebrow { color: var(--gold); }

.ideal-section .bloom {
  position: absolute;
  width: 46vw;
  max-width: 620px;
  aspect-ratio: 1;
  border-radius: 50%;
  filter: blur(90px);
  opacity: .3;
  pointer-events: none;
  z-index: 0;
}
.ideal-section .bloom.copper { background: var(--copper); }
.ideal-section .bloom.teal   { background: var(--teal); }
.ideal-section .bloom.gold   { background: var(--gold); }
.ideal-section > .container { position: relative; z-index: 1; }

/* --------------------------------------------------------------------------
   3. Buttons -- copper fill with a light sweeping across on hover
   -------------------------------------------------------------------------- */

.btn {
  position: relative;
  overflow: hidden;
  border-radius: 999px;
  font-weight: 700;
  letter-spacing: .01em;
  transition: transform .35s var(--ease-spring), box-shadow .35s var(--ease-out), background-color .3s, color .3s;
}
.btn::after {
  content: "";
  position: absolute;
  top: -60%; bottom: -60%; left: 0;
  width: 42px;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.42), transparent);
  transform: translateX(-160%) skewX(-18deg);
  pointer-events: none;
}
.btn:hover::after { animation: ideal-shine .85s var(--ease-out); }
.btn:hover { transform: translateY(-3px); }
.btn-primary { background: var(--copper); border-color: var(--copper); color: #fff; }
.btn-primary:hover { background: var(--copper-dark); border-color: var(--copper-dark); box-shadow: 0 14px 34px rgba(192,86,42,.36); }
.btn .btn-icon { display: inline-block; transition: transform .35s var(--ease-spring); }
.btn:hover .btn-icon { transform: translateX(5px); }

/* --------------------------------------------------------------------------
   4. Header -- glass bar that condenses once the page moves
   -------------------------------------------------------------------------- */

.site-header {
  transition: padding .4s var(--ease-out), background-color .4s, box-shadow .4s;
}
.site-header.scrolled {
  background: rgba(255,255,255,.88);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
  box-shadow: 0 10px 34px rgba(11,61,65,.13);
}
.site-header.scrolled .brand img { transform: scale(.88); }
.brand img { transition: transform .4s var(--ease-out); }

/* Nav links: a copper rule grows out from the middle. */
.nav-menu .nav-link { position: relative; }
.nav-menu .nav-link::after {
  content: "";
  position: absolute;
  left: 50%; right: 50%; bottom: .35rem;
  height: 2px;
  border-radius: 2px;
  background: var(--copper);
  transition: left .32s var(--ease-out), right .32s var(--ease-out);
}
.nav-menu .nav-link:hover::after,
.nav-menu .nav-link.active::after { left: .8rem; right: .8rem; }

.nav-menu .dropdown-menu {
  border-top: 3px solid var(--copper);
  border-radius: 0 0 18px 18px;
  box-shadow: 0 26px 60px rgba(11,61,65,.20);
}
.nav-menu .dropdown-menu a { transition: background-color .25s, padding-left .25s var(--ease-out), color .25s; }
.nav-menu .dropdown-menu a:hover { background: var(--teal-soft); padding-left: 1.9rem; color: var(--teal-deep); }

/* Top bar: the contact strip plus the enquiry button the school asked for. */
.topbar-btn.is-contact {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--teal-deep);
  font-weight: 800;
}
.topbar-btn.is-contact:hover { background: #fff; border-color: #fff; }

/* --------------------------------------------------------------------------
   5. Scroll progress + back-to-top
   -------------------------------------------------------------------------- */

.scroll-progress {
  position: fixed;
  top: 0; left: 0;
  height: 3px;
  width: 100%;
  transform: scaleX(var(--progress, 0));
  transform-origin: left;
  background: linear-gradient(90deg, var(--copper), var(--gold), var(--teal));
  z-index: 9999;
  pointer-events: none;
}

.back-to-top { transition: opacity .4s, transform .4s var(--ease-spring), background-color .3s; }
.back-to-top:hover { background: var(--copper); transform: translateY(-4px); }

/* --------------------------------------------------------------------------
   6. Stat band -- the teal strip with counting figures
   -------------------------------------------------------------------------- */

.stat-band {
  position: relative;
  background:
    radial-gradient(120% 140% at 12% 0%, #17696f 0%, transparent 55%),
    linear-gradient(120deg, var(--teal-deep), #10474b 60%, #0a3236);
  color: #fff;
  padding: clamp(2.4rem, 4.5vw, 3.6rem) 0;
  overflow: hidden;
}
.stat-band::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(115deg, rgba(255,255,255,.05) 0 1px, transparent 1px 42px);
  pointer-events: none;
}
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1.4rem;
  position: relative;
}
.stat-cell { text-align: center; padding: .4rem 1rem; position: relative; }
.stat-cell + .stat-cell::before {
  content: "";
  position: absolute;
  left: 0; top: 18%; bottom: 18%;
  width: 1px;
  background: linear-gradient(180deg, transparent, rgba(255,255,255,.24), transparent);
}
.stat-ico {
  width: 46px; height: 46px;
  margin: 0 auto .7rem;
  display: grid; place-items: center;
  border-radius: 14px;
  background: rgba(221,178,76,.16);
  color: var(--gold);
  font-size: 1.25rem;
  transition: transform .45s var(--ease-spring), background-color .35s;
}
.stat-cell:hover .stat-ico { transform: translateY(-5px) rotate(-8deg); background: rgba(221,178,76,.3); }
.stat-num {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: clamp(2rem, 3.78vw, 2.9rem);
  line-height: 1;
  color: var(--gold);
  display: block;
}
.stat-label {
  display: block;
  margin-top: .5rem;
  font-size: .82rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: rgba(255,255,255,.76);
}

/* --------------------------------------------------------------------------
   7. Feature / why-choose cards
   -------------------------------------------------------------------------- */

.ideal-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.4rem;
}
.ideal-card {
  position: relative;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 22px;
  padding: 2rem 1.6rem 1.7rem;
  overflow: hidden;
  transition: transform .5s var(--ease-out), box-shadow .5s var(--ease-out), border-color .4s;
}
/* A copper wash climbs the card on hover instead of the card simply lifting. */
.ideal-card::before {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 0;
  background: linear-gradient(180deg, rgba(192,86,42,.06), rgba(192,86,42,.12));
  transition: height .55s var(--ease-out);
  z-index: 0;
}
.ideal-card:hover::before { height: 100%; }
.ideal-card:hover {
  transform: translateY(-9px);
  border-color: rgba(192,86,42,.38);
  box-shadow: 0 26px 52px rgba(11,61,65,.15);
}
.ideal-card > * { position: relative; z-index: 1; }
.ideal-card .card-ico {
  width: 56px; height: 56px;
  display: grid; place-items: center;
  border-radius: 18px 18px 18px 6px;
  background: var(--teal-soft);
  color: var(--teal);
  font-size: 1.5rem;
  margin-bottom: 1.1rem;
  transition: transform .5s var(--ease-spring), background-color .4s, color .4s;
}
.ideal-card:hover .card-ico { background: var(--copper); color: #fff; transform: rotate(-8deg) scale(1.06); }
.ideal-card h4 { font-family: var(--font-head); font-size: 1.16rem; color: var(--teal-deep); margin: 0 0 .5rem; }
.ideal-card p { color: var(--muted); font-size: .95rem; line-height: 1.75; margin: 0; }
.ideal-card .card-no {
  position: absolute;
  top: .8rem; right: 1.1rem;
  font-family: var(--font-head);
  font-size: 2.6rem;
  font-weight: 700;
  color: rgba(20,89,94,.07);
  z-index: 0;
  transition: color .45s;
}
.ideal-card:hover .card-no { color: rgba(192,86,42,.14); }

/* --------------------------------------------------------------------------
   8. Faculty -- portrait cards with the arch frame
   -------------------------------------------------------------------------- */

.faculty-people {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(215px, 1fr));
  gap: 1.5rem;
}
.person-card {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 24px;
  padding: 1.1rem 1.1rem 1.4rem;
  text-align: center;
  transition: transform .5s var(--ease-out), box-shadow .5s var(--ease-out), border-color .4s;
}
.person-card:hover {
  transform: translateY(-8px);
  border-color: rgba(192,86,42,.35);
  box-shadow: 0 24px 48px rgba(11,61,65,.16);
}
.person-photo {
  position: relative;
  aspect-ratio: 3 / 3.6;
  border-radius: 999px 999px 20px 20px;
  overflow: hidden;
  background: linear-gradient(160deg, var(--teal-soft), var(--cream));
  margin-bottom: 1rem;
}
.person-photo img { width: 100%; height: 100%; object-fit: cover; transition: transform 1s var(--ease-out); }
.person-card:hover .person-photo img { transform: scale(1.06); }
/* Initials stand in until a photograph is uploaded in the CMS. */
.person-photo .person-initials {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--font-head);
  font-size: 2.6rem;
  font-weight: 700;
  color: rgba(20,89,94,.4);
  letter-spacing: .04em;
}
.person-photo::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 55%, rgba(11,61,65,.55));
  opacity: 0;
  transition: opacity .45s;
}
.person-card:hover .person-photo::after { opacity: 1; }
.person-name { font-family: var(--font-head); font-size: 1.02rem; color: var(--teal-deep); margin: 0 0 .35rem; }
.person-role {
  display: inline-block;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--copper);
  background: var(--copper-soft);
  border-radius: 999px;
  padding: .22rem .7rem;
}
.person-qual { display: block; margin-top: .5rem; font-size: .82rem; color: var(--muted); }

/* The compact name list, for groups with many members and no portraits. */
.staff-name { transition: transform .35s var(--ease-out), background-color .35s, color .35s, border-color .35s; }
.staff-name:hover { transform: translateX(5px); background: var(--copper-soft); color: var(--copper-dark); border-color: rgba(192,86,42,.3); }

/* --------------------------------------------------------------------------
   9. Gallery albums
   -------------------------------------------------------------------------- */

.album-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(265px, 1fr));
  gap: 1.5rem;
}
.album-card {
  position: relative;
  border-radius: 24px;
  overflow: hidden;
  background: var(--teal-deep);
  cursor: pointer;
  border: 0;
  padding: 0;
  text-align: left;
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3.2;
  transition: transform .55s var(--ease-out), box-shadow .55s var(--ease-out);
}
.album-card:hover { transform: translateY(-8px); box-shadow: 0 28px 56px rgba(11,61,65,.28); }
.album-card img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 1.1s var(--ease-out);
}
.album-card:hover img { transform: scale(1.09); }
.album-card::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(11,61,65,0) 30%, rgba(11,61,65,.88));
}
.album-meta { position: absolute; left: 0; right: 0; bottom: 0; padding: 1.2rem; z-index: 2; color: #fff; }
.album-meta h4 { font-family: var(--font-head); font-size: 1.1rem; margin: 0 0 .3rem; }
.album-folder {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: .72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--gold);
}
.album-count {
  position: absolute;
  top: .9rem; right: .9rem;
  z-index: 2;
  background: rgba(255,255,255,.92);
  color: var(--teal-deep);
  border-radius: 999px;
  padding: .25rem .7rem;
  font-size: .74rem;
  font-weight: 800;
  transform: translateY(-8px);
  opacity: 0;
  transition: opacity .4s, transform .4s var(--ease-spring);
}
.album-card:hover .album-count { opacity: 1; transform: none; }

/* --------------------------------------------------------------------------
   10. Notice ticker + marquee strip
   -------------------------------------------------------------------------- */

.notice-pulse { animation: ideal-pulse 2.2s infinite; }

.brand-marquee {
  overflow: hidden;
  background: var(--teal-deep);
  color: rgba(255,255,255,.9);
  padding: .85rem 0;
  border-top: 1px solid rgba(255,255,255,.09);
  border-bottom: 1px solid rgba(255,255,255,.09);
}
.brand-marquee .mq-track {
  display: flex;
  width: max-content;
  gap: 3rem;
  animation: ideal-marquee 32s linear infinite;
}
.brand-marquee:hover .mq-track { animation-play-state: paused; }
.brand-marquee .mq-item {
  display: inline-flex;
  align-items: center;
  gap: .8rem;
  font-family: var(--font-head);
  font-size: 1.05rem;
  white-space: nowrap;
}
.brand-marquee .mq-item::before { content: "\2726"; color: var(--gold); }

/* --------------------------------------------------------------------------
   11. Lab / facility tiles with a reserved image slot
   -------------------------------------------------------------------------- */

.lab-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.6rem;
}
.lab-tile {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 24px;
  overflow: hidden;
  transition: transform .5s var(--ease-out), box-shadow .5s var(--ease-out);
}
.lab-tile:hover { transform: translateY(-8px); box-shadow: 0 26px 52px rgba(11,61,65,.16); }
.lab-shot { position: relative; aspect-ratio: 16 / 10; background: var(--cream); overflow: hidden; }
.lab-shot img { width: 100%; height: 100%; object-fit: cover; transition: transform 1s var(--ease-out); }
.lab-tile:hover .lab-shot img { transform: scale(1.07); }
/* Until a photograph is added in the CMS the slot says so rather than showing a broken frame. */
.lab-shot .shot-pending {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  align-content: center;
  gap: .4rem;
  text-align: center;
  color: var(--teal);
  background:
    repeating-linear-gradient(45deg, rgba(20,89,94,.045) 0 12px, transparent 12px 24px),
    var(--cream);
}
.lab-shot .shot-pending strong { font-family: var(--font-head); font-size: 1rem; display: block; }
.lab-shot .shot-pending span { font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.lab-body { padding: 1.4rem 1.4rem 1.6rem; }
.lab-body h4 { font-family: var(--font-head); color: var(--teal-deep); margin: 0 0 .5rem; font-size: 1.15rem; }
.lab-body p { color: var(--muted); font-size: .94rem; line-height: 1.75; margin: 0 0 .9rem; }
.lab-stats { display: flex; flex-wrap: wrap; gap: .5rem; }
.lab-stat {
  background: var(--teal-soft);
  color: var(--teal-deep);
  border-radius: 999px;
  padding: .3rem .8rem;
  font-size: .78rem;
  font-weight: 700;
}
.lab-stat b { color: var(--copper); }

/* --------------------------------------------------------------------------
   12. Contact -- map beside the form
   -------------------------------------------------------------------------- */

.contact-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.6rem;
  align-items: stretch;
}
@media (max-width: 900px) { .contact-split { grid-template-columns: 1fr; } }

.map-frame {
  position: relative;
  border-radius: 24px;
  overflow: hidden;
  min-height: 420px;
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  background: var(--cream);
}
.map-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

.contact-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 1.6rem; }
.contact-tile {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 18px;
  padding: 1.1rem;
  display: flex;
  gap: .9rem;
  align-items: flex-start;
  transition: transform .45s var(--ease-out), border-color .35s, box-shadow .45s;
}
.contact-tile:hover { transform: translateY(-5px); border-color: rgba(192,86,42,.35); box-shadow: 0 18px 38px rgba(11,61,65,.13); }
.contact-tile .ct-ico {
  flex: 0 0 auto;
  width: 42px; height: 42px;
  display: grid; place-items: center;
  border-radius: 13px;
  background: var(--copper-soft);
  color: var(--copper);
  font-size: 1.05rem;
}
.contact-tile h5 { margin: 0 0 .2rem; font-size: .78rem; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); font-weight: 700; }
.contact-tile p { margin: 0; font-size: .95rem; color: var(--teal-deep); font-weight: 600; line-height: 1.6; }
.contact-tile a { color: inherit; }
.contact-tile a:hover { color: var(--copper); }

/* --------------------------------------------------------------------------
   13. Page loader
   -------------------------------------------------------------------------- */

.page-loader {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: grid;
  place-items: center;
  background: var(--cream);
  transition: opacity .6s var(--ease-out), visibility .6s;
}
.page-loader .loader-mark { position: relative; display: grid; place-items: center; }
.page-loader .loader-mark img { width: 82px; height: auto; animation: ideal-float 2.4s ease-in-out infinite; }
.page-loader .loader-mark::after {
  content: "";
  position: absolute;
  width: 120px; height: 120px;
  border-radius: 50%;
  border: 2px solid rgba(192,86,42,.2);
  border-top-color: var(--copper);
  animation: ideal-spin 1s linear infinite;
}

/* --------------------------------------------------------------------------
   14. Small screens
   -------------------------------------------------------------------------- */

@media (max-width: 640px) {
  .stat-cell + .stat-cell::before { display: none; }
  .faculty-people { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
  .album-grid { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   15. Page banner, faculty headings and the album folder chip
   -------------------------------------------------------------------------- */

.page-hero { padding: clamp(3rem, 6vw, 5rem) 0 clamp(2.4rem, 5vw, 4rem); }
.page-hero .ideal-title { margin-bottom: .8rem; }

.faculty-group-head { max-width: 68ch; margin-bottom: 2.2rem; }
.faculty-empty {
  border: 1px dashed rgba(20,89,94,.3);
  border-radius: 18px;
  padding: 1.4rem;
  color: var(--muted);
  background: rgba(255,255,255,.6);
  margin: 0;
}

.staff-name-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: .75rem;
}
/* style.css carries a .staff-name of its own from another theme: a flex row
   with a tick drawn in a pseudo-element. The flex put the subject beside the
   name rather than under it, and the tick's colours are scoped to a section
   class this page never uses, so it came out white on white. Both undone. */
.staff-name {
  display: block;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: .8rem 1rem;
  font-weight: 600;
  color: var(--teal-deep);
}
.staff-name::before { content: none; }
.staff-name small {
  display: block;
  font-weight: 500;
  font-size: .78rem;
  color: var(--muted);
  margin-top: .15rem;
}

/* The folder each album's pictures live in, shown on the card so the CMS
   listing and the public page name the same thing. */
.pg-folder {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  font-size: .72rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--copper);
  margin-bottom: .2rem;
}

/* --------------------------------------------------------------------------
   16. Page body components
   The vocabulary the stored page bodies are written in: heading blocks, prose,
   checked lists, numbered steps, tables, split panels, quotes and CTA strips.
   -------------------------------------------------------------------------- */

.ideal-head { max-width: 70ch; margin-bottom: 2.4rem; }
.ideal-head.is-centred { margin-left: auto; margin-right: auto; text-align: center; }
.ideal-head.is-centred .ideal-lead { margin-left: auto; margin-right: auto; }
.ideal-head .ideal-title { margin-bottom: .7rem; }

.ideal-prose { max-width: 70ch; }
.ideal-prose p {
  color: var(--muted);
  font-size: 1.02rem;
  line-height: 1.9;
  margin: 0 0 1.05rem;
}
.on-teal .ideal-prose p { color: rgba(238,246,246,.82); }

/* Checked list: the tick sits in a copper roundel that fills on hover. */
.ideal-checks { list-style: none; margin: 1.4rem 0 0; padding: 0; display: grid; gap: .7rem; }
.ideal-checks li {
  position: relative;
  padding: .75rem 1rem .75rem 3rem;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 14px;
  color: var(--ink);
  font-size: .97rem;
  line-height: 1.7;
  transition: transform .4s var(--ease-out), border-color .35s, box-shadow .4s;
}
.ideal-checks li::before {
  content: "\2713";
  position: absolute;
  left: .85rem; top: .8rem;
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--copper-soft);
  color: var(--copper);
  font-size: .72rem;
  font-weight: 900;
  transition: background-color .35s, color .35s, transform .4s var(--ease-spring);
}
.ideal-checks li:hover {
  transform: translateX(5px);
  border-color: rgba(192,86,42,.35);
  box-shadow: 0 14px 30px rgba(11,61,65,.10);
}
.ideal-checks li:hover::before { background: var(--copper); color: #fff; transform: rotate(-10deg) scale(1.08); }
.on-cream .ideal-checks li { background: #fff; }
.on-teal .ideal-checks li { background: rgba(255,255,255,.06); border-color: rgba(255,255,255,.16); color: #eef6f6; }

/* Numbered steps down a copper rail. */
.ideal-steps { list-style: none; counter-reset: step; margin: 1.6rem 0 0; padding: 0; position: relative; }
.ideal-steps::before {
  content: "";
  position: absolute;
  left: 21px; top: .6rem; bottom: .6rem;
  width: 2px;
  background: linear-gradient(180deg, var(--copper), var(--gold), transparent);
  opacity: .35;
}
.ideal-steps li {
  counter-increment: step;
  position: relative;
  padding: 0 0 1.7rem 3.9rem;
}
.ideal-steps li::before {
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0; top: 0;
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--copper);
  color: var(--copper);
  font-family: var(--font-head);
  font-weight: 700;
  font-size: .92rem;
  transition: background-color .4s, color .4s, transform .45s var(--ease-spring);
}
.ideal-steps li:hover::before { background: var(--copper); color: #fff; transform: scale(1.08); }
.ideal-steps li:last-child { padding-bottom: 0; }
.ideal-steps h4 { font-family: var(--font-head); color: var(--teal-deep); margin: .5rem 0 .35rem; font-size: 1.1rem; }
.ideal-steps p { margin: 0; color: var(--muted); line-height: 1.8; font-size: .97rem; }
.on-teal .ideal-steps li::before { background: var(--teal-deep); }
.on-teal .ideal-steps h4 { color: #fff; }
.on-teal .ideal-steps p { color: rgba(238,246,246,.78); }

/* Tables. On a phone each row becomes its own card and the column heading is
   printed beside the value from the data-label attribute. */
.ideal-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 20px;
  box-shadow: var(--shadow-sm);
  margin-bottom: 1.4rem;
}
.table-caption {
  margin: 0;
  padding: 1rem 1.2rem 0;
  font-weight: 700;
  color: var(--teal-deep);
}
.ideal-table { width: 100%; border-collapse: collapse; min-width: 560px; font-size: .94rem; }
.ideal-table thead th {
  background: var(--teal-deep);
  color: #fff;
  text-align: left;
  font-weight: 700;
  font-size: .8rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: .85rem 1rem;
  white-space: nowrap;
}
.ideal-table tbody th,
.ideal-table tbody td {
  padding: .8rem 1rem;
  border-top: 1px solid var(--border);
  text-align: left;
  vertical-align: top;
  line-height: 1.6;
}
.ideal-table tbody th { font-weight: 700; color: var(--teal-deep); }
.ideal-table tbody td { color: var(--muted); }
.ideal-table tbody tr { transition: background-color .3s; }
.ideal-table tbody tr:nth-child(even) { background: var(--cream); }
.ideal-table tbody tr:hover { background: var(--copper-soft); }

@media (max-width: 720px) {
  .ideal-table { min-width: 0; }
  .ideal-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .ideal-table tbody tr {
    display: block;
    border: 1px solid var(--border);
    border-radius: 14px;
    margin: .8rem;
    background: #fff;
  }
  .ideal-table tbody th,
  .ideal-table tbody td { display: block; border-top: 0; padding: .5rem .9rem; }
  .ideal-table tbody th { background: var(--teal-soft); border-radius: 13px 13px 0 0; }
  .ideal-table tbody td::before {
    content: attr(data-label);
    display: block;
    font-size: .7rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--copper);
    font-weight: 700;
    margin-bottom: .15rem;
  }
}

/* Picture beside copy. */
.ideal-split {
  display: grid;
  grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr);
  gap: clamp(1.6rem, 4vw, 3.2rem);
  align-items: center;
}
.ideal-split.is-flipped { grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); }
@media (max-width: 860px) { .ideal-split, .ideal-split.is-flipped { grid-template-columns: 1fr; } }

.split-figure { position: relative; margin: 0; }
.split-figure .arch-frame { aspect-ratio: 4 / 4.4; box-shadow: var(--shadow-lg); }
.split-badge {
  position: absolute;
  right: -12px; bottom: 26px;
  background: var(--copper);
  color: #fff;
  border-radius: 18px;
  padding: .9rem 1.2rem;
  text-align: center;
  box-shadow: 0 18px 40px rgba(192,86,42,.4);
  animation: ideal-float 5.5s ease-in-out infinite;
}
.split-badge strong { display: block; font-family: var(--font-head); font-size: 1.5rem; line-height: 1; }
.split-badge span { display: block; font-size: .7rem; letter-spacing: .1em; text-transform: uppercase; opacity: .9; margin-top: .25rem; }
.split-copy .ideal-head { margin-bottom: 1.2rem; }
@media (max-width: 520px) { .split-badge { right: 10px; bottom: 12px; padding: .7rem .9rem; } }

/* Pull quote. */
.ideal-quote {
  position: relative;
  margin: 0 auto;
  max-width: 74ch;
  background: #fff;
  border: 1px solid var(--border);
  border-left: 4px solid var(--copper);
  border-radius: 8px 22px 22px 8px;
  padding: 2.4rem 2rem 1.8rem;
  box-shadow: var(--shadow-sm);
}
.ideal-quote::before {
  content: "\201C";
  position: absolute;
  top: -.15em; left: .5rem;
  font-family: var(--font-head);
  font-size: 5rem;
  line-height: 1;
  color: rgba(192,86,42,.18);
}
.ideal-quote p {
  margin: 0 0 1.2rem;
  font-family: var(--font-head);
  font-size: clamp(1.02rem, 1.53vw, 1.22rem);
  line-height: 1.8;
  color: var(--teal-deep);
}
.ideal-quote footer { display: flex; flex-direction: column; gap: .1rem; }
.ideal-quote footer strong { color: var(--copper); font-size: 1rem; }
.ideal-quote footer span { color: var(--muted); font-size: .85rem; }

/* Call-to-action strip. */
.ideal-cta {
  display: flex;
  flex-wrap: wrap;
  gap: 1.4rem;
  align-items: center;
  justify-content: space-between;
  background:
    radial-gradient(120% 160% at 100% 0%, #17696f 0%, transparent 60%),
    linear-gradient(120deg, var(--teal-deep), #0e4a4f);
  color: #fff;
  border-radius: 26px;
  padding: clamp(1.7rem, 4vw, 2.8rem);
  box-shadow: 0 26px 60px rgba(11,61,65,.25);
  overflow: hidden;
  position: relative;
}
.ideal-cta::after {
  content: "";
  position: absolute;
  right: -60px; top: -60px;
  width: 220px; height: 220px;
  border-radius: 50%;
  border: 26px solid rgba(221,178,76,.14);
  pointer-events: none;
}
.ideal-cta h3 { font-family: var(--font-head); font-size: clamp(1.25rem, 2.16vw, 1.75rem); margin: 0 0 .5rem; }
.ideal-cta p { margin: 0; color: rgba(238,246,246,.82); max-width: 58ch; line-height: 1.8; }
.ideal-cta > div:first-child { position: relative; z-index: 1; flex: 1 1 320px; }
.cta-actions { display: flex; flex-wrap: wrap; gap: .7rem; position: relative; z-index: 1; }

.teaser-actions { display: flex; flex-wrap: wrap; gap: .8rem; justify-content: center; }

/* Form helpers, shared with the CMS screens. */
.hint { display: block; margin-top: .3rem; font-size: .78rem; color: var(--muted); }
h3.sub { margin: 1.6rem 0 .4rem; font-size: 1rem; color: var(--teal-deep); }

/* A dropdown with many items gets two columns instead of one very long list. */
.nav-menu .dropdown-menu.is-wide { min-width: 380px; columns: 2; column-gap: .4rem; }
.nav-menu .dropdown-menu.is-wide a { break-inside: avoid; }
@media (max-width: 920px) { .nav-menu .dropdown-menu.is-wide { min-width: 0; columns: 1; } }

/* --------------------------------------------------------------------------
   17. Layout corrections
   -------------------------------------------------------------------------- */

/* The crest block was taking whatever width its two lines needed and pushing the
   navigation into a wrap. Cap it and let the lines break instead. */
.brand { max-width: 42%; }
.brand-text { min-width: 0; }
.brand-text strong { font-size: clamp(1rem, 1.35vw, 1.22rem); line-height: 1.25; }
.brand-text span { font-size: 0.5938rem; letter-spacing: .07em; line-height: 1.45; }
@media (max-width: 1120px) { .brand-text span { display: none; } }
@media (max-width: 920px)  { .brand { max-width: none; } .brand-text span { display: block; } }

.nav-menu .nav-link { white-space: nowrap; }

/* Four cards were laying out as three plus a stray. Let the row take as many as fit. */
.card-grid { grid-template-columns: repeat(auto-fit, minmax(228px, 1fr)); }

/* The secondary hero button was a translucent wash, which disappears against a
   photograph. On the hero it becomes a frosted panel with its own border. */
.hero .btn-light {
  background: rgba(255,255,255,.92);
  color: var(--teal-deep);
  border: 1px solid rgba(255,255,255,.9);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.hero .btn-light:hover { background: #fff; box-shadow: 0 14px 34px rgba(11,61,65,.3); }

/* Card icons: the emoji sat small and off-centre inside its rounded tile. */
.info-card .card-icon,
.ideal-card .card-ico {
  font-size: 1.6rem;
  line-height: 1;
  font-family:
    "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Segoe UI Symbol", sans-serif;
}
.stat-ico { font-size: 1.35rem; line-height: 1;
  font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Segoe UI Symbol", sans-serif; }

/* The heading underline is drawn on a nowrap span; on a narrow screen that span
   would push the line off the edge, so let it break there. */
@media (max-width: 560px) { .ideal-title em { white-space: normal; } }

/* The folder name sits on its own line above the date on an album card. */
.pg-folder { display: block; }
.pg-card-body h3 { margin-bottom: .35rem; }

/* A long email must wrap inside its tile rather than run past the edge. */
.contact-tile p { overflow-wrap: anywhere; }

/* Without scripting the underline never gets its .is-in cue, so draw it outright. */
html:not(.js) .ideal-title em::after { transform: scaleX(1); }
html:not(.js) .page-loader { display: none; }

/* --------------------------------------------------------------------------
   18. Restraint pass
   Drawn icons in place of emoji, and the decoration turned down: no gradient
   wash behind every section, no ghost numerals, and the heading accent kept for
   the few places it earns.
   -------------------------------------------------------------------------- */

/* Line icons. One weight, sized to the tile, colour inherited. */
.card-ico svg,
.card-icon svg,
.stat-ico svg,
.ct-ico svg {
  width: 1.45rem;
  height: 1.45rem;
  display: block;
  stroke: currentColor;
  fill: none;
}
.stat-ico svg { width: 1.3rem; height: 1.3rem; }

/* Quieter icon tiles: a soft square rather than a coloured badge. */
.ideal-card .card-ico,
.info-card .card-icon {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--teal-soft);
  color: var(--teal);
  margin-bottom: .95rem;
  transition: background-color .35s, color .35s;
}
/* No more rotate-and-grow on hover; the colour change is enough. */
.ideal-card:hover .card-ico,
.info-card:hover .card-icon {
  background: var(--copper-soft);
  color: var(--copper);
  transform: none;
}
.stat-cell:hover .stat-ico { transform: none; background: rgba(221,178,76,.24); }

/* Cards sit still and simply lift. The climbing copper wash is gone. */
.ideal-card::before { display: none; }
.ideal-card {
  border-radius: 16px;
  padding: 1.6rem 1.5rem 1.5rem;
}
.ideal-card:hover {
  transform: translateY(-4px);
  border-color: rgba(20,89,94,.28);
  box-shadow: 0 14px 30px rgba(11,61,65,.10);
}

/* The heading accent survives only where it is asked for by name. */
.ideal-title em::after { height: .12em; background: var(--gold); }

/* Softer section rhythm: less padding, no oversized headings. */
.ideal-title { font-size: clamp(1.6rem, 2.34vw, 2.15rem); font-weight: 600; }
.ideal-section { padding: clamp(3rem, 5.5vw, 5rem) 0; }
.ideal-eyebrow { letter-spacing: .16em; }
.ideal-eyebrow::before { width: 26px; }

/* Checked list: a plain tick, no roundel, no slide on hover. */
.ideal-checks li {
  border-radius: 10px;
  padding: .7rem 1rem .7rem 2.6rem;
}
.ideal-checks li::before {
  background: none;
  color: var(--copper);
  width: auto;
  height: auto;
  left: 1rem;
  top: .72rem;
  font-size: .95rem;
}
.ideal-checks li:hover {
  transform: none;
  border-color: rgba(20,89,94,.28);
  box-shadow: none;
  background: var(--surface-soft);
}
.ideal-checks li:hover::before { background: none; color: var(--copper); transform: none; }

/* Steps: smaller markers, no growth on hover. */
.ideal-steps li::before { width: 38px; height: 38px; font-size: .85rem; }
.ideal-steps li:hover::before { background: #fff; color: var(--copper); transform: none; }
.ideal-steps li { padding-left: 3.4rem; }
.on-teal .ideal-steps li:hover::before { background: var(--teal-deep); }

/* People and album cards lift a little less. */
.person-card:hover,
.lab-tile:hover,
.contact-tile:hover { transform: translateY(-4px); box-shadow: 0 14px 30px rgba(11,61,65,.10); }
.album-card:hover { transform: translateY(-4px); }

/* Buttons keep the copper but lose the sweeping highlight. */
.btn::after { display: none; }
.btn:hover { transform: translateY(-2px); }

/* The call-to-action strip: flat teal, no ring. */
.ideal-cta {
  background: var(--teal-deep);
  border-radius: 18px;
  box-shadow: none;
}
.ideal-cta::after { display: none; }

/* The badge on a split picture sits still. */
.split-badge { animation: none; border-radius: 12px; }
.split-figure .arch-frame { box-shadow: var(--shadow-sm); }

/* Quote: a plain rule rather than a giant floating quotation mark. */
.ideal-quote { border-radius: 4px 14px 14px 4px; padding: 1.8rem 1.8rem 1.5rem; }
.ideal-quote::before { display: none; }

/* --------------------------------------------------------------------------
   19. Hero: show the photograph
   The slider used to lay two full-bleed dark gradients over every slide to keep
   white type readable. That dimmed the school's own photographs, which are the
   point of the section. The scrim is gone; the type carries its own weight
   instead, so the picture is shown as taken.
   -------------------------------------------------------------------------- */

.hero-slide.has-copy::before { background: none; }

/* Readability now comes from the letterforms themselves rather than from
   darkening what is behind them: a tight shadow close in, and a wider soft one
   to lift the type off a busy background. */
.hero-copy h2 {
  text-shadow:
    0 1px 2px rgba(3, 10, 11, .55),
    0 2px 18px rgba(3, 10, 11, .45);
}

.hero-slide.has-copy .hero-copy p {
  color: #fff;
  text-shadow:
    0 1px 2px rgba(3, 10, 11, .65),
    0 2px 14px rgba(3, 10, 11, .5);
}

/* The badge was legible only against the scrim, so it becomes a panel of its own. */
.hero-badge {
  background: rgba(11, 61, 65, .55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  border: 1px solid rgba(255, 255, 255, .3);
  text-shadow: 0 1px 2px rgba(3, 10, 11, .5);
}

/* Slide dots and arrows sat on the darkest part of the old gradient. */
.slider-dot {
  background: rgba(255, 255, 255, .5);
  box-shadow: 0 1px 3px rgba(3, 10, 11, .5);
}
.slider-arrow {
  background: rgba(11, 61, 65, .45);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  border-color: rgba(255, 255, 255, .35);
  color: #fff;
}
.slider-arrow:hover { background: var(--copper); border-color: var(--copper); }

/* --------------------------------------------------------------------------
   20. Footer credit line
   -------------------------------------------------------------------------- */

.footer-bottom .container { text-align: center; }
.footer-bottom .copyline { margin: 0; }
.footer-bottom .creditline {
  margin: .45rem 0 0;
  font-size: .82rem;
  letter-spacing: .02em;
  color: rgba(255, 255, 255, .58);
}
.footer-bottom .creditline a {
  color: rgba(255, 255, 255, .72);
  border-bottom: 1px solid rgba(255, 255, 255, .22);
  padding-bottom: 1px;
  transition: color .25s, border-color .25s;
}
.footer-bottom .creditline a:hover {
  color: var(--gold);
  border-bottom-color: var(--gold);
}

/* --------------------------------------------------------------------------
   21. Portraits beside copy
   The picture in a split section was running to 593x653 -- wide enough to
   compete with the text rather than sit beside it. It now takes a narrower
   column and is capped, so the words lead and the photograph supports them.
   -------------------------------------------------------------------------- */

.ideal-split { grid-template-columns: minmax(0, .62fr) minmax(0, 1.38fr); }
.ideal-split.is-flipped { grid-template-columns: minmax(0, 1.38fr) minmax(0, .62fr); }

.split-figure {
  max-width: 340px;
  width: 100%;
  margin-inline: auto;
}

/* A portrait rather than the near-square it was. */
.split-figure .arch-frame { aspect-ratio: 3 / 3.5; }

/* The badge is sized to the smaller frame and tucked inside its edge, so it no
   longer hangs off a narrow picture. */
.split-badge {
  right: -10px;
  bottom: 18px;
  padding: .7rem 1rem;
}
.split-badge strong { font-size: 1.25rem; }
.split-badge span { font-size: .64rem; }

@media (max-width: 860px) {
  /* These repeat the stacking rule from section 12. The column widths above
     are declared later in the file at the same specificity, so without this
     they would win over the earlier media query and the layout would stay in
     two columns on a phone. */
  .ideal-split,
  .ideal-split.is-flipped { grid-template-columns: 1fr; }
  .split-figure { max-width: 300px; }
}

/* --- the two home-page panels ------------------------------------------- */

.image-composition { min-height: 470px; }
.image-composition .image-main { width: 80%; height: 420px; }
.image-composition .image-small { width: 42%; height: 200px; border-width: 7px; }

.principal-wrap:not(.stacked) .principal-photo { padding: 32px 0 32px 32px; }
.principal-wrap:not(.stacked) .principal-photo img { max-width: 290px; margin-inline: auto; }

@media (max-width: 860px) {
  .image-composition { min-height: 0; }
  .image-composition .image-main { width: 100%; height: 300px; }
  .image-composition .image-small { position: static; width: 100%; height: 220px; margin-top: 1rem; }
}

/* The ch unit is measured on the "0" glyph, and Plus Jakarta Sans has a wide
   one: 70ch came out at 845px, roughly 105 characters a line. A pixel cap is
   predictable and lands the measure where it is comfortable to read. */
.ideal-prose { max-width: 640px; }
.ideal-lead  { max-width: 660px; }
.ideal-head.is-centred .ideal-lead { max-width: 700px; }

/* --------------------------------------------------------------------------
   22. Page banners
   The flat teal band behind every page title becomes a photograph of the
   school, with a gradient over it so white type still reads. The gradient is
   heaviest on the left, where the words sit, and thins out to the right so the
   picture is actually visible.
   -------------------------------------------------------------------------- */

.page-hero.has-shot { background: var(--teal-deep); }

/* The photograph sits on its own layer behind the words. */
.page-hero .hero-shot {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center 38%;
  background-repeat: no-repeat;
  z-index: 0;
}

/* A light wash only: the photograph is meant to be seen, so the type carries
   its own contrast (below) rather than the picture being dimmed to suit it.
   Written as rgba() rather than the newer rgb(a b c / d%) so that a browser
   which does not understand that syntax keeps the gradient instead of
   dropping the whole declaration. */
.page-hero .hero-shot::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(95deg,
    rgba(11, 61, 65, 0) 0%,
    rgba(6, 77, 83, .24) 38%,
    rgba(11, 61, 65, .52) 70%,
    rgba(11, 61, 65, .38) 100%);
}

/* A little more room now the sentence under the title has gone. */
.page-hero { padding: clamp(3.4rem, 7vw, 5.6rem) 0 clamp(3rem, 6vw, 4.6rem); }
.page-hero .ideal-title { margin-bottom: 0; }

/* On a phone the picture is cropped hard, so the type needs a heavier ground. */
/* On a phone the crop is tight and the title sits over the middle of the
   picture, so it gets a little more ground under it -- still far lighter than
   the old scrim. */
@media (max-width: 720px) {
  .page-hero .hero-shot::after {
    background: linear-gradient(180deg, rgba(11, 61, 65, .30), rgba(11, 61, 65, .55));
  }
}

/* With the wash that light, the title has to hold its own against whatever is
   behind it. Three shadows do that: a tight one for the edge of each letter, a
   mid one for separation, and a wide soft pool that darkens the picture only
   immediately around the words. */
.page-hero .ideal-title {
  color: #fff;
  text-shadow:
    0 1px 2px rgba(3, 12, 13, .62),
    0 4px 18px rgba(3, 12, 13, .58),
    0 0 64px rgba(3, 12, 13, .55);
}


/* --------------------------------------------------------------------------
   23. The admission and enquiry forms
   The form used to sit outside any section and run the full width of the page,
   which put single-line fields across 1100px. It now sits in a section of its
   own, centred and capped.
   -------------------------------------------------------------------------- */

.admission-form,
.ideal-section .contact-form {
  max-width: 660px;
  margin-inline: auto;
  width: 100%;
}

/* Its own heading is in the section above it, so the one inside is redundant. */
.ideal-section .admission-form > .eyebrow,
.ideal-section .admission-form > h2 { display: none; }

.ideal-section .admission-form { padding: 2rem; border-radius: 18px; }

/* Two columns is right at this width; on a narrow screen it stacks. */
.admission-form .form-grid { gap: 1rem 1.1rem; }
@media (max-width: 620px) {
  .admission-form .form-grid { grid-template-columns: 1fr; }
  .ideal-section .admission-form { padding: 1.3rem; }
}

/* The contact page keeps its side-by-side layout, so it is not capped there. */
.contact-split .contact-form { max-width: none; }

/* --------------------------------------------------------------------------
   24. Footer typography
   The footer inherited the 16.5px body size with its 1.75 line height, which
   is right for reading a page and too heavy for what the footer actually is:
   a set of links, two phone numbers, an address. Everything is set a step
   down and the lines pulled closer, so the four columns read as a reference
   strip under the page rather than a second helping of copy.
   -------------------------------------------------------------------------- */

.site-footer {
  font-size: .875rem;
  line-height: 1.6;
}

.site-footer .footer-brand img { height: 62px; max-width: 56px; }
.site-footer .footer-brand strong { font-size: 1.06rem; }
.site-footer .footer-brand span { font-size: .66rem; }
.site-footer .footer-brand { gap: 11px; margin-bottom: 16px; }

.site-footer .footer-title {
  font-size: 1rem;
  letter-spacing: .01em;
  margin-bottom: 15px;
}

.site-footer .footer-links { gap: 8px; }
.site-footer .footer-social { gap: 9px; margin-top: 18px; }
.site-footer .social-link { width: 36px; height: 36px; border-radius: 10px; }
.site-footer .footer-why { font-size: .82rem; margin-top: 16px; }

/* The contact column carries the smallest type in the footer: it is looked up,
   not read through. The pin keeps the address hanging under its own icon. */
.site-footer #footer-contact {
  font-size: .82rem;
  gap: 9px;
}

.site-footer .footer-address { line-height: 1.5; }

.footer-bottom { font-size: .78rem; }
.footer-bottom .creditline { font-size: .74rem; }

/* --------------------------------------------------------------------------
   25. Album card titles
   The card title took the site's display serif, which is right for a section
   heading and fussy at card size -- an album name is a label, read at a
   glance, not a piece of set copy. It moves to the body sans at a plain
   weight, so the picture above it stays the loudest thing on the card.
   -------------------------------------------------------------------------- */

.pg-card-body h3 {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: 0;
  line-height: 1.35;
}

/* --------------------------------------------------------------------------
   26. The navigation row on a narrow laptop
   Brand, menu and the Apply Now button share one row that cannot wrap. Between
   the point where the button is hidden (1080px) and a comfortable desktop the
   three together were wider than the container, and the button was pushed past
   the right edge -- where the page's overflow clip cut its first letter off.
   The menu gives up a little of its padding through that band instead.
   -------------------------------------------------------------------------- */

@media (min-width: 1081px) and (max-width: 1400px) {
  .nav-menu { gap: 5px; }
  .nav-link { padding-inline: 7px; }
  .nav-cta { margin-left: 2px; }
}

/* Whatever the width, the button keeps its own size and the menu is the part
   that yields, so the row can never push it out of the container. */
.nav-menu { min-width: 0; flex-shrink: 1; }
.nav-cta { flex: 0 0 auto; }

/* --------------------------------------------------------------------------
   27. The link on from a shortened section
   A section that shows only part of a list ends with one centred button to the
   page holding the rest.
   -------------------------------------------------------------------------- */

.section-cta {
  display: flex;
  justify-content: center;
  margin-top: 2.2rem;
}

/* --------------------------------------------------------------------------
   28. A button below a checklist
   The paragraph holding the button had only its own default margin to stand
   on, which left the button sitting against the last item of the list above
   it. It gets room of its own instead.
   -------------------------------------------------------------------------- */

.ideal-checks + p,
.ideal-steps + p {
  margin-top: 1.9rem;
}

/* --------------------------------------------------------------------------
   29. The second button on a dark panel
   .btn-light is a pale translucent wash, which reads as a button on the light
   sections it was drawn for and all but vanishes on the teal CTA panel and the
   teal sections -- the label sat there with no button around it. On anything
   dark it becomes a solid white button instead. The hero already had its own
   frosted version of this fix; these are the rest of the dark grounds.
   -------------------------------------------------------------------------- */

.ideal-cta .btn-light,
.on-teal .btn-light {
  color: var(--teal-deep);
  background: #fff;
  border: 1px solid #fff;
  box-shadow: 0 10px 24px rgba(3, 26, 28, .28);
}

.ideal-cta .btn-light:hover,
.on-teal .btn-light:hover {
  color: var(--teal-deep);
  background: #fff;
  box-shadow: 0 16px 34px rgba(3, 26, 28, .38);
}

/* --------------------------------------------------------------------------
   30. How wide a checklist runs
   Beside a picture the list is as narrow as its column, but in a full-width
   section it stretched the whole container -- a one-line item became a white
   bar running the width of the screen with the sentence stranded at the left.
   It takes the same measure the prose does, so a line ends where it is still
   comfortable to read.
   -------------------------------------------------------------------------- */

.ideal-checks {
  max-width: 720px;
}

/* --------------------------------------------------------------------------
   31. Two photographs side by side
   A pair of pictures closing a page, each taking half the width. They are
   cropped to a common shape so the row reads as one band however different
   the two originals are, and they stack on a phone.
   -------------------------------------------------------------------------- */

.photo-duo {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.2rem;
  margin: 2.2rem 0 0;
}

.photo-duo figure { margin: 0; }

/* 3:2 sits between the two shapes the photographs actually come in -- a wide
   room shot and a squarer one -- so neither loses much to the crop. */
.photo-duo img {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: 18px;
  box-shadow: var(--shadow-sm);
}

.photo-duo figcaption {
  margin-top: .5rem;
  font-size: .82rem;
  color: var(--muted);
}

@media (max-width: 720px) {
  .photo-duo { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   32. Board result rank lists
   Named rank-* rather than topper-*: style.css already carries a
   .topper-card from another theme, with a grid-column of its own that
   quietly took these cards two columns wide.
   The top three of a batch get a card each, then the whole batch follows as a
   plain ranked table. The cards are for the people who came to see a name and
   a number; the table is for reading the list properly, and it carries every
   student including the three above it, so the list is never missing its head.
   -------------------------------------------------------------------------- */

.rank-podium {
  list-style: none;
  margin: 0 0 2rem;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.1rem;
}

.rank-card {
  position: relative;
  overflow: hidden;
  text-align: center;
  padding: 1.6rem 1.2rem 1.5rem;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 22px;
  transition: transform .5s var(--ease-out), box-shadow .5s var(--ease-out), border-color .4s;
}

.rank-card:hover {
  transform: translateY(-6px);
  border-color: rgba(192, 86, 42, .35);
  box-shadow: 0 20px 44px rgba(11, 61, 65, .12);
}

/* First place is the one people are looking for, so it is the only card that
   changes colour rather than all three competing for attention. */
.rank-card.is-place-1 {
  color: #fff;
  background:
    radial-gradient(120% 160% at 100% 0%, #17696f 0%, transparent 60%),
    linear-gradient(120deg, var(--teal-deep), #0e4a4f);
  border-color: transparent;
}

.rank-place {
  display: inline-block;
  margin-bottom: 1rem;
  padding: .3rem .8rem;
  border-radius: 999px;
  background: var(--copper-soft);
  color: var(--copper);
  font-size: .68rem;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.rank-card.is-place-1 .rank-place {
  background: rgba(255, 255, 255, .16);
  color: #fff;
}

/* Initials rather than a photograph: the school has no portrait for every
   student, and a mixed row of photographs and blanks reads worse than none. */
.rank-mark {
  width: 68px;
  height: 68px;
  margin: 0 auto .9rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 2px solid var(--copper);
  background: var(--cream);
  color: var(--teal-deep);
  font-family: var(--font-head);
  font-size: 1.4rem;
  font-weight: 700;
  letter-spacing: .02em;
}

.rank-card.is-place-1 .rank-mark {
  border-color: var(--gold);
  background: rgba(255, 255, 255, .1);
  color: #fff;
}

.rank-card h3 {
  margin: 0 0 .35rem;
  font-size: 1.06rem;
  line-height: 1.3;
}

.rank-card.is-place-1 h3 { color: #fff; }

.rank-score {
  margin: 0;
  font-family: var(--font-head);
  font-size: 1.7rem;
  font-weight: 700;
  color: var(--copper);
  line-height: 1.1;
}

.rank-card.is-place-1 .rank-score { color: var(--gold); }

.rank-stream {
  margin: .3rem 0 0;
  font-size: .76rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}

.rank-card.is-place-1 .rank-stream { color: rgba(238, 246, 246, .78); }

/* The rank column is a number, and numbers read better right up against their
   own edge than spread across a column sized for a name. */
.rank-table th[scope="row"] {
  width: 4.5rem;
  color: var(--copper);
  font-family: var(--font-head);
  font-size: 1rem;
}

@media (max-width: 720px) {
  .rank-podium { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   33. A result poster
   A printed flex banner reproduced on the page. It is far too wide to read at
   page width, so it links to itself: the caption says so rather than leaving
   people to guess that the picture is clickable.
   -------------------------------------------------------------------------- */

.board-poster { margin: 0; }

.board-poster img {
  width: 100%;
  height: auto;
  border-radius: 18px;
  border: 1px solid var(--border);
  box-shadow: 0 18px 44px rgba(11, 61, 65, .12);
}

.board-poster figcaption {
  margin-top: .7rem;
  font-size: .84rem;
  color: var(--muted);
}

/* A rank list is three or four short columns; across the full container the
   name and the number ended up at opposite ends of the screen with a stretch
   of nothing between them. The podium above it takes the same measure, so the
   whole result block reads as one column under its heading. */
.rank-podium,
.rank-wrap {
  max-width: 920px;
  margin-inline: auto;
}

/* Centred under a centred heading, so the section holds together. */
.board-poster figcaption { text-align: center; }

/* --------------------------------------------------------------------------
   34. The yearly planner
   A hundred dated entries. As one long table the month was lost and every row
   looked alike; as a card per month the year can be scanned two months at a
   time, and a single month can be read on its own.
   -------------------------------------------------------------------------- */

/* Two text columns rather than a two-column grid. A grid gives every card in
   a row the height of the tallest, so February -- which has two entries next
   to March's twelve -- sat above a hole the height of ten rows. Columns let
   each card take only its own height and the next month close up under it.
   The reading order stays chronological: down the first column, then down the
   second. */
.planner {
  columns: 2;
  column-gap: 1.8rem;
}

.planner-month {
  /* A month must not be split across the two columns. */
  break-inside: avoid;
  page-break-inside: avoid;
  margin-bottom: 1.6rem;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 1.4rem 1.5rem 1.5rem;
  box-shadow: var(--shadow-sm);
}

.planner-title {
  margin: 0 0 1rem;
  padding-bottom: .6rem;
  font-size: 1.05rem;
  color: var(--teal-deep);
  border-bottom: 2px solid var(--copper);
}

.planner-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .6rem;
}

/* The date column is fixed so the events line up down the card whatever the
   width of the number beside them. */
.planner-list li {
  display: grid;
  grid-template-columns: 3.1rem 1fr;
  gap: .9rem;
  align-items: start;
  padding-bottom: .6rem;
  border-bottom: 1px dashed var(--border);
}

.planner-list li:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

.planner-when strong {
  display: block;
  font-family: var(--font-head);
  font-size: 1.05rem;
  line-height: 1.2;
  color: var(--copper);
}

.planner-when small {
  display: block;
  font-size: .64rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}

.planner-event {
  font-size: .88rem;
  line-height: 1.55;
  color: var(--ink);
}

@media (max-width: 860px) {
  .planner { columns: 1; }
}

/* --------------------------------------------------------------------------
   35. Faculty group headings
   Each group on the faculties page is announced centred, over its own people,
   rather than from the left margin. A group of two -- the management -- sat as
   two cards in the corner of a five-column grid, so the tracks are capped and
   the row is centred: two cards or twenty, they sit under their heading.
   -------------------------------------------------------------------------- */

.faculty-group-head {
  margin-inline: auto;
  text-align: center;
}

.faculty-people {
  grid-template-columns: repeat(auto-fit, minmax(200px, 240px));
  justify-content: center;
}

/* --------------------------------------------------------------------------
   36. The principal's sign-off
   The name used to head the message, above the line saying whose desk it came
   from. It now closes it instead: the office in the signature hand, the name
   set under it.
   -------------------------------------------------------------------------- */

.principal-sign {
  margin: 1.4rem 0 1.6rem;
}

.principal-copy .signature {
  display: block;
  margin: 0;
}

.principal-name {
  margin: .1rem 0 0;
  font-size: 1.2rem;
  color: var(--teal-deep);
}

/* --------------------------------------------------------------------------
   37. Narrow tables
   A table of two columns -- a name and a position, a label and a value -- had
   the same full container width as the seven-column fee table, which left the
   two entries at opposite ends of the screen. Selecting on the table having
   exactly two header cells caps those and leaves the wide ones alone; a
   browser that cannot read :has() simply keeps the old full width.
   -------------------------------------------------------------------------- */

.ideal-table-wrap:has(thead th:nth-child(2):last-child) {
  max-width: 760px;
  margin-inline: auto;
}

/* --------------------------------------------------------------------------
   38. Timings, grouped
   School, office and visiting hours are three separate questions, so each gets
   its own short table under its own heading rather than being flattened into
   one list. The heading is held to the same measure as the table under it.
   -------------------------------------------------------------------------- */

.timing-group {
  max-width: 760px;
  margin-inline: auto;
}

.timing-group + .timing-group {
  margin-top: 2.2rem;
}

.timing-title {
  margin: 0 0 .8rem;
  font-size: 1.05rem;
  color: var(--teal-deep);
}

/* --------------------------------------------------------------------------
   39. Sections that are one element
   A section of copy earns the full band of space above and below it. A section
   whose entire content is a pair of photographs, or a call-to-action panel
   that already carries its own padding, does not -- stacked, those bands left
   a screen's worth of empty ground between one thing and the next.
   -------------------------------------------------------------------------- */

.ideal-section:has(> .container > .photo-duo:only-child),
.ideal-section:has(> .container > .ideal-cta:only-child) {
  padding-block: clamp(1.8rem, 3.4vw, 3rem);
}

/* The duo's own top margin is for when it follows copy inside a section; on
   its own it would only add to the padding above it. */
.container > .photo-duo:first-child {
  margin-top: 0;
}

/* --------------------------------------------------------------------------
   40. The Apply Now button in the navigation
   It takes the same size as the buttons that sit inside a section, where a
   button is the point of the block. In the navigation bar it is one item in a
   row of links, and at full size it dominated the header -- so it keeps its
   colour and loses a step of height, padding and type.
   -------------------------------------------------------------------------- */

.nav-cta {
  min-height: 40px;
  padding: 8px 18px;
  gap: 7px;
  font-size: .88rem;
}

/* --------------------------------------------------------------------------
   41. The header on a phone
   Below 920px the crest block was given its width back but kept flex:0 0 auto,
   so it could not give: at 390px it measured 353px inside a 337px row and
   shouldered the menu button off the right edge, where the page's overflow
   clip cut it in half. The crest now yields and the button never does; on a
   phone the two affiliation lines go, since at that size they are a band of
   unreadable capitals above a name that has to wrap anyway.
   -------------------------------------------------------------------------- */

@media (max-width: 920px) {
  .navbar { gap: 12px; }

  .brand {
    flex: 0 1 auto;
    min-width: 0;
  }

  .menu-toggle {
    flex: 0 0 auto;
    margin-left: auto;
  }
}

@media (max-width: 600px) {
  .brand-text span { display: none; }
  .brand-text strong { font-size: 1rem; }
}

/* --------------------------------------------------------------------------
   42. Spacing and stacking on a phone
   Two things were making a phone scroll further than it needed to. The band of
   space around a section was set larger below 640px than it is on a desktop --
   70px a side, so 140px of nothing between one section and the next on the
   narrowest screen there is. And the figures band asks for 180px a column, one
   more than a 337px row can hold, so four figures stood in a column four deep.
   -------------------------------------------------------------------------- */

@media (max-width: 640px) {
  .section { padding: 2.6rem 0; }
  .ideal-section { padding-block: 2.8rem; }
}

/* Two by two rather than four deep: the whole band then fits on one screen. */
@media (max-width: 560px) {
  .stat-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.5rem .6rem;
  }
}
