/* =====================================================================
   South Point English School — public website components
   Layer 2 of 3. Depends on the tokens in base.css.
   ===================================================================== */

/* =====================================================================
   1. TOP BAR  (contact strip above the header)
   ===================================================================== */
.topbar {
    background: var(--brand-900);
    color: rgba(255, 255, 255, 0.78);
    font-size: var(--step--2);
    letter-spacing: 0.02em;
}

.topbar__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2xs) var(--space-sm);
    min-height: 2.25rem;
    padding-block: 0.4rem;
}

.topbar__group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2xs) var(--space-sm);
    min-width: 0;
}

.topbar__item {
    display: inline-flex;
    align-items: center;
    gap: 0.4em;
    color: inherit;
    text-decoration: none;
    white-space: nowrap;
}

.topbar__item:hover {
    color: #fff;
}

.topbar__item svg {
    width: 0.95em;
    height: 0.95em;
    flex: none;
    opacity: 0.7;
}

/* --- Telephone numbers ---------------------------------------------- */
/* The school publishes a landline and two mobiles. They share one icon and
   one group so the strip stays a list of contact details rather than a row
   of near-identical items. */
.topbar__phones {
    /* .topbar__item pins nowrap so single items never break mid-label. Three
       numbers are longer than one, so this group is allowed to wrap. */
    white-space: normal;
}

.topbar__phone-list {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0 0.5em;
}

.topbar__phone {
    color: inherit;
    text-decoration: none;
    white-space: nowrap;
    /* A comfortable tap target without altering the height of the strip. */
    padding-block: 0.15rem;
}

.topbar__phone:hover,
.topbar__phone:focus-visible {
    color: #fff;
}

/* A thin separator between numbers, drawn rather than typed so it is never
   read out by a screen reader. */
.topbar__phone + .topbar__phone::before {
    content: "";
    display: inline-block;
    width: 1px;
    height: 0.8em;
    margin-right: 0.5em;
    vertical-align: -0.05em;
    background: rgba(255, 255, 255, 0.28);
}

.topbar__divider {
    width: 1px;
    height: 0.9rem;
    background: rgba(255, 255, 255, 0.2);
}

/* The contact strip is a convenience, not essential: on the smallest
   phones it is hidden so the header itself gets the vertical space. */
@media (max-width: 47.9375em) {
    .topbar__group--secondary {
        display: none;
    }
}

@media (max-width: 29.9375em) {
    .topbar {
        display: none;
    }
}

/* =====================================================================
   1b. NOTICE TICKER  (scrolling announcements above the carousel)
   ---------------------------------------------------------------------
   The band only exists in the markup when a notice is published, so there is
   no "empty" state to style here — if this rule is doing anything at all,
   there is something to read.

   --ticker-bg, --ticker-fg and --ticker-duration are set inline from Website
   Settings, so the school controls the colours and the speed. The fallbacks
   are only reached if a value is somehow missing.
   ===================================================================== */
.ticker {
    position: relative;
    z-index: 1;
    background: var(--ticker-bg);
    color: var(--ticker-fg);
    font-size: var(--step--1);
    /* The track is wider than the screen by design. */
    overflow: hidden;
}

.ticker__inner {
    display: flex;
    align-items: stretch;
    min-height: 2.5rem;
}

/* --- The fixed label ------------------------------------------------- */
/* Outside the scrolling area, so "Notices" stays put and the band reads as
   a labelled strip rather than mystery text drifting past. */
.ticker__label {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 0.45em;
    margin: 0;
    padding-inline: var(--gutter) 0.9em;
    font-size: var(--step--2);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    /* A wash of the band's own colour, so it darkens whatever the school
       picks instead of assuming the background is green. */
    background: rgba(0, 0, 0, 0.16);
}

.ticker__label svg {
    width: 1em;
    height: 1em;
    flex: none;
}

/* --- The moving area ------------------------------------------------- */
.ticker__viewport {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    /* Fades the text out as it reaches the edges rather than letting it stop
       dead against them. */
    -webkit-mask-image: linear-gradient(to right, transparent, #000 2.5rem, #000 calc(100% - 2.5rem), transparent);
    mask-image: linear-gradient(to right, transparent, #000 2.5rem, #000 calc(100% - 2.5rem), transparent);
}

/*
 * The track carries the notices twice. Shifting it left by exactly half its
 * own width lands the second copy where the first started, so the loop is
 * seamless however many notices there are and whatever they say.
 */
.ticker__track {
    display: flex;
    width: max-content;
    animation: ticker-scroll var(--ticker-duration) linear infinite;
}

.ticker__list {
    display: flex;
    align-items: center;
    gap: 0;
    list-style: none;
    margin: 0;
    padding: 0;
}

.ticker__item {
    display: inline-flex;
    align-items: center;
    /* One line, always: a wrapped notice would break the loop geometry. */
    white-space: nowrap;
    padding-block: 0.45rem;
    padding-inline: 1.6em;
}

/* A diamond between notices, drawn rather than typed so a screen reader
   reads the notices and not a row of punctuation. */
.ticker__item::after {
    content: "";
    width: 0.4em;
    height: 0.4em;
    margin-left: 1.6em;
    margin-right: -1.6em;
    flex: none;
    rotate: 45deg;
    background: currentColor;
    opacity: 0.45;
}

.ticker__link {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px solid currentColor;
    /* The underline should read as an underline, not as part of the letters. */
    padding-bottom: 0.1em;
}

.ticker__link:hover,
.ticker__link:focus-visible {
    border-bottom-width: 2px;
}

@keyframes ticker-scroll {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}

/* Hovering or tabbing into the band stops it, so a notice can actually be
   read or clicked instead of sliding away from the pointer. */
.ticker:hover .ticker__track,
.ticker:focus-within .ticker__track {
    animation-play-state: paused;
}

/*
 * Movement is decoration. Without it the band becomes a plain list that can be
 * scrolled by hand, and the duplicate copy is removed so nothing is repeated.
 */
@media (prefers-reduced-motion: reduce) {
    .ticker__track {
        animation: none;
        width: auto;
    }

    .ticker__track > .ticker__list[aria-hidden="true"] {
        display: none;
    }

    .ticker__viewport {
        overflow-x: auto;
        -webkit-mask-image: none;
        mask-image: none;
    }

    .ticker__list {
        flex-wrap: wrap;
    }
}

/* =====================================================================
   2. HEADER
   ===================================================================== */
.site-header {
    position: sticky;
    top: 0;
    z-index: var(--z-header);
    background: rgba(255, 255, 255, 0.97);
    border-bottom: 1px solid var(--ink-200);
    transition:
        box-shadow var(--duration-base) var(--ease-out),
        background-color var(--duration-base) var(--ease-out),
        border-color var(--duration-base) var(--ease-out);
}

@supports (backdrop-filter: blur(10px)) or (-webkit-backdrop-filter: blur(10px)) {
    .site-header {
        background: rgba(255, 255, 255, 0.72);
        -webkit-backdrop-filter: blur(var(--glass-blur-lg)) saturate(1.8);
        backdrop-filter: blur(var(--glass-blur-lg)) saturate(1.8);
        border-bottom-color: rgba(255, 255, 255, 0.6);
    }

    /* Once scrolled, the panel firms up so navigation stays legible over
       whatever content is passing beneath it. */
    .site-header.is-stuck {
        background: rgba(255, 255, 255, 0.86);
        border-bottom-color: var(--ink-200);
    }
}

.site-header.is-stuck {
    box-shadow: 0 6px 26px rgba(12, 110, 85, 0.12);
}

@media (prefers-reduced-transparency: reduce) {
    .site-header,
    .site-header.is-stuck {
        background: #fff;
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }
}

.header__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-xs);
    min-height: var(--header-height);
    padding-block: var(--space-2xs);
    /* The header carries more across it than any content section, so it is
       allowed the wider shell and a tighter gutter than the page body. */
    max-width: var(--shell-wide);
}

@media (min-width: 85em) {
    .header__inner {
        padding-inline: clamp(1rem, 2vw, 2rem);
    }
}

/* --- Brand lockup -------------------------------------------------- */
.brand {
    display: flex;
    align-items: center;
    gap: clamp(0.5rem, 1.5vw, 0.85rem);
    text-decoration: none;
    color: inherit;
    /* The brand may shrink, but never below a width that keeps the school
       name readable. Without a floor, flexbox crushes this item and the
       name wraps one character per line. */
    flex: 0 1 auto;
    min-width: min(100%, 13rem);
}

/* Once the full navigation is on screen the bar is competing for width, so
   the brand gives a little back. The school name already wraps onto two
   balanced lines, so a narrower floor costs nothing. */
@media (min-width: 85em) {
    .brand {
        min-width: min(100%, 11rem);
    }
}

/* The logo is the school's primary mark, so it is given real presence.
   It is allowed to stand taller than the header text block, which is why
   the header's min-height accommodates it rather than clipping it. */

/* A soft coloured halo behind the crest. It makes the outline logo sit on
   the white header as a deliberate object rather than floating, and it is
   the first spot of colour a visitor sees. */
.brand__crest {
    position: relative;
    display: grid;
    place-items: center;
    flex: none;
}

.brand__crest::before {
    content: "";
    position: absolute;
    inset: -8%;
    border-radius: 50%;
    background:
        radial-gradient(circle at 30% 25%, var(--brand-100) 0%, var(--gold-100) 55%, transparent 72%);
    transition: transform var(--duration-slow) var(--ease-bounce);
}

.brand:hover .brand__crest::before {
    transform: scale(1.12) rotate(8deg);
}

.brand__mark {
    position: relative;
    flex: none;
    width: clamp(3.25rem, 7vw, 4.75rem);
    height: clamp(3.25rem, 7vw, 4.75rem);
    object-fit: contain;
    /* A transparent PNG needs no background; object-fit keeps the outline
       correctly proportioned whatever the source aspect ratio. */
    transition: transform var(--duration-slow) var(--ease-bounce);
}

.brand:hover .brand__mark {
    transform: scale(1.06);
}

/* Shown only if no crest file can be found at all. */
.brand__mark--initials {
    display: grid;
    place-items: center;
    background: linear-gradient(140deg, var(--brand-500), var(--brand-800));
    color: #fff;
    border-radius: 50%;
    font-family: var(--font-display);
    font-weight: 700;
    letter-spacing: 0.02em;
}

@media (prefers-reduced-motion: reduce) {
    .brand:hover .brand__crest::before,
    .brand:hover .brand__mark {
        transform: none;
    }
}

.brand__text {
    min-width: 0;
}

/* The name may wrap onto a second line, but never mid-word and never
   down to a single character per line. */
.brand__name,
.brand__tagline {
    overflow-wrap: normal;
    word-break: keep-all;
    hyphens: none;
}

.brand__name {
    display: block;
    font-family: var(--font-display);
    font-size: clamp(0.95rem, 0.78rem + 0.85vw, 1.3rem);
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: -0.01em;
    color: var(--brand-800);
    /* Deliberately allowed to wrap onto two balanced lines. A long school
       name on one line would eat the width the navigation needs. */
    max-width: 11em;
    text-wrap: balance;
}

.brand__tagline {
    display: block;
    margin-top: 0.15em;
    font-size: clamp(0.58rem, 0.5rem + 0.28vw, 0.7rem);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wider);
    color: var(--ink-500);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The tagline is the first thing sacrificed when width gets tight, so the
   school name itself keeps as much room as possible. */
@media (max-width: 87.5em) {
    .brand__tagline {
        display: none;
    }
}

/* =====================================================================
   3. DESKTOP NAVIGATION
   ===================================================================== */
.primary-nav {
    display: none;
}

/* Desktop nav appears only when there is genuinely room for it.
   Eight top-level items plus the Admission button and the school name need
   roughly 1360px to sit side by side without crushing each other, so the
   drawer is used below that — including on a 1280px laptop. A tidy drawer
   beats a broken header.
   NOTE: the 85em value is repeated on .header__cta and .nav-toggle below,
   and in site.js. All four must change together. */
@media (min-width: 85em) {
    .primary-nav {
        display: block;
        margin-left: auto;
    }

    .nav-list {
        display: flex;
        align-items: stretch;
        /* Tight at the breakpoint, more generous on a large monitor. */
        gap: clamp(0.05rem, 0.35vw, 0.5rem);
        list-style: none;
        margin: 0;
        padding: 0;
        min-width: 0;
    }

    .nav-item {
        position: relative;
        display: flex;
        align-items: stretch;
        min-width: 0;
    }

    .nav-link {
        display: inline-flex;
        align-items: center;
        gap: 0.35em;
        /* Tight at the breakpoint: "Mandatory Public Disclosure" is written
           out in full here, so the bar has to earn its width back from the
           padding and tracking rather than from the wording. */
        padding: 0.6rem clamp(0.3rem, 0.7vw, 0.7rem);
        font-size: clamp(0.64rem, 0.5rem + 0.28vw, 0.74rem);
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: clamp(0.04em, 0.35vw, 0.085em);
        text-decoration: none;
        color: var(--ink-700);
        /*
         * Long labels wrap onto a second line rather than being truncated or
         * pushing the bar wider than the window. "Mandatory Public
         * Disclosure" is written out in full here, and the header is tall
         * enough for two lines of this size, so a taller item is a far better
         * outcome than an overflowing one. Short labels are unaffected: they
         * are narrower than the max-width and stay on one line.
         */
        white-space: normal;
        max-width: 11em;
        text-align: center;
        line-height: 1.22;
        text-wrap: balance;
        background: none;
        border: 0;
        border-radius: var(--radius-sm);
        cursor: pointer;
        transition: color var(--duration-fast) var(--ease-out);
    }

    .nav-link:hover,
    .nav-item:hover > .nav-link,
    .nav-item:focus-within > .nav-link {
        color: var(--brand-700);
    }

    /* Active state: a thick, rounded, clearly visible underline */
    .nav-link::after {
        content: "";
        position: absolute;
        left: clamp(0.3rem, 0.7vw, 0.7rem);
        right: clamp(0.3rem, 0.7vw, 0.7rem);
        bottom: 0.1rem;
        height: 4px;
        border-radius: var(--radius-pill);
        background: linear-gradient(90deg, var(--brand-500), var(--gold-500));
        transform: scaleX(0);
        transform-origin: left center;
        transition: transform var(--duration-base) var(--ease-out);
    }

    .nav-link:hover::after,
    .nav-item:focus-within > .nav-link::after {
        transform: scaleX(0.55);
    }

    .nav-link[aria-current="page"],
    .nav-item.is-active > .nav-link {
        color: var(--brand-800);
    }

    .nav-link[aria-current="page"]::after,
    .nav-item.is-active > .nav-link::after {
        transform: scaleX(1);
    }

    .nav-caret {
        width: 0.55em;
        height: 0.55em;
        flex: none;
        opacity: 0.55;
        transition: transform var(--duration-base) var(--ease-out);
    }

    .nav-item:hover .nav-caret,
    .nav-item:focus-within .nav-caret,
    .nav-link[aria-expanded="true"] .nav-caret {
        transform: rotate(180deg);
        opacity: 0.9;
    }

    /* --- Dropdown panels ------------------------------------------- */
    .nav-panel {
        position: absolute;
        top: 100%;
        left: 50%;
        transform: translate(-50%, 0.4rem);
        min-width: 15rem;
        max-width: min(20rem, calc(100vw - 2rem));
        padding: var(--space-2xs);
        list-style: none;
        margin: 0;
        background: #fff;
        border: 1px solid var(--ink-200);
        border-radius: var(--radius-md);
        box-shadow: var(--shadow-lg);
        opacity: 0;
        visibility: hidden;
        pointer-events: none;
        transition:
            opacity var(--duration-base) var(--ease-out),
            transform var(--duration-base) var(--ease-out),
            visibility var(--duration-base);
    }

    /* Panels near the right edge align right instead of overflowing */
    .nav-item:last-child .nav-panel,
    .nav-item:nth-last-child(2) .nav-panel {
        left: auto;
        right: 0;
        transform: translate(0, 0.4rem);
    }

    .nav-item:hover > .nav-panel,
    .nav-item:focus-within > .nav-panel,
    .nav-panel.is-open {
        opacity: 1;
        visibility: visible;
        pointer-events: auto;
        transform: translate(-50%, 0);
    }

    .nav-item:last-child:hover > .nav-panel,
    .nav-item:last-child:focus-within > .nav-panel,
    .nav-item:nth-last-child(2):hover > .nav-panel,
    .nav-item:nth-last-child(2):focus-within > .nav-panel {
        transform: translate(0, 0);
    }

    /* Invisible bridge so the pointer can travel into the panel */
    .nav-item--has-panel::after {
        content: "";
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        height: 0.5rem;
    }

    .nav-panel__link {
        display: block;
        padding: 0.6rem 0.8rem;
        font-size: var(--step--1);
        font-weight: 500;
        letter-spacing: 0.01em;
        text-transform: none;
        text-decoration: none;
        color: var(--ink-700);
        border-radius: var(--radius-sm);
        transition:
            background-color var(--duration-fast) var(--ease-out),
            color var(--duration-fast) var(--ease-out),
            padding-left var(--duration-fast) var(--ease-out);
    }

    .nav-panel__link:hover {
        background: var(--brand-050);
        color: var(--brand-800);
        padding-left: 1rem;
    }

    .nav-panel__link[aria-current="page"] {
        background: var(--brand-050);
        color: var(--brand-800);
        font-weight: 600;
        box-shadow: inset 2px 0 0 var(--brand-600);
    }
}

/* --- Header actions ------------------------------------------------ */
.header__actions {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    flex: none;
}

.header__cta {
    display: none;
}

/* Matches the desktop-nav breakpoint: the CTA only appears once the full
   navigation does, otherwise it competes with the brand for width. */
@media (min-width: 85em) {
    .header__cta {
        display: inline-flex;
        margin-left: clamp(0.35rem, 1vw, 1rem);
    }
}

/* --- Hamburger ----------------------------------------------------- */
.nav-toggle {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    width: 2.875rem;
    height: 2.875rem;
    flex: none;
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-sm);
    background: #fff;
    transition:
        border-color var(--duration-fast) var(--ease-out),
        background-color var(--duration-fast) var(--ease-out);
}

.nav-toggle:hover {
    border-color: var(--brand-200);
    background: var(--brand-050);
}

.nav-toggle__bar {
    display: block;
    width: 1.25rem;
    height: 1.5px;
    background: var(--brand-800);
    border-radius: 2px;
    transition:
        transform var(--duration-base) var(--ease-emphasis),
        opacity var(--duration-fast) var(--ease-out);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(1) {
    transform: translateY(6.5px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(2) {
    opacity: 0;
    transform: scaleX(0.4);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(3) {
    transform: translateY(-6.5px) rotate(-45deg);
}

/* Must match the desktop-nav breakpoint exactly, or there would be a
   window with neither a menu nor a hamburger. */
@media (min-width: 85em) {
    .nav-toggle {
        display: none;
    }
}

/* =====================================================================
   4. MOBILE DRAWER
   ===================================================================== */
.nav-overlay {
    position: fixed;
    inset: 0;
    z-index: var(--z-drawer);
    background: rgba(12, 110, 85, 0.48);
    opacity: 0;
    visibility: hidden;
    transition:
        opacity var(--duration-base) var(--ease-out),
        visibility var(--duration-base);
}

.nav-overlay.is-open {
    opacity: 1;
    visibility: visible;
}

.mobile-nav {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: calc(var(--z-drawer) + 1);
    /* Comfortable on a 320px phone, never wider than needed on a tablet */
    width: min(22rem, 90vw);
    display: flex;
    flex-direction: column;
    background: #fff;
    box-shadow: -8px 0 40px rgba(12, 110, 85, 0.22);
    transform: translateX(100%);
    visibility: hidden;
    transition:
        transform var(--duration-slow) var(--ease-emphasis),
        visibility var(--duration-slow);
    /* Respects notches and the iOS home indicator */
    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
}

.mobile-nav.is-open {
    transform: translateX(0);
    visibility: visible;
}

.mobile-nav__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    padding: var(--space-sm) var(--space-md);
    border-bottom: 1px solid var(--ink-200);
    flex: none;
}

.mobile-nav__title {
    font-family: var(--font-display);
    font-size: var(--step-0);
    font-weight: 600;
    color: var(--brand-800);
    line-height: 1.2;
}

.mobile-nav__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    flex: none;
    margin-right: -0.5rem;
    border-radius: var(--radius-sm);
    color: var(--ink-600);
    transition:
        background-color var(--duration-fast) var(--ease-out),
        color var(--duration-fast) var(--ease-out);
}

.mobile-nav__close:hover {
    background: var(--ink-100);
    color: var(--ink-900);
}

.mobile-nav__close svg {
    width: 1.15rem;
    height: 1.15rem;
}

.mobile-nav__body {
    flex: 1;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding: var(--space-xs) 0 var(--space-md);
}

.mobile-nav__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.mobile-nav__item {
    border-bottom: 1px solid var(--ink-100);
}

.mobile-nav__link,
.mobile-nav__trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-xs);
    width: 100%;
    /* 52px tall: a generous touch target */
    min-height: 3.25rem;
    padding: 0.85rem var(--space-md);
    font-family: var(--font-body);
    font-size: var(--step-0);
    font-weight: 600;
    letter-spacing: 0.01em;
    text-align: left;
    text-decoration: none;
    color: var(--ink-800);
    background: none;
    border: 0;
    transition:
        background-color var(--duration-fast) var(--ease-out),
        color var(--duration-fast) var(--ease-out);
}

.mobile-nav__link:hover,
.mobile-nav__trigger:hover {
    background: var(--paper-warm);
    color: var(--brand-800);
}

.mobile-nav__link[aria-current="page"] {
    color: var(--brand-800);
    background: var(--brand-050);
    box-shadow: inset 3px 0 0 var(--brand-600);
}

/* Expanded state is unmistakable: tinted row plus rotated chevron */
.mobile-nav__trigger[aria-expanded="true"] {
    background: var(--brand-050);
    color: var(--brand-800);
}

.mobile-nav__chevron {
    width: 0.7rem;
    height: 0.7rem;
    flex: none;
    opacity: 0.5;
    transition:
        transform var(--duration-base) var(--ease-out),
        opacity var(--duration-fast) var(--ease-out);
}

.mobile-nav__trigger[aria-expanded="true"] .mobile-nav__chevron {
    transform: rotate(180deg);
    opacity: 1;
}

/* Nested submenu: animated height, no jump.

   The panel is a <div> and the list inside it is the <ul>. It used to be the
   other way round, with a bare <div> as a direct child of the <ul> — invalid,
   and it meant the <li>s were not children of any list, so assistive software
   announced the submenu without a role, a position or an item count. */
.mobile-nav__submenu {
    overflow: hidden;
    background: var(--paper-warm);
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--duration-slow) var(--ease-emphasis);
}

/* The content of the animated row. min-height:0 is what lets a grid row
   actually collapse to nothing. */
.mobile-nav__sublist {
    list-style: none;
    margin: 0;
    padding: 0;
    overflow: hidden;
    min-height: 0;
}

.mobile-nav__submenu.is-open {
    grid-template-rows: 1fr;
}

/* Fallback for browsers without animatable grid rows */
@supports not (grid-template-rows: 0fr) {
    .mobile-nav__submenu {
        display: block;
        max-height: 0;
        transition: max-height var(--duration-slow) var(--ease-emphasis);
    }

    .mobile-nav__submenu.is-open {
        max-height: 30rem;
    }
}

.mobile-nav__sublink {
    display: flex;
    align-items: center;
    min-height: 2.875rem;
    padding: 0.7rem var(--space-md) 0.7rem calc(var(--space-md) + 0.9rem);
    font-size: var(--step--1);
    font-weight: 500;
    text-decoration: none;
    color: var(--ink-600);
    border-top: 1px solid rgba(0, 0, 0, 0.04);
    transition:
        color var(--duration-fast) var(--ease-out),
        background-color var(--duration-fast) var(--ease-out);
}

.mobile-nav__sublink::before {
    content: "";
    width: 0.5rem;
    height: 1px;
    margin-right: 0.6rem;
    background: var(--gold-500);
    flex: none;
    transition: width var(--duration-fast) var(--ease-out);
}

.mobile-nav__sublink:hover {
    color: var(--brand-800);
    background: #fff;
}

.mobile-nav__sublink:hover::before {
    width: 0.9rem;
}

.mobile-nav__sublink[aria-current="page"] {
    color: var(--brand-800);
    font-weight: 600;
}

.mobile-nav__foot {
    flex: none;
    padding: var(--space-md);
    border-top: 1px solid var(--ink-200);
    background: var(--paper-warm);
    display: grid;
    gap: var(--space-xs);
}

.mobile-nav__contact {
    display: flex;
    align-items: center;
    gap: 0.5em;
    font-size: var(--step--1);
    color: var(--ink-600);
    text-decoration: none;
    /* Long email addresses must wrap, not overflow */
    overflow-wrap: anywhere;
}

.mobile-nav__contact svg {
    width: 0.95em;
    height: 0.95em;
    flex: none;
    color: var(--brand-600);
}

/* =====================================================================
   5. HERO CAROUSEL
   ===================================================================== */
.hero {
    position: relative;
    isolation: isolate;
    background: var(--brand-900);
    /* Height is viewport-relative but capped, and has a floor so the
       text never crowds the image on a short landscape phone. */
    min-height: clamp(26rem, 78svh, 44rem);
    display: grid;
    overflow: hidden;
}

/* Taller, more cinematic on wide screens */
@media (min-width: 64em) {
    .hero {
        min-height: clamp(34rem, 86svh, 50rem);
    }
}

/* Landscape phones: don't demand more than the screen has */
@media (max-height: 30rem) and (orientation: landscape) {
    .hero {
        min-height: 100svh;
    }
}

.hero__viewport {
    position: absolute;
    inset: 0;
    z-index: 0;
}

/* --- Slides: crossfade with a slow scale, nothing more --------------- */
/* The slide is a grid so its single child (.hero__content) can be stretched
   to the full height of the hero. Without this the content block only grows
   to fit its text, and `align-content: end` has no free space to push
   against — leaving the heading floating near the top. */
.hero__slide {
    position: absolute;
    inset: 0;
    display: grid;
    grid-template-rows: 1fr;
    opacity: 0;
    visibility: hidden;
    transition:
        opacity var(--hero-fade, 1100ms) var(--ease-in-out),
        visibility var(--hero-fade, 1100ms);
}

.hero__slide.is-active {
    opacity: 1;
    visibility: visible;
    z-index: 1;
}

.hero__media {
    position: absolute;
    inset: 0;
    overflow: hidden;
}

/* The slow zoom (a "Ken Burns" drift) runs for the whole time a slide is on
   screen. Starting slightly scaled and settling back to 1 means the movement
   is always inward, which reads as calm rather than restless. */
.hero__image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Slight downward bias keeps faces in frame on tall crops */
    object-position: center 42%;
    transform: scale(1.08);
    transition: transform 9000ms cubic-bezier(0.33, 0, 0.25, 1);
    will-change: transform;
}

.hero__slide.is-active .hero__image {
    transform: scale(1);
}

/* The outgoing slide drifts very slightly the other way, so the crossfade
   has a sense of depth instead of two flat images dissolving. */
.hero__slide:not(.is-active) .hero__image {
    transform: scale(1.08);
}

/* The scrim was a two-layer green wash over the slide. It is now fully
   transparent so the photographs are shown exactly as they were taken.
   The element itself is kept (rather than deleted from the markup) so the
   wash can be brought back by raising the opacity alone.
   Because the slide no longer darkens behind the copy, legibility is
   carried entirely by the text shadows on .hero__eyebrow / __heading /
   __text below. */
.hero__scrim {
    position: absolute;
    inset: 0;
    opacity: 0;
    background:
        linear-gradient(
            to top,
            rgba(9, 88, 68, 0.90) 0%,
            rgba(9, 88, 68, 0.64) 32%,
            rgba(9, 88, 68, 0.30) 62%,
            rgba(9, 88, 68, 0.34) 100%
        ),
        linear-gradient(
            to right,
            rgba(9, 88, 68, 0.62) 0%,
            rgba(9, 88, 68, 0.22) 55%,
            rgba(9, 88, 68, 0) 100%
        );
}

/* --- Slide copy ----------------------------------------------------- */
/* Copy is anchored to the bottom of the hero. The bottom padding leaves room
   for the arrows and slide indicators, which sit in their own layer below. */
.hero__content {
    position: relative;
    z-index: 2;
    display: grid;
    align-content: end;
    width: 100%;
    min-height: 0;
    padding-top: var(--space-xl);
    padding-bottom: clamp(5rem, 9vw, 7rem);
    pointer-events: none;
}

.hero__copy {
    /* Never wider than the reading measure, never wider than the screen */
    max-width: min(40rem, 100%);
    display: grid;
    gap: var(--space-xs);
    color: #fff;
}

.hero__copy > * {
    pointer-events: auto;
}

.hero__eyebrow {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    font-size: var(--step--2);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-widest);
    color: var(--gold-200);
    /* With the scrim at zero opacity the copy sits directly on the
       photograph, so each line carries its own shadow: a tight one for
       edge definition and a wide one to lift it off a busy background. */
    text-shadow:
        0 1px 2px rgba(0, 0, 0, 0.55),
        0 1px 18px rgba(0, 0, 0, 0.45);
}

.hero__eyebrow::before {
    content: "";
    width: clamp(1.5rem, 4vw, 2.5rem);
    height: 1px;
    background: var(--gold-500);
    flex: none;
}

.hero__heading {
    /* Stated rather than inherited, because this class is used on an <h1> in
       the standfirst band and on a <p> over each slide. Only the heading
       elements pick up the display face from base.css, so without this the
       two would be set in different typefaces. */
    font-family: var(--font-display);
    font-size: var(--step-6);
    font-weight: 600;
    line-height: 1.06;
    letter-spacing: -0.02em;
    color: #fff;
    text-shadow:
        0 1px 3px rgba(0, 0, 0, 0.5),
        0 2px 28px rgba(0, 0, 0, 0.55);
    text-wrap: balance;
}

.hero__text {
    font-size: var(--step-1);
    line-height: var(--leading-normal);
    color: #fff;
    max-width: 34rem;
    text-shadow:
        0 1px 2px rgba(0, 0, 0, 0.55),
        0 1px 20px rgba(0, 0, 0, 0.5);
    text-wrap: pretty;
}

.hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    margin-top: var(--space-2xs);
}

/* --- Entrance choreography -------------------------------------------
   The image settles first, then the words arrive in reading order:
   eyebrow → heading → description → button. Each element rises a short
   distance and fades in, with a slight blur lifting on the heading so it
   appears to resolve into focus. Nothing bounces, spins or flashes.
   -------------------------------------------------------------------- */
.hero__slide .hero__eyebrow,
.hero__slide .hero__heading,
.hero__slide .hero__text,
.hero__slide .hero__actions {
    opacity: 0;
    transform: translateY(1.5rem);
    transition:
        opacity 800ms var(--ease-out),
        transform 1000ms var(--ease-emphasis),
        filter 800ms var(--ease-out);
}

/* Only the heading gets the focus-pull; on the smaller text it would just
   look smudged during the transition. */
.hero__slide .hero__heading {
    filter: blur(6px);
}

.hero__slide.is-active .hero__eyebrow,
.hero__slide.is-active .hero__heading,
.hero__slide.is-active .hero__text,
.hero__slide.is-active .hero__actions {
    opacity: 1;
    transform: translateY(0);
}

.hero__slide.is-active .hero__heading {
    filter: blur(0);
}

/* Staggered so each line lands just as the eye reaches it. */
.hero__slide.is-active .hero__eyebrow { transition-delay: 300ms; }
.hero__slide.is-active .hero__heading { transition-delay: 440ms; }
.hero__slide.is-active .hero__text    { transition-delay: 600ms; }
.hero__slide.is-active .hero__actions { transition-delay: 760ms; }

/* Outgoing text leaves quickly and without delay, so it is gone before the
   incoming text arrives and the two never overlap mid-air. */
.hero__slide:not(.is-active) .hero__eyebrow,
.hero__slide:not(.is-active) .hero__heading,
.hero__slide:not(.is-active) .hero__text,
.hero__slide:not(.is-active) .hero__actions {
    transition-duration: 400ms;
    transition-delay: 0ms;
    transform: translateY(-0.75rem);
}

/* Reduced motion: the fade stays, all movement, zoom and blur is removed */
@media (prefers-reduced-motion: reduce) {
    .hero__image,
    .hero__slide.is-active .hero__image,
    .hero__slide:not(.is-active) .hero__image {
        transform: none;
        transition: none;
    }

    .hero__slide .hero__eyebrow,
    .hero__slide .hero__heading,
    .hero__slide .hero__text,
    .hero__slide .hero__actions,
    .hero__slide:not(.is-active) .hero__eyebrow,
    .hero__slide:not(.is-active) .hero__heading,
    .hero__slide:not(.is-active) .hero__text,
    .hero__slide:not(.is-active) .hero__actions {
        opacity: 1;
        transform: none;
        filter: none;
        transition: none;
    }
}

/* --- Controls ------------------------------------------------------- */
.hero__controls {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 3;
    padding-bottom: clamp(1rem, 3vw, 1.75rem);
}

.hero__controls-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
}

.hero__arrows {
    display: flex;
    gap: var(--space-2xs);
}

.hero__arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.875rem;
    height: 2.875rem;
    flex: none;
    color: #fff;
    border: 1px solid rgba(255, 255, 255, 0.38);
    border-radius: 50%;
    background: rgba(12, 110, 85, 0.40);
    transition:
        background-color var(--duration-base) var(--ease-out),
        border-color var(--duration-base) var(--ease-out),
        transform var(--duration-base) var(--ease-bounce);
}

@supports (backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px)) {
    .hero__arrow {
        background: rgba(255, 255, 255, 0.16);
        -webkit-backdrop-filter: blur(var(--glass-blur-md)) saturate(1.4);
        backdrop-filter: blur(var(--glass-blur-md)) saturate(1.4);
    }
}

.hero__arrow:hover {
    background: rgba(255, 255, 255, 0.95);
    border-color: #fff;
    color: var(--brand-800);
}

.hero__arrow:active {
    transform: scale(0.94);
}

.hero__arrow svg {
    width: 1.05rem;
    height: 1.05rem;
}

.hero__dots {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    list-style: none;
    margin: 0;
    padding: 0;
    /* Many slides on a narrow screen: wrap rather than overflow */
    flex-wrap: wrap;
    justify-content: flex-end;
}

.hero__dot {
    display: block;
    /* The visible dot is small, the hit area is 44px */
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    display: grid;
    place-items: center;
}

.hero__dot::after {
    content: "";
    width: 0.55rem;
    height: 0.55rem;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.45);
    border: 1px solid rgba(255, 255, 255, 0.5);
    transition:
        background-color var(--duration-base) var(--ease-out),
        width var(--duration-base) var(--ease-emphasis),
        border-radius var(--duration-base) var(--ease-out);
}

.hero__dot:hover::after {
    background: rgba(255, 255, 255, 0.8);
}

.hero__dot[aria-current="true"]::after {
    width: 1.6rem;
    border-radius: var(--radius-pill);
    background: #fff;
    border-color: #fff;
}

/* On very small screens the controls centre up. The arrows used to be dropped
   here to free width for the slide copy, but on a phone there is no longer any
   copy over the slide — see section 11 of refine.css, which lays the arrows
   out along the edges of the photograph instead. */
@media (max-width: 29.9375em) {
    .hero__controls-inner {
        justify-content: center;
    }

    .hero__dots {
        justify-content: center;
    }
}

/* --- Progress bar --------------------------------------------------- */
.hero__progress {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 4;
    height: 3px;
    background: rgba(255, 255, 255, 0.16);
    overflow: hidden;
}

.hero__progress-bar {
    height: 100%;
    width: 100%;
    background: var(--gold-500);
    transform: scaleX(0);
    transform-origin: left center;
}

.hero__progress-bar.is-running {
    animation: hero-progress var(--hero-duration, 6s) linear forwards;
}

.hero__progress-bar.is-paused {
    animation-play-state: paused;
}

@keyframes hero-progress {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
}

@media (prefers-reduced-motion: reduce) {
    .hero__progress {
        display: none;
    }
}

/* --- Empty carousel fallback ---------------------------------------- */
.hero--empty {
    min-height: clamp(20rem, 52svh, 30rem);
    place-items: center;
    background:
        radial-gradient(120% 120% at 20% 0%, var(--brand-700) 0%, var(--brand-900) 60%);
}

.hero--empty .hero__content {
    align-content: center;
    padding-block: var(--space-2xl);
    text-align: center;
}

.hero--empty .hero__copy {
    margin-inline: auto;
    justify-items: center;
}

.hero--empty .hero__eyebrow {
    justify-content: center;
}

/* =====================================================================
   6. PAGE HEADER  (interior pages)
   ===================================================================== */
.page-hero {
    position: relative;
    isolation: isolate;
    display: grid;
    align-content: center;
    min-height: clamp(11rem, 28svh, 19rem);
    padding-block: var(--space-xl);
    background: var(--brand-900);
    color: #fff;
    overflow: hidden;
}

.page-hero__bg {
    position: absolute;
    inset: 0;
    z-index: -2;
}

.page-hero__bg img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 40%;
}

.page-hero::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background:
        linear-gradient(to right, rgba(9, 88, 68, 0.90) 0%, rgba(9, 88, 68, 0.68) 60%, rgba(9, 88, 68, 0.52) 100%);
}

/* Without a background image the band becomes a bright green wash with a
   sunny glow in one corner and a cool one in the other, so an interior page
   header is cheerful rather than a slab of dark colour. */
.page-hero--plain::after {
    background:
        radial-gradient(120% 140% at 6% 0%, rgba(53, 209, 160, 0.55) 0%, rgba(12, 110, 85, 0) 58%),
        radial-gradient(70% 110% at 96% 8%, rgba(245, 181, 38, 0.30) 0%, rgba(12, 110, 85, 0) 60%),
        radial-gradient(80% 120% at 80% 100%, rgba(52, 174, 232, 0.28) 0%, rgba(12, 110, 85, 0) 62%),
        linear-gradient(140deg, var(--brand-800) 0%, var(--brand-900) 55%, var(--brand-800) 100%);
}

.page-hero__inner {
    display: grid;
    gap: var(--space-xs);
    max-width: 48rem;
}

.page-hero__title {
    font-size: var(--step-5);
    color: #fff;
    line-height: 1.08;
}

.page-hero__lede {
    font-size: var(--step-1);
    line-height: var(--leading-normal);
    color: rgba(255, 255, 255, 0.82);
    max-width: 38rem;
}

/* --- Breadcrumb ----------------------------------------------------- */
.breadcrumb {
    font-size: var(--step--2);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
}

.breadcrumb__list {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.breadcrumb__list li {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    color: rgba(255, 255, 255, 0.6);
}

.breadcrumb__list li + li::before {
    content: "/";
    color: rgba(255, 255, 255, 0.35);
}

.breadcrumb a {
    color: rgba(255, 255, 255, 0.78);
    text-decoration: none;
}

.breadcrumb a:hover {
    color: #fff;
    text-decoration: underline;
}

.breadcrumb [aria-current="page"] {
    color: var(--gold-200);
}

/* =====================================================================
   7. WELCOME / EDITORIAL SPLIT
   ===================================================================== */
.split {
    display: grid;
    gap: var(--space-lg);
    align-items: center;
}

@media (min-width: 56em) {
    .split {
        grid-template-columns: 1fr 1fr;
        gap: clamp(2.5rem, 5vw, 5rem);
    }

    .split--wide-text {
        grid-template-columns: 1.15fr 0.85fr;
    }

    .split--wide-media {
        grid-template-columns: 0.85fr 1.15fr;
    }

    /* Reverses the visual order without changing the DOM order,
       so the reading order stays correct for screen readers. */
    .split--reverse > :first-child {
        order: 2;
    }
}

.split__body > * + * {
    margin-top: var(--space-sm);
}

.split__body p {
    line-height: var(--leading-relaxed);
    color: var(--ink-700);
}

/* --- Framed image with a gold offset rule --------------------------- */
.media-frame {
    position: relative;
    isolation: isolate;
}

.media-frame__image {
    position: relative;
    z-index: 1;
    width: 100%;
    aspect-ratio: 4 / 3;
    overflow: hidden;
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-lg);
    background: var(--ink-100);
}

.media-frame__image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.media-frame::before {
    content: "";
    position: absolute;
    z-index: 0;
    inset: auto -0.75rem -0.75rem auto;
    width: 62%;
    height: 62%;
    border: 1px solid var(--gold-500);
    border-radius: var(--radius-sm);
}

/* The decorative offset is dropped on small screens where it would
   otherwise sit outside the gutter. */
@media (max-width: 35.9375em) {
    .media-frame::before {
        display: none;
    }
}

.media-frame__caption {
    margin-top: var(--space-xs);
    font-size: var(--step--1);
    color: var(--ink-500);
    font-style: italic;
}

/* --- Portrait aspect variant --------------------------------------- */
.media-frame--portrait .media-frame__image {
    aspect-ratio: 4 / 5;
}

.media-frame--square .media-frame__image {
    aspect-ratio: 1 / 1;
}

/* =====================================================================
   8. STATS STRIP
   ===================================================================== */
.stats {
    display: grid;
    gap: 1px;
    background: var(--ink-200);
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-sm);
    overflow: hidden;
    /* Two columns on a phone, four when there's room — never one tall
       column of mostly empty space. */
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 48em) {
    .stats {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

.stat {
    display: grid;
    gap: 0.2rem;
    padding: clamp(1rem, 3vw, 1.85rem) clamp(0.85rem, 2.5vw, 1.5rem);
    background: rgba(255, 255, 255, 0.82);
    text-align: center;
}

@supports (backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px)) {
    .stat {
        background: rgba(255, 255, 255, 0.62);
        -webkit-backdrop-filter: blur(var(--glass-blur-sm)) saturate(1.5);
        backdrop-filter: blur(var(--glass-blur-sm)) saturate(1.5);
    }
}

@media (prefers-reduced-transparency: reduce) {
    .stat {
        background: #fff;
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }
}

.stat__value {
    font-family: var(--font-display);
    font-size: clamp(1.4rem, 1.1rem + 1.4vw, 2.25rem);
    font-weight: 600;
    line-height: 1.05;
    letter-spacing: -0.02em;
    color: var(--brand-700);
    /* Long values such as "Nursery–X" must shrink, not overflow */
    overflow-wrap: anywhere;
}

.stat__label {
    font-size: var(--step--2);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wider);
    color: var(--ink-500);
}

.stats--on-dark {
    background: rgba(255, 255, 255, 0.14);
    border-color: rgba(255, 255, 255, 0.16);
}

.stats--on-dark .stat {
    background: transparent;
}

.stats--on-dark .stat__value {
    color: #fff;
}

.stats--on-dark .stat__label {
    color: rgba(255, 255, 255, 0.62);
}

/* =====================================================================
   8a. WELCOME
   ---------------------------------------------------------------------
   The first thing a visitor reads. It has to do three jobs at once: say who
   the school is, answer the questions a parent actually arrives with, and
   look like somebody cared.

   The composition is deliberately asymmetric — a tall portrait photograph
   with a smaller landscape one lapping over its lower corner, and a dated
   seal above them. A single centred rectangle would say "template"; this
   says a person arranged it. All three pieces are decorative in the
   accessibility sense: the prose beside them carries the meaning.

   Everything overlapping is arranged with grid areas rather than negative
   margins, so nothing escapes the section and there is nothing to unpick at
   the small breakpoint — the pieces simply stack.

   COLOUR. This section used to be white with one pale green circle behind the
   photographs, which made the school's first impression a grey page. It now
   carries a tinted ground, two washes bleeding off opposite edges, a dotted
   field, a gradient rule under the heading and three separately coloured fact
   chips. Every decorative layer is aria-hidden and sits behind the content on
   its own z-index, so none of it can interfere with reading, tapping or
   contrast: the words and the chip labels are all measured against the pale
   surface they actually sit on, not against white.
   ===================================================================== */
.welcome {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    /* A warm tint rather than white, fading back to paper at the foot so the
       next section begins cleanly. */
    background:
        linear-gradient(180deg, var(--brand-050) 0%, var(--paper-warm) 46%, var(--paper) 100%);
}

/* The green wash, under the picture side, bleeding off the top right. */
.welcome__wash {
    position: absolute;
    z-index: -1;
    top: -18%;
    right: -14%;
    width: 46rem;
    max-width: 78%;
    aspect-ratio: 1;
    border-radius: 50%;
    background:
        radial-gradient(circle at 35% 35%, var(--brand-200) 0%, transparent 62%),
        radial-gradient(circle at 70% 70%, var(--brand-100) 0%, transparent 58%);
    opacity: 0.8;
}

/* The gold wash, low and to the left, under the words. Warm against the cool
   green above it, which is what stops the section reading as monochrome. */
.welcome__wash--gold {
    top: auto;
    right: auto;
    bottom: -22%;
    left: -12%;
    width: 34rem;
    max-width: 62%;
    background:
        radial-gradient(circle at 50% 50%, var(--gold-200) 0%, transparent 64%);
    opacity: 0.5;
}

/* A faint dotted field over the whole section. Barely visible, but it gives
   the pale area a texture, so it reads as a prepared surface rather than as
   space the designer left empty. */
.welcome__grid {
    position: absolute;
    z-index: -1;
    inset: 0;
    background-image: radial-gradient(circle, var(--brand-300) 1px, transparent 1px);
    background-size: 1.5rem 1.5rem;
    opacity: 0.16;
    /* Faded out towards the foot, so it never competes with the prose. */
    mask-image: linear-gradient(180deg, #000 0%, transparent 72%);
    -webkit-mask-image: linear-gradient(180deg, #000 0%, transparent 72%);
}

.welcome__inner {
    display: grid;
    gap: clamp(2rem, 5vw, 3.5rem);
    align-items: center;
}

/* Text first, pictures second, and the text given the larger share: this is
   a reading section with an illustration, not a gallery with a caption. */
@media (min-width: 62em) {
    .welcome__inner {
        grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    }
}

/* --- The words -------------------------------------------------------- */
.welcome__body {
    display: grid;
    gap: var(--space-sm);
    /* Never wider than comfortable reading, whatever the column allows. */
    max-width: 38rem;
}

.welcome__eyebrow {
    display: flex;
    align-items: center;
    gap: 0.6em;
    margin: 0;
    font-size: var(--step--2);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-widest);
    color: var(--brand-700);
}

/* A short gold bar instead of a bullet: the same mark the hero uses, so the
   two sections feel like one hand. */
.welcome__eyebrow-mark {
    width: clamp(1.5rem, 4vw, 2.5rem);
    height: 2px;
    flex: none;
    border-radius: var(--radius-pill);
    background: linear-gradient(90deg, var(--gold-500), var(--brand-500));
}

.welcome__title {
    margin: 0;
    font-size: var(--step-5);
    line-height: 1.08;
    letter-spacing: -0.02em;
    color: var(--ink-900);
    text-wrap: balance;
}

/* A short gradient rule under the heading. It carries both hues at once, so
   the green chips and the gold one below it read as one scheme. */
.welcome__flourish {
    display: block;
    width: clamp(4rem, 14vw, 7rem);
    height: 4px;
    margin-top: 0.15rem;
    border-radius: var(--radius-pill);
    background: linear-gradient(90deg, var(--brand-600) 0%, var(--brand-400) 42%, var(--gold-500) 100%);
}

/* --- The three facts -------------------------------------------------- */
/*
 * Pills, not a list of ticks: they are labels, and they should read as
 * quickly as a badge on a shop window.
 *
 * Each carries its own palette, described by three custom properties so the
 * rules below never need to know which chip is which:
 *
 *     --chip-tint    the surface
 *     --chip-edge    the border
 *     --chip-ink     the label, always 5:1 or better on --chip-tint
 *     --chip-mark    the medallion behind the glyph
 *
 * The glyph itself is white on --chip-mark, which is a mid-weight fill in
 * every palette, so the icon is legible in all three.
 */
.welcome__facts {
    display: flex;
    flex-wrap: wrap;
    gap: 0.45rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.welcome__fact {
    /* Green, the default; overridden per chip below. */
    --chip-tint: var(--brand-050);
    --chip-edge: var(--brand-200);
    --chip-ink: var(--brand-800);
    --chip-mark: var(--brand-600);

    display: inline-flex;
    align-items: center;
    gap: 0.45em;
    padding: 0.3rem 0.8rem 0.3rem 0.35rem;
    border: 1px solid var(--chip-edge);
    border-radius: var(--radius-pill);
    background: var(--chip-tint);
    box-shadow: var(--shadow-xs);
    font-size: var(--step--2);
    font-weight: 700;
    color: var(--chip-ink);
}

/* The glyph in a filled medallion rather than loose against the tint: at this
   size a 1.4-stroke outline in a mid green turns into a smudge. */
.welcome__fact-mark {
    display: grid;
    place-items: center;
    flex: none;
    width: 1.35rem;
    height: 1.35rem;
    border-radius: 50%;
    background: var(--chip-mark);
    color: #fff;
}

.welcome__fact-mark svg {
    width: 0.8rem;
    height: 0.8rem;
}

/* Chip 1 — the affiliation. The school's own green. Label 5.1:1, glyph 4.8:1. */
.welcome__fact--1 {
    --chip-tint: var(--brand-050);
    --chip-edge: var(--brand-200);
    --chip-ink: var(--brand-800);
    --chip-mark: var(--brand-600);
}

/* Chip 2 — the class range. Gold, using the text-safe --gold-600: 5.5:1 on
   --gold-100. The medallion is white on --gold-600 (5.9:1) rather than on
   --gold-500, which would not clear 3:1. */
.welcome__fact--2 {
    --chip-tint: var(--gold-100);
    --chip-edge: var(--gold-200);
    --chip-ink: var(--gold-600);
    --chip-mark: var(--gold-600);
}

/* Chip 3 — the science stream. Deep teal, distinct from chip 1 at a glance
   without leaving the palette. 7.2:1 on --paper-deep. */
.welcome__fact--3 {
    --chip-tint: var(--paper-deep);
    --chip-edge: var(--brand-300);
    --chip-ink: #0a5c46;
    --chip-mark: var(--brand-900);
}

.welcome__prose {
    /* The prose already has its own paragraph rhythm; the grid gap would
       add a second one on top. */
    margin: 0;
}

.welcome__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs);
    margin-top: var(--space-2xs);
}

/* The outlined button sits on a tint here rather than on white, so it is
   given a solid fill of its own — a transparent outline over the wash reads
   as disabled. */
.welcome__actions .btn--outline {
    background: var(--paper);
}

.welcome__actions .btn svg {
    width: 1.1em;
    height: 1.1em;
    flex: none;
}

/* --- The pictures ----------------------------------------------------- */
/*
 * A 6x6 grid the three pieces are placed onto. Using areas rather than
 * absolute positioning means the block still has a real height, so the
 * section grows with it and nothing has to be measured.
 */
.welcome__media {
    position: relative;
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    grid-template-rows: repeat(6, auto);
}

.welcome__figure {
    margin: 0;
    overflow: hidden;
    border-radius: var(--radius-lg);
    background: var(--ink-100);
    box-shadow: var(--shadow-lg);
}

.welcome__figure img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.welcome__figure--main {
    grid-column: 1 / 6;
    grid-row: 1 / 7;
    aspect-ratio: 4 / 5;
}

.welcome__figure--inset {
    /* Laps over the lower-right corner of the main picture. */
    grid-column: 4 / 7;
    grid-row: 5 / 7;
    align-self: end;
    aspect-ratio: 4 / 3;
    border: 4px solid var(--paper);
    box-shadow: var(--shadow-xl);
}

/* --- The seal --------------------------------------------------------- */
.welcome__seal {
    grid-column: 5 / 7;
    grid-row: 1 / 2;
    align-self: start;
    justify-self: end;

    display: grid;
    place-items: center;
    gap: 0;
    width: clamp(4.5rem, 12vw, 5.75rem);
    aspect-ratio: 1;
    margin: 0;
    border-radius: 50%;
    color: #fff;
    /* Gold woven into the far end, so the seal belongs to the same scheme as
       the chips rather than being a plain green disc. */
    background: linear-gradient(140deg, var(--brand-500) 0%, var(--brand-800) 58%, var(--brand-900) 100%);
    box-shadow:
        0 0 0 3px rgba(255, 255, 255, 0.92),
        0 0 0 5px var(--gold-400),
        var(--shadow-lg);
    text-align: center;
}

.welcome__seal-since {
    font-size: 0.6rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-widest);
    color: var(--gold-200);
}

.welcome__seal-year {
    font-family: var(--font-display);
    font-size: clamp(1.25rem, 3vw, 1.6rem);
    font-weight: 600;
    line-height: 1;
}

/* A slow drift, so the seal reads as sitting above the picture rather than
   printed on it. Small enough that it is felt, not watched. */
@media (prefers-reduced-motion: no-preference) {
    .welcome__seal {
        animation: welcome-float 7s var(--ease-in-out) infinite;
    }
}

@keyframes welcome-float {
    0%, 100% { translate: 0 0; }
    50%      { translate: 0 -0.5rem; }
}

/* --- Phones ----------------------------------------------------------- */
@media (max-width: 47.9375em) {
    /* The inset picture covers a third of the main one on a narrow screen,
       which loses more than it adds. */
    .welcome__figure--inset {
        display: none;
    }

    .welcome__figure--main {
        grid-column: 1 / 7;
        /* Less tall on a phone, where a 4:5 portrait fills the whole screen
           and pushes the words out of sight. */
        aspect-ratio: 3 / 2;
    }

    .welcome__seal {
        grid-column: 5 / 7;
    }

    .welcome__title {
        font-size: var(--step-4);
    }

    /* Full-width buttons, stacked: the standard phone treatment used
       everywhere else on the site. */
    .welcome__actions {
        display: grid;
    }

    .welcome__actions .btn {
        width: 100%;
        min-height: 3.125rem;
    }
}

/* =====================================================================
   8b. ATTRIBUTE CARDS  (the three "why South Point" cards)
   ---------------------------------------------------------------------
   The one place on the site that gets a colour rotation, and it earns it:
   three parallel statements of what the school stands for, sitting side by
   side with nothing to tell them apart. Giving each its own hue makes the
   set read as three ideas rather than one long paragraph cut into thirds.

   The rest of the site keeps a single card treatment on purpose (see
   section 6 of refine.css) — this is the exception, not a new habit.

   Every card is built from four custom properties, so a card is described
   by its palette and the rules below never need to know which is which:

       --card-tint     the page-facing surface, very pale
       --card-accent   the medallion and the rule, mid-weight
       --card-deep     the medallion's far end and the heading, dark
       --card-edge     the border, between tint and accent

   Contrast was chosen, not guessed: every heading is a --card-deep on its
   own --card-tint (8:1 or better), the body copy is --ink-700 on the same
   tint, and each medallion is a white glyph on a gradient whose lightest
   point still clears 3:1. Three hues, all of them legible.
   ===================================================================== */
.attribute-cards {
    display: grid;
    gap: var(--space-sm);
    grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
}

.attribute-card {
    /* Green, from the school's own palette. Overridden per card below. */
    --card-tint: var(--brand-050);
    --card-accent: var(--brand-700);
    --card-deep: #0a5c46;
    --card-edge: var(--brand-200);

    position: relative;
    isolation: isolate;
    overflow: hidden;
    display: grid;
    /* icon · title · rule · text, with the text taking the slack so the
       cards stay the same height whatever the wording. */
    grid-template-rows: auto auto auto 1fr;
    gap: var(--space-2xs);
    padding: clamp(1.4rem, 3vw, 2rem);
    border: 1px solid var(--card-edge);
    border-radius: var(--radius-md);
    background: var(--card-tint);
    /*
     * The lift uses `translate`, not `transform`. These cards sit inside a
     * .reveal-group, whose entrance rules end with `transform: none` and are
     * declared later in this file — a transform here would be overruled by it.
     * `translate` is its own property, so the two cannot collide.
     */
    transition:
        translate var(--duration-base) var(--ease-out),
        box-shadow var(--duration-base) var(--ease-out),
        border-color var(--duration-base) var(--ease-out);
}

/* A soft wash of the card's own colour in the top corner. Large, slow and
   low-contrast: it should be felt rather than noticed. */
.attribute-card__glow {
    position: absolute;
    z-index: -1;
    top: -40%;
    right: -25%;
    width: 78%;
    aspect-ratio: 1;
    border-radius: 50%;
    background: var(--card-accent);
    opacity: 0.1;
    transition:
        transform var(--duration-slow) var(--ease-out),
        opacity var(--duration-slow) var(--ease-out);
}

.attribute-card:hover {
    translate: 0 -4px;
    border-color: var(--card-accent);
    box-shadow: var(--shadow-lg);
}

.attribute-card:hover .attribute-card__glow {
    transform: scale(1.18);
    opacity: 0.16;
}

/* --- The number ------------------------------------------------------ */
/* Set in the card's own colour at low opacity, in the far corner. It
   numbers the set without competing with the heading. */
.attribute-card__number {
    position: absolute;
    top: clamp(0.7rem, 2vw, 1.1rem);
    right: clamp(0.9rem, 2.5vw, 1.4rem);
    font-family: var(--font-display);
    font-size: var(--step-4);
    font-weight: 600;
    line-height: 1;
    color: var(--card-accent);
    opacity: 0.22;
    font-variant-numeric: tabular-nums;
}

/* --- The medallion --------------------------------------------------- */
.attribute-card__icon {
    display: grid;
    place-items: center;
    width: 3.5rem;
    height: 3.5rem;
    border-radius: 1.15rem;
    color: #fff;
    background: linear-gradient(140deg, var(--card-accent), var(--card-deep));
    /* A ring of the card's colour, so the medallion sits on the tint rather
       than being pasted onto it. */
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--card-accent) 14%, transparent);
    transition:
        transform var(--duration-base) var(--ease-bounce),
        box-shadow var(--duration-base) var(--ease-out);
}

.attribute-card:hover .attribute-card__icon {
    transform: scale(1.07);
    box-shadow: 0 0 0 9px color-mix(in srgb, var(--card-accent) 16%, transparent);
}

.attribute-card__icon svg {
    width: 1.6rem;
    height: 1.6rem;
}

/* --- Words ----------------------------------------------------------- */
.attribute-card__title {
    margin: 0;
    font-size: var(--step-2);
    line-height: var(--leading-snug);
    /* Dark enough on the pale tint to clear 8:1. */
    color: var(--card-deep);
}

/* Grows from nothing on hover: the one piece of movement that points at
   the words rather than decorating around them. */
.attribute-card__rule {
    width: 2.25rem;
    height: 3px;
    border-radius: var(--radius-pill);
    background: var(--card-accent);
    transition: width var(--duration-slow) var(--ease-emphasis);
}

.attribute-card:hover .attribute-card__rule {
    width: 4.5rem;
}

.attribute-card__text {
    margin: 0;
    color: var(--ink-700);
    line-height: var(--leading-relaxed);
}

/* =====================================================================
   8c. THE CARD PALETTES
   ---------------------------------------------------------------------
   Six palettes, defined once and used by every component that rotates
   colour: the attribute cards above and the quick links further down. One
   list means the homepage cannot end up with two different greens, and
   adding a seventh card is a matter of adding a seventh entry here.

   Each is four values, and each was measured rather than eyeballed — see
   the note in section 8b. In short: --card-deep on --card-tint clears 6.5:1
   for every one of them, --ink-700 on --card-tint clears 8:1, and white on
   either of the two darker values clears 3:1 for a glyph.

   The order runs green, amber, blue, rose, violet, teal: the school's own
   green leads, and no two neighbours are adjacent hues.
   ===================================================================== */
.attribute-card--1,
.quick-link--1 {
    --card-tint: var(--brand-050);
    --card-accent: var(--brand-700);
    --card-deep: #0a5c46;
    --card-edge: var(--brand-200);
}

.attribute-card--2,
.quick-link--2 {
    --card-tint: var(--gold-100);
    --card-accent: #a06a08;
    --card-deep: #7a4e07;
    --card-edge: var(--gold-200);
}

.attribute-card--3,
.quick-link--3 {
    --card-tint: #eef4fb;
    --card-accent: #2c6bb5;
    --card-deep: #1f4a7d;
    --card-edge: #cfe0f2;
}

.attribute-card--4,
.quick-link--4 {
    --card-tint: #fdf1f3;
    --card-accent: #a8324a;
    --card-deep: #7f2338;
    --card-edge: #f2d2d9;
}

.attribute-card--5,
.quick-link--5 {
    --card-tint: #f4f1fc;
    --card-accent: #5b46a8;
    --card-deep: #42327d;
    --card-edge: #ded6f4;
}

.attribute-card--6,
.quick-link--6 {
    --card-tint: #eafaf8;
    --card-accent: #0d7c86;
    --card-deep: #0a5b62;
    --card-edge: #bfe9e9;
}

/* color-mix is recent. Without it the medallion simply has no ring, which
   is a cosmetic loss and nothing more. */
@supports not (color: color-mix(in srgb, red 50%, blue)) {
    .attribute-card__icon,
    .attribute-card:hover .attribute-card__icon {
        box-shadow: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .attribute-card,
    .attribute-card__glow,
    .attribute-card__icon,
    .attribute-card__rule {
        transition: none;
    }

    .attribute-card:hover {
        translate: none;
    }

    .attribute-card:hover .attribute-card__glow,
    .attribute-card:hover .attribute-card__icon {
        transform: none;
    }

    /* The rule still marks the hovered card, it just arrives at once. */
    .attribute-card:hover .attribute-card__rule {
        width: 4.5rem;
    }
}

/* =====================================================================
   9. FEATURE CARDS
   ---------------------------------------------------------------------
   The plain card used across the site: the leadership messages on the
   homepage, and the card grids on the interior pages. The three coloured
   "why South Point" cards are section 8b above and no longer use this.
   ===================================================================== */
.features {
    --col-min: 18rem;
}

.feature {
    position: relative;
    isolation: isolate;
    display: grid;
    grid-template-rows: auto auto 1fr;
    gap: var(--space-xs);
    padding: clamp(1.5rem, 3.5vw, 2.35rem);
    /* Solid fallback; the glass treatment is layered on below. */
    background: rgba(255, 255, 255, 0.86);
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-lg);
    box-shadow: var(--glass-shadow);
    transition:
        border-color var(--duration-base) var(--ease-out),
        box-shadow var(--duration-base) var(--ease-out),
        transform var(--duration-base) var(--ease-out);
}

@supports (backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px)) {
    .feature {
        background: var(--glass-light);
        border-color: var(--glass-light-border);
        -webkit-backdrop-filter: blur(var(--glass-blur-md)) saturate(1.6);
        backdrop-filter: blur(var(--glass-blur-md)) saturate(1.6);
    }
}

/* The lit top edge that makes the card read as glass rather than as a
   simply translucent box. */
.feature::after {
    content: "";
    position: absolute;
    top: 0;
    left: 14%;
    right: 14%;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.95) 50%, transparent);
    pointer-events: none;
}

@media (prefers-reduced-transparency: reduce) {
    .feature {
        background: #fff;
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }
}

/* The brand bar sweeps across the top on hover. It sits just below the
   card's rounded corner so it follows the border radius. */
.feature::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    background: linear-gradient(90deg, var(--brand-600), var(--brand-400));
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform var(--duration-slow) var(--ease-emphasis);
    pointer-events: none;
    z-index: 1;
}

.feature:hover {
    border-color: rgba(255, 255, 255, 0.95);
    box-shadow: var(--glass-shadow-lg);
    transform: translateY(-3px);
}

.feature:hover::before {
    transform: scaleX(1);
}

/* The static glass sheen yields to the brand bar on hover, so the two
   never sit on top of each other. */
.feature:hover::after {
    opacity: 0;
}

.feature::after {
    transition: opacity var(--duration-base) var(--ease-out);
}

.feature__index {
    font-family: var(--font-display);
    font-size: var(--step--1);
    font-weight: 600;
    letter-spacing: var(--tracking-wider);
    color: var(--gold-600);
}

.feature__icon {
    display: grid;
    place-items: center;
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    background: var(--brand-050);
    color: var(--brand-700);
    border: 1px solid var(--brand-100);
}

.feature__icon svg {
    width: 1.35rem;
    height: 1.35rem;
}

.feature__title {
    font-size: var(--step-2);
    line-height: var(--leading-snug);
}

.feature__text {
    font-size: var(--step-0);
    line-height: var(--leading-relaxed);
    color: var(--ink-600);
}

/* =====================================================================
   10. CALL TO ACTION BAND
   ===================================================================== */
.cta-band {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    background: var(--brand-900);
    color: rgba(255, 255, 255, 0.85);
}

.cta-band::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background:
        radial-gradient(90% 140% at 85% 10%, rgba(245, 181, 38, 0.30) 0%, rgba(12, 110, 85, 0) 60%),
        radial-gradient(60% 110% at 50% 0%, rgba(166, 130, 245, 0.22) 0%, rgba(12, 110, 85, 0) 55%),
        radial-gradient(70% 120% at 0% 100%, rgba(53, 209, 160, 0.55) 0%, rgba(12, 110, 85, 0) 58%);
}

.cta-band__inner {
    display: grid;
    gap: var(--space-md);
    align-items: center;
}

@media (min-width: 52em) {
    .cta-band__inner {
        grid-template-columns: 1fr auto;
        gap: var(--space-lg);
    }
}

.cta-band__title {
    font-size: var(--step-4);
    color: #fff;
}

.cta-band__text {
    margin-top: var(--space-2xs);
    font-size: var(--step-1);
    line-height: var(--leading-normal);
    color: rgba(255, 255, 255, 0.78);
    max-width: 40rem;
}

.cta-band__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
}

/* =====================================================================
   11. QUICK LINKS
   ===================================================================== */
.quick-links {
    --col-min: 15rem;
}

/*
 * These used to be six panes of frosted white on a coloured band, which meant
 * six identical cards and a lot of blur for no gain. Each now takes one of the
 * palettes from section 8c, so the row reads as six separate destinations, and
 * the medallion carries the colour the way the attribute cards do.
 *
 * The palette is decoration: the label and the hint are the information, and
 * both are set in ink on a pale tint at 8:1 or better regardless of which
 * colour a card draws.
 */
.quick-link {
    /* Green, if the markup does not name a palette. */
    --card-tint: var(--brand-050);
    --card-accent: var(--brand-700);
    --card-deep: #0a5c46;
    --card-edge: var(--brand-200);

    position: relative;
    isolation: isolate;
    overflow: hidden;
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-sm) var(--space-md);
    background: var(--card-tint);
    border: 1px solid var(--card-edge);
    border-radius: var(--radius-md);
    text-decoration: none;
    color: var(--ink-800);
    box-shadow: var(--shadow-xs);
    /* translate, not transform: these sit in a .reveal-group whose entrance
       rules end with `transform: none`. See section 8b. */
    transition:
        border-color var(--duration-base) var(--ease-out),
        box-shadow var(--duration-base) var(--ease-out),
        translate var(--duration-base) var(--ease-out);
}

/* The accent, drawn along the left edge and growing on hover. A card that is
   nearly all pale tint needs one saturated mark to anchor it. */
.quick-link::before {
    content: "";
    position: absolute;
    z-index: -1;
    inset: 0 auto 0 0;
    width: 3px;
    background: var(--card-accent);
    transition: width var(--duration-base) var(--ease-emphasis);
}

.quick-link:hover {
    border-color: var(--card-accent);
    box-shadow: var(--shadow-md);
    translate: 0 -3px;
}

.quick-link:hover::before {
    width: 6px;
}

.quick-link__icon {
    display: grid;
    place-items: center;
    width: 2.6rem;
    height: 2.6rem;
    flex: none;
    border-radius: 0.85rem;
    color: #fff;
    background: linear-gradient(140deg, var(--card-accent), var(--card-deep));
    transition: scale var(--duration-base) var(--ease-bounce);
}

.quick-link:hover .quick-link__icon {
    scale: 1.07;
}

.quick-link__icon svg {
    width: 1.2rem;
    height: 1.2rem;
}

.quick-link__label {
    font-size: var(--step-0);
    font-weight: 600;
    line-height: 1.3;
    /* The card's own dark shade, so the label belongs to it. */
    color: var(--card-deep);
}

.quick-link__hint {
    display: block;
    margin-top: 0.15rem;
    font-size: var(--step--2);
    font-weight: 400;
    color: var(--ink-600);
}

@media (prefers-reduced-motion: reduce) {
    .quick-link,
    .quick-link::before,
    .quick-link__icon {
        transition: none;
    }

    .quick-link:hover {
        translate: none;
    }

    .quick-link:hover .quick-link__icon {
        scale: none;
    }
}

/* =====================================================================
   12. FOOTER
   ===================================================================== */
.site-footer {
    background: var(--brand-900);
    color: rgba(255, 255, 255, 0.7);
    font-size: var(--step--1);
}

.footer__main {
    display: grid;
    gap: var(--space-lg);
    padding-block: var(--space-xl);
}

/* Progressive column count: 1 → 2 → 4, so no column is ever cramped */
@media (min-width: 40em) {
    .footer__main {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--space-lg) var(--space-md);
    }
}

@media (min-width: 64em) {
    .footer__main {
        grid-template-columns: 1.5fr 1fr 1fr 1.2fr;
        gap: var(--space-lg) clamp(1.5rem, 3vw, 3rem);
    }
}

.footer__brand {
    display: grid;
    gap: var(--space-xs);
    /* Spans both columns in the 2-column layout for a balanced footer */
}

@media (min-width: 40em) and (max-width: 63.9375em) {
    .footer__brand {
        grid-column: 1 / -1;
    }
}

.footer__lockup {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    text-decoration: none;
    color: inherit;
}

/* The crest gets a white disc so it reads against the green footer, whether
   the file is the transparent outline or the full printed version. */
.footer__mark {
    width: 4.5rem;
    height: 4.5rem;
    flex: none;
    object-fit: contain;
    background: #fff;
    border-radius: 50%;
    padding: 0.45rem;
    box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.22);
    transition: transform var(--duration-slow) var(--ease-bounce);
}

.footer__lockup:hover .footer__mark {
    transform: rotate(-6deg) scale(1.05);
}

@media (prefers-reduced-motion: reduce) {
    .footer__lockup:hover .footer__mark {
        transform: none;
    }
}

.footer__name {
    font-family: var(--font-display);
    font-size: var(--step-1);
    font-weight: 600;
    line-height: 1.15;
    color: #fff;
}

.footer__affiliation {
    display: block;
    margin-top: 0.2rem;
    font-size: var(--step--2);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--gold-200);
}

.footer__about {
    line-height: var(--leading-relaxed);
    color: rgba(255, 255, 255, 0.66);
    max-width: 30rem;
}

.footer__heading {
    font-family: var(--font-body);
    font-size: var(--step--2);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wider);
    color: #fff;
    margin-bottom: var(--space-xs);
}

.footer__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.55rem;
}

.footer__list a {
    display: inline-flex;
    align-items: baseline;
    gap: 0.45rem;
    color: rgba(255, 255, 255, 0.7);
    text-decoration: none;
    transition: color var(--duration-fast) var(--ease-out);
}

.footer__list a::before {
    content: "";
    width: 0.4rem;
    height: 1px;
    flex: none;
    margin-top: 0.7em;
    background: var(--gold-500);
    opacity: 0.6;
    transition: width var(--duration-fast) var(--ease-out);
}

.footer__list a:hover {
    color: #fff;
}

.footer__list a:hover::before {
    width: 0.8rem;
    opacity: 1;
}

/* --- Contact block -------------------------------------------------- */
.footer__contact {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--space-xs);
}

.footer__contact li {
    display: grid;
    grid-template-columns: 1.15rem 1fr;
    gap: 0.6rem;
    align-items: start;
    line-height: var(--leading-normal);
}

.footer__contact svg {
    width: 1rem;
    height: 1rem;
    margin-top: 0.22em;
    color: var(--gold-200);
    flex: none;
}

.footer__contact a {
    color: rgba(255, 255, 255, 0.78);
    text-decoration: none;
    /* Long email/phone strings wrap instead of overflowing */
    overflow-wrap: anywhere;
}

.footer__contact a:hover {
    color: #fff;
    text-decoration: underline;
}

.footer__phones {
    display: grid;
    gap: 0.2rem;
}

/* --- Social icons --------------------------------------------------- */
.footer__social {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs);
    margin-top: var(--space-xs);
}

.footer__social a {
    display: grid;
    place-items: center;
    width: 2.5rem;
    height: 2.5rem;
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: 50%;
    color: rgba(255, 255, 255, 0.78);
    transition:
        background-color var(--duration-base) var(--ease-out),
        border-color var(--duration-base) var(--ease-out),
        color var(--duration-base) var(--ease-out);
}

.footer__social a:hover {
    background: #fff;
    border-color: #fff;
    color: var(--brand-800);
}

.footer__social svg {
    width: 1.05rem;
    height: 1.05rem;
}

/* --- Footer base ---------------------------------------------------- */
.footer__base {
    border-top: 1px solid rgba(255, 255, 255, 0.12);
    padding-block: var(--space-sm);
}

.footer__base-inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2xs) var(--space-sm);
    font-size: var(--step--2);
    color: rgba(255, 255, 255, 0.55);
}

.footer__legal {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2xs) var(--space-sm);
    list-style: none;
    margin: 0;
    padding: 0;
}

.footer__legal a {
    color: rgba(255, 255, 255, 0.6);
    text-decoration: none;
}

.footer__legal a:hover {
    color: #fff;
    text-decoration: underline;
}

/* =====================================================================
   13. FLASH MESSAGES / ALERTS
   ===================================================================== */
.alert {
    display: grid;
    grid-template-columns: 1.25rem 1fr;
    gap: var(--space-xs);
    align-items: start;
    padding: var(--space-sm) var(--space-md);
    border: 1px solid;
    border-radius: var(--radius-sm);
    font-size: var(--step--1);
    line-height: var(--leading-normal);
}

.alert svg {
    width: 1.15rem;
    height: 1.15rem;
    margin-top: 0.1em;
    flex: none;
}

.alert__title {
    font-weight: 700;
    display: block;
    margin-bottom: 0.15rem;
}

.alert--success {
    background: var(--success-bg);
    border-color: var(--success-border);
    color: var(--success-text);
}

.alert--error {
    background: var(--error-bg);
    border-color: var(--error-border);
    color: var(--error-text);
}

.alert--warning {
    background: var(--warning-bg);
    border-color: var(--warning-border);
    color: var(--warning-text);
}

.alert--info {
    background: var(--info-bg);
    border-color: var(--info-border);
    color: var(--info-text);
}

.flash-stack {
    display: grid;
    gap: var(--space-xs);
    margin-bottom: var(--space-md);
}

/* =====================================================================
   14. EMPTY STATES
   ===================================================================== */
.empty-state {
    display: grid;
    justify-items: center;
    gap: var(--space-xs);
    padding: clamp(2.5rem, 7vw, 4.5rem) var(--space-md);
    text-align: center;
    background: var(--paper-warm);
    border: 1px dashed var(--ink-300);
    border-radius: var(--radius-sm);
}

.empty-state__icon {
    display: grid;
    place-items: center;
    width: 3.5rem;
    height: 3.5rem;
    border-radius: 50%;
    background: #fff;
    border: 1px solid var(--ink-200);
    color: var(--ink-400);
}

.empty-state__icon svg {
    width: 1.5rem;
    height: 1.5rem;
}

.empty-state__title {
    font-size: var(--step-1);
    color: var(--ink-700);
}

.empty-state__text {
    font-size: var(--step--1);
    color: var(--ink-500);
    max-width: 30rem;
}

/* =====================================================================
   15. EDITORIAL LETTER  (Principal / Secretary desk)
   ===================================================================== */
.letter {
    display: grid;
    gap: var(--space-lg);
    align-items: start;
}

@media (min-width: 60em) {
    .letter {
        /* Portrait column is fixed-ish, letter takes the rest */
        grid-template-columns: minmax(16rem, 22rem) 1fr;
        gap: clamp(2.5rem, 4.5vw, 4.5rem);
    }

    .letter__aside {
        position: sticky;
        top: calc(var(--header-height) + var(--space-md));
    }
}

.letter__portrait {
    position: relative;
    width: 100%;
    max-width: 22rem;
    aspect-ratio: 4 / 5;
    overflow: hidden;
    border-radius: var(--radius-sm);
    background: var(--ink-100);
    box-shadow: var(--shadow-lg);
}

.letter__portrait img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center top;
}

/* Initials placeholder when no photograph exists */
.letter__portrait--empty {
    display: grid;
    place-items: center;
    background: linear-gradient(150deg, var(--brand-800), var(--brand-900));
}

.letter__initials {
    font-family: var(--font-display);
    font-size: clamp(3rem, 8vw, 5rem);
    font-weight: 600;
    color: rgba(255, 255, 255, 0.85);
    letter-spacing: 0.02em;
}

.letter__identity {
    margin-top: var(--space-sm);
    padding-top: var(--space-sm);
    border-top: 2px solid var(--gold-500);
}

.letter__name {
    font-family: var(--font-display);
    font-size: var(--step-2);
    font-weight: 600;
    color: var(--brand-800);
    line-height: 1.2;
}

.letter__role {
    display: block;
    margin-top: 0.2rem;
    font-size: var(--step--2);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wider);
    color: var(--ink-500);
}

.letter__quote {
    margin-top: var(--space-md);
    padding: var(--space-sm) var(--space-md);
    background: var(--brand-050);
    border-left: 2px solid var(--brand-600);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    font-family: var(--font-display);
    font-size: var(--step-1);
    font-style: italic;
    line-height: var(--leading-snug);
    color: var(--brand-800);
}

.letter__body {
    max-width: var(--measure);
}

.letter__salutation {
    font-family: var(--font-display);
    font-size: var(--step-2);
    line-height: var(--leading-snug);
    color: var(--ink-900);
    margin-bottom: var(--space-sm);
}

/* A restrained drop cap: editorial, not decorative */
.letter__text > p:first-of-type::first-letter {
    float: left;
    font-family: var(--font-display);
    font-size: 3.4em;
    line-height: 0.82;
    font-weight: 600;
    color: var(--brand-700);
    padding-right: 0.09em;
    padding-top: 0.06em;
}

.letter__text > * + * {
    margin-top: var(--space-sm);
}

.letter__text p {
    line-height: var(--leading-relaxed);
    color: var(--ink-700);
}

.letter__signoff {
    margin-top: var(--space-lg);
    padding-top: var(--space-md);
    border-top: 1px solid var(--ink-200);
}

.letter__signoff-text {
    color: var(--ink-600);
}

/*
 * The signed name, in maroon.
 *
 * A letter ends with a signature, and a signature is not the same kind of thing
 * as the headings above it — so this is the one place on the site that leaves the
 * green family. 10.8:1 on white, so it is legible at display size and small.
 */
.letter__signature {
    margin-top: var(--space-2xs);
    font-family: var(--font-display);
    font-size: var(--step-2);
    font-weight: 600;
    color: var(--maroon-700);
}

/* A short maroon rule beneath it, the width of a pen stroke: it finishes the
   letter without pretending to be a scanned signature. */
.letter__signature::after {
    content: "";
    display: block;
    width: 3.5rem;
    height: 2px;
    margin-top: 0.4rem;
    border-radius: var(--radius-pill);
    background: linear-gradient(90deg, var(--maroon-500), transparent);
}

.letter__signature-role {
    display: block;
    font-family: var(--font-body);
    font-size: var(--step--2);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wider);
    color: var(--ink-500);
    margin-top: 0.15rem;
}

/* =====================================================================
   16. MISSION LIST  (numbered editorial list)
   ===================================================================== */
.mission-list {
    list-style: none;
    margin: 0;
    padding: 0;
    counter-reset: mission;
    display: grid;
    gap: 1px;
    background: var(--ink-200);
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-sm);
    overflow: hidden;
}

.mission-list__item {
    counter-increment: mission;
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-sm);
    align-items: baseline;
    padding: clamp(1rem, 2.5vw, 1.5rem) clamp(1rem, 3vw, 2rem);
    background: #fff;
    transition: background-color var(--duration-base) var(--ease-out);
}

.mission-list__item:hover {
    background: var(--brand-050);
}

.mission-list__item::before {
    content: counter(mission, decimal-leading-zero);
    font-family: var(--font-display);
    font-size: var(--step-1);
    font-weight: 600;
    color: var(--gold-600);
    line-height: 1.3;
    font-variant-numeric: tabular-nums;
}

.mission-list__text {
    font-size: var(--step-1);
    line-height: var(--leading-normal);
    color: var(--ink-700);
}

/* --- Simple tick list ----------------------------------------------- */
.tick-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--space-xs);
}

.tick-list li {
    display: grid;
    grid-template-columns: 1.15rem 1fr;
    gap: var(--space-xs);
    align-items: start;
    line-height: var(--leading-normal);
    color: var(--ink-700);
}

.tick-list li::before {
    content: "";
    width: 1.15rem;
    height: 1.15rem;
    margin-top: 0.15em;
    border-radius: 50%;
    background: var(--brand-050) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%230a8262' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E") center / 0.75rem no-repeat;
    border: 1px solid var(--brand-100);
    flex: none;
}

/* Two columns when the list is long and there is room */
@media (min-width: 44em) {
    .tick-list--columns {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--space-xs) var(--space-lg);
    }
}

/* =====================================================================
   17. ANTHEM & PLEDGE  (typography-led layouts)
   ===================================================================== */
.verse-panel {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    padding: clamp(2rem, 6vw, 4.5rem) clamp(1.25rem, 5vw, 4rem);
    background: #fff;
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-sm);
    text-align: center;
}

/* Oversized quotation mark, used sparingly as a watermark */
.verse-panel::before {
    content: "\201C";
    position: absolute;
    top: -0.35em;
    left: 0.15em;
    z-index: -1;
    font-family: var(--font-display);
    font-size: clamp(9rem, 26vw, 18rem);
    line-height: 1;
    color: var(--brand-050);
    pointer-events: none;
    user-select: none;
}

.verse-panel__title {
    font-size: var(--step-4);
    color: var(--brand-800);
    line-height: 1.12;
}

.verse-panel__subtitle {
    display: block;
    margin-top: var(--space-2xs);
    font-family: var(--font-display);
    font-size: var(--step-1);
    font-style: italic;
    font-weight: 400;
    color: var(--gold-600);
    letter-spacing: 0.01em;
}

.verse-panel__rule {
    width: clamp(2.5rem, 8vw, 4rem);
    height: 2px;
    background: var(--gold-500);
    border: 0;
    margin: var(--space-md) auto;
}

/* The anthem: each line on its own row, centred, generously led */
.verse {
    display: grid;
    gap: clamp(0.35rem, 1.4vw, 0.75rem);
    margin: 0 auto;
    max-width: 34rem;
    list-style: none;
    padding: 0;
}

/* Every line of the anthem is set identically — it is one continuous verse,
   so no line is singled out with a different colour, weight or style. */
.verse__line {
    font-family: var(--font-display);
    font-size: clamp(1.05rem, 0.92rem + 0.75vw, 1.5rem);
    font-weight: 600;
    line-height: var(--leading-snug);
    color: var(--ink-800);
    letter-spacing: 0.005em;
}

/* The anthem has no heading inside the panel, so the rule at the top does
   the work of announcing it. */
.verse-panel--anthem .verse-panel__rule {
    margin-top: 0;
}

.verse-panel__note {
    margin-top: var(--space-lg);
    font-size: var(--step--1);
    color: var(--ink-500);
    font-style: italic;
}

/* The pledge: numbered statements, left aligned for readability */
.pledge {
    display: grid;
    gap: var(--space-md);
    margin: 0 auto;
    max-width: 50rem;
    list-style: none;
    padding: 0;
    counter-reset: pledge;
    text-align: left;
}

.pledge__item {
    counter-increment: pledge;
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-sm);
    align-items: baseline;
}

.pledge__item::before {
    content: counter(pledge);
    display: grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    flex: none;
    border-radius: 50%;
    background: var(--brand-050);
    border: 1px solid var(--brand-100);
    font-family: var(--font-display);
    font-size: var(--step--1);
    font-weight: 600;
    color: var(--brand-700);
    align-self: start;
    margin-top: 0.15em;
}

.pledge__text {
    font-family: var(--font-display);
    font-size: clamp(1.02rem, 0.94rem + 0.5vw, 1.32rem);
    line-height: var(--leading-normal);
    color: var(--ink-800);
}

/* =====================================================================
   18. GALLERY
   ===================================================================== */
.gallery-filters {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs);
    margin-bottom: var(--space-lg);
}

.gallery-filter {
    display: inline-flex;
    align-items: center;
    gap: 0.45em;
    /* 44px: a row of pills is easy to mis-tap when they are shorter. */
    min-height: 2.75rem;
    padding: 0.45rem 1.05rem;
    background: #fff;
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-pill);
    font-size: var(--step--1);
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--ink-600);
    text-decoration: none;
    white-space: nowrap;
    transition:
        background-color var(--duration-fast) var(--ease-out),
        border-color var(--duration-fast) var(--ease-out),
        color var(--duration-fast) var(--ease-out);
}

.gallery-filter:hover {
    border-color: var(--brand-200);
    color: var(--brand-800);
}

.gallery-filter[aria-current="true"] {
    background: var(--brand-700);
    border-color: var(--brand-700);
    color: #fff;
}

.gallery-filter__count {
    font-size: var(--step--2);
    opacity: 0.7;
    font-variant-numeric: tabular-nums;
}

/* --- Grid ------------------------------------------------------------
   A deliberate, evenly-spaced grid rather than a ragged masonry: it
   reads as designed, and it never leaves odd gaps at any width. */
.gallery-grid {
    display: grid;
    gap: clamp(0.5rem, 1.5vw, 1rem);
    grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr));
}

/* Two columns from 480px: photographs stay large enough to enjoy */
@media (min-width: 30em) {
    .gallery-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 48em) {
    .gallery-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

@media (min-width: 75em) {
    .gallery-grid {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

.gallery-item {
    position: relative;
    display: block;
    width: 100%;
    padding: 0;
    overflow: hidden;
    border-radius: var(--radius-sm);
    background: var(--ink-100);
    border: 0;
    cursor: zoom-in;
    aspect-ratio: 4 / 3;
}

.gallery-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--duration-slower) var(--ease-out);
}

.gallery-item:hover img,
.gallery-item:focus-visible img {
    transform: scale(1.05);
}

/* The overlay carries no text — there are no titles or albums — so it is a
   soft brand wash with a magnifier, signalling that the photograph opens
   larger when clicked. */
.gallery-item__veil {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    background: rgba(12, 110, 85, 0.48);
    opacity: 0;
    transition: opacity var(--duration-base) var(--ease-out);
}

.gallery-item:hover .gallery-item__veil,
.gallery-item:focus-visible .gallery-item__veil {
    opacity: 1;
}

.gallery-item__zoom {
    display: grid;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.95);
    color: var(--brand-800);
    transform: scale(0.85);
    transition: transform var(--duration-base) var(--ease-emphasis);
}

.gallery-item:hover .gallery-item__zoom,
.gallery-item:focus-visible .gallery-item__zoom {
    transform: scale(1);
}

.gallery-item__zoom svg {
    width: 1.15rem;
    height: 1.15rem;
}

/* Touch devices have no hover, so an affordance that only appears on hover
   serves no purpose — the overlay is simply left off. */
@media (hover: none) {
    .gallery-item__veil {
        opacity: 0;
    }
}

/* =====================================================================
   19. LIGHTBOX
   ===================================================================== */
.lightbox {
    position: fixed;
    inset: 0;
    z-index: var(--z-overlay);
    display: grid;
    grid-template-rows: auto 1fr auto;
    background: rgba(7, 62, 47, 0.96);
    opacity: 0;
    visibility: hidden;
    transition:
        opacity var(--duration-base) var(--ease-out),
        visibility var(--duration-base);
    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
}

.lightbox.is-open {
    opacity: 1;
    visibility: visible;
}

.lightbox__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    padding: var(--space-xs) var(--gutter);
    color: rgba(255, 255, 255, 0.72);
    font-size: var(--step--1);
}

.lightbox__counter {
    font-variant-numeric: tabular-nums;
    letter-spacing: var(--tracking-wide);
}

.lightbox__close {
    display: grid;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    flex: none;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, 0.25);
    color: #fff;
    transition:
        background-color var(--duration-fast) var(--ease-out),
        border-color var(--duration-fast) var(--ease-out);
}

.lightbox__close:hover {
    background: rgba(255, 255, 255, 0.14);
    border-color: rgba(255, 255, 255, 0.5);
}

.lightbox__close svg {
    width: 1.1rem;
    height: 1.1rem;
}

.lightbox__stage {
    position: relative;
    display: grid;
    place-items: center;
    min-height: 0;
    padding-inline: var(--gutter);
}

.lightbox__figure {
    margin: 0;
    display: grid;
    gap: var(--space-xs);
    justify-items: center;
    max-height: 100%;
    min-height: 0;
}

.lightbox__image {
    max-width: 100%;
    /* Fits the stage without ever forcing the page to scroll */
    max-height: min(72svh, 48rem);
    width: auto;
    height: auto;
    object-fit: contain;
    border-radius: var(--radius-sm);
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);
    background: rgba(255, 255, 255, 0.04);
}

.lightbox__caption {
    max-width: 44rem;
    text-align: center;
    font-size: var(--step--1);
    line-height: var(--leading-normal);
    color: rgba(255, 255, 255, 0.78);
}

.lightbox__caption strong {
    display: block;
    color: #fff;
    font-size: var(--step-0);
    margin-bottom: 0.15rem;
}

.lightbox__nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    display: grid;
    place-items: center;
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, 0.25);
    background: rgba(0, 0, 0, 0.3);
    color: #fff;
    transition:
        background-color var(--duration-fast) var(--ease-out),
        border-color var(--duration-fast) var(--ease-out);
}

.lightbox__nav:hover {
    background: rgba(255, 255, 255, 0.92);
    border-color: #fff;
    color: var(--brand-900);
}

.lightbox__nav svg {
    width: 1.15rem;
    height: 1.15rem;
}

.lightbox__nav--prev { left: max(0.5rem, calc(var(--gutter) - 2.5rem)); }
.lightbox__nav--next { right: max(0.5rem, calc(var(--gutter) - 2.5rem)); }

.lightbox__hint {
    padding: var(--space-xs) var(--gutter) var(--space-sm);
    text-align: center;
    font-size: var(--step--2);
    letter-spacing: var(--tracking-wide);
    color: rgba(255, 255, 255, 0.45);
}

/* On phones the arrows drop to the lower corners so they never cover the
   photograph, and the keyboard hint is replaced by a swipe hint. */
@media (max-width: 47.9375em) {
    .lightbox__stage {
        align-items: center;
    }

    .lightbox__nav {
        top: auto;
        bottom: 0;
        transform: none;
        width: 2.875rem;
        height: 2.875rem;
        background: rgba(0, 0, 0, 0.55);
    }

    .lightbox__nav--prev { left: var(--gutter); }
    .lightbox__nav--next { right: var(--gutter); }

    .lightbox__image {
        max-height: min(58svh, 32rem);
    }

    .lightbox__hint-text {
        display: none;
    }

    .lightbox__hint::before {
        content: "Swipe to browse · Swipe down to close";
    }
}

/* =====================================================================
   20. FACULTY
   ===================================================================== */
.faculty-group + .faculty-group {
    margin-top: var(--space-xl);
}

.group-heading {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin-bottom: var(--space-md);
}

.group-heading__text {
    font-size: var(--step-2);
    color: var(--brand-800);
    white-space: nowrap;
}

.group-heading::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--ink-200);
}

.group-heading__count {
    font-size: var(--step--2);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--ink-400);
    white-space: nowrap;
}

.faculty-grid {
    display: grid;
    gap: var(--space-md);
    grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr));
}

@media (min-width: 34em) {
    .faculty-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 56em) {
    .faculty-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

@media (min-width: 80em) {
    .faculty-grid {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

.faculty-card {
    display: grid;
    grid-template-rows: auto 1fr;
    background: #fff;
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-sm);
    overflow: hidden;
    transition:
        border-color var(--duration-base) var(--ease-out),
        box-shadow var(--duration-base) var(--ease-out),
        transform var(--duration-base) var(--ease-out);
}

.faculty-card:hover {
    border-color: var(--brand-200);
    box-shadow: var(--shadow-md);
    transform: translateY(-3px);
}

.faculty-card__photo {
    position: relative;
    aspect-ratio: 1 / 1;
    background: var(--ink-100);
    overflow: hidden;
}

.faculty-card__photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center top;
    transition: transform var(--duration-slower) var(--ease-out);
}

.faculty-card:hover .faculty-card__photo img {
    transform: scale(1.04);
}

.faculty-card__placeholder {
    display: grid;
    place-items: center;
    width: 100%;
    height: 100%;
    background: linear-gradient(150deg, var(--brand-700), var(--brand-900));
    font-family: var(--font-display);
    font-size: clamp(2rem, 8vw, 3rem);
    font-weight: 600;
    color: rgba(255, 255, 255, 0.82);
    letter-spacing: 0.02em;
}

.faculty-card__body {
    display: grid;
    gap: 0.3rem;
    align-content: start;
    padding: var(--space-sm) var(--space-md) var(--space-md);
}

.faculty-card__name {
    font-size: var(--step-1);
    line-height: var(--leading-snug);
    color: var(--ink-900);
}

.faculty-card__role {
    font-size: var(--step--1);
    font-weight: 600;
    color: var(--brand-700);
    line-height: 1.35;
}

.faculty-card__qual {
    font-size: var(--step--2);
    color: var(--ink-500);
    letter-spacing: 0.01em;
}

.faculty-card__bio {
    margin-top: var(--space-2xs);
    padding-top: var(--space-2xs);
    border-top: 1px solid var(--ink-100);
    font-size: var(--step--1);
    line-height: var(--leading-normal);
    color: var(--ink-600);
}

/* =====================================================================
   21. CLASS DETAILS
   ===================================================================== */
.class-grid {
    display: grid;
    gap: var(--space-md);
    grid-template-columns: repeat(auto-fill, minmax(min(17rem, 100%), 1fr));
}

@media (min-width: 42em) {
    .class-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 68em) {
    .class-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.class-card {
    display: grid;
    grid-template-rows: auto 1fr auto;
    gap: var(--space-xs);
    padding: clamp(1.25rem, 3vw, 1.85rem);
    background: #fff;
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-sm);
    transition:
        border-color var(--duration-base) var(--ease-out),
        box-shadow var(--duration-base) var(--ease-out);
}

.class-card:hover {
    border-color: var(--brand-200);
    box-shadow: var(--shadow-sm);
}

.class-card__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-xs);
    padding-bottom: var(--space-xs);
    border-bottom: 1px solid var(--ink-100);
}

.class-card__name {
    font-size: var(--step-2);
    color: var(--brand-800);
    line-height: 1.15;
}

.class-card__stage {
    font-size: var(--step--2);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--ink-400);
    text-align: right;
    white-space: nowrap;
}

.class-card__text {
    font-size: var(--step--1);
    line-height: var(--leading-relaxed);
    color: var(--ink-600);
}

.class-card__section {
    margin-top: var(--space-2xs);
}

.class-card__label {
    display: block;
    margin-bottom: 0.35rem;
    font-size: var(--step--2);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wider);
    color: var(--ink-500);
}

.chip-list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.chip {
    padding: 0.25rem 0.65rem;
    background: var(--paper-warm);
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-xs);
    font-size: var(--step--2);
    color: var(--ink-600);
    line-height: 1.5;
}

.class-card__teacher {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: var(--space-xs);
    padding-top: var(--space-xs);
    border-top: 1px solid var(--ink-100);
    font-size: var(--step--1);
    color: var(--ink-600);
}

.class-card__teacher svg {
    width: 1rem;
    height: 1rem;
    flex: none;
    color: var(--brand-600);
}

/* =====================================================================
   22. NEWS / VIDEO CARDS
   ===================================================================== */
.video-grid {
    display: grid;
    gap: var(--space-md);
    /* 1 column on phones, 2 on tablets, 3 on desktop */
    grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 40em) {
    .video-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 66em) {
    .video-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.video-card {
    display: grid;
    grid-template-rows: auto 1fr;
    background: #fff;
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-sm);
    overflow: hidden;
    transition:
        border-color var(--duration-base) var(--ease-out),
        box-shadow var(--duration-base) var(--ease-out);
}

.video-card:hover {
    border-color: var(--brand-200);
    box-shadow: var(--shadow-md);
}

.video-card__media {
    position: relative;
    aspect-ratio: 16 / 9;
    background: var(--ink-900);
    overflow: hidden;
}

.video-card__media img,
.video-card__media video,
.video-card__media iframe {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border: 0;
}

/* Poster + play button, replaced by the real player on activation */
.video-card__poster {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    width: 100%;
    padding: 0;
    border: 0;
    background: var(--ink-900);
    cursor: pointer;
}

.video-card__poster img {
    position: absolute;
    inset: 0;
    transition: transform var(--duration-slower) var(--ease-out), opacity var(--duration-base) var(--ease-out);
}

.video-card__poster:hover img {
    transform: scale(1.04);
    opacity: 0.85;
}

.video-card__play {
    position: relative;
    z-index: 1;
    display: grid;
    place-items: center;
    width: 3.75rem;
    height: 3.75rem;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.92);
    color: var(--brand-800);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
    transition:
        transform var(--duration-base) var(--ease-emphasis),
        background-color var(--duration-base) var(--ease-out);
}

.video-card__poster:hover .video-card__play {
    transform: scale(1.08);
    background: #fff;
}

.video-card__play svg {
    width: 1.35rem;
    height: 1.35rem;
    margin-left: 0.15rem;
}

.video-card__placeholder {
    display: grid;
    place-items: center;
    width: 100%;
    height: 100%;
    background: linear-gradient(150deg, var(--brand-800), var(--brand-900));
    color: rgba(255, 255, 255, 0.55);
}

.video-card__placeholder svg {
    width: 2.5rem;
    height: 2.5rem;
}

.video-card__body {
    display: grid;
    gap: 0.4rem;
    align-content: start;
    padding: var(--space-sm) var(--space-md) var(--space-md);
}

.video-card__date {
    font-size: var(--step--2);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--gold-600);
}

.video-card__title {
    font-size: var(--step-1);
    line-height: var(--leading-snug);
    color: var(--ink-900);
}

.video-card__text {
    font-size: var(--step--1);
    line-height: var(--leading-normal);
    color: var(--ink-600);
}

.video-card__link {
    margin-top: var(--space-2xs);
}

/* =====================================================================
   23. DOCUMENTS  (mandatory public disclosure)
   ===================================================================== */
.doc-group + .doc-group {
    margin-top: var(--space-xl);
}

.doc-list {
    display: grid;
    gap: 1px;
    background: var(--ink-200);
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-sm);
    overflow: hidden;
}

.doc-row {
    display: grid;
    gap: var(--space-xs);
    align-items: center;
    padding: clamp(0.9rem, 2.5vw, 1.35rem) clamp(1rem, 3vw, 1.75rem);
    background: #fff;
    transition: background-color var(--duration-base) var(--ease-out);
}

/* Icon + text + action, collapsing to two rows on narrow screens */
@media (min-width: 40em) {
    .doc-row {
        grid-template-columns: auto 1fr auto;
        gap: var(--space-md);
    }
}

.doc-row:hover {
    background: var(--brand-050);
}

.doc-row__icon {
    display: grid;
    place-items: center;
    width: 2.5rem;
    height: 2.5rem;
    flex: none;
    border-radius: var(--radius-xs);
    background: var(--brand-050);
    border: 1px solid var(--brand-100);
    color: var(--brand-700);
}

.doc-row__icon svg {
    width: 1.15rem;
    height: 1.15rem;
}

.doc-row__body {
    min-width: 0;
}

.doc-row__title {
    font-size: var(--step-0);
    font-weight: 600;
    line-height: var(--leading-snug);
    color: var(--ink-900);
}

.doc-row__text {
    margin-top: 0.2rem;
    font-size: var(--step--1);
    line-height: var(--leading-normal);
    color: var(--ink-600);
}

.doc-row__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem var(--space-sm);
    margin-top: 0.35rem;
    font-size: var(--step--2);
    color: var(--ink-400);
    letter-spacing: 0.01em;
}

.doc-row__action {
    flex: none;
}

/* =====================================================================
   24. FORMS
   ---------------------------------------------------------------------
   Section 24 was RESULT ANALYSIS: the summary cards, the generic
   .data-table / .table-scroll pair and the .pass-bar meter. All of it went
   with that page, and nothing else on the site used any of it.
   ===================================================================== */
.form-panel {
    padding: clamp(1.5rem, 4vw, 2.75rem);
    background: #fff;
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-sm);
}

.form-grid {
    display: grid;
    gap: var(--space-md);
}

@media (min-width: 40em) {
    .form-grid--two {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/*
 * The `hidden` attribute has to win against every display rule in this file.
 *
 * A browser's own stylesheet says `[hidden] { display: none }`, but that is
 * weaker than any author rule — so `.field { display: grid }` below silently
 * un-hid every field marked hidden, and the conditional stream field on the
 * enquiry form stayed on screen whatever class was chosen. Declared once, up
 * front, with !important so no later component rule can undo it again.
 */
[hidden] {
    display: none !important;
}

.field {
    display: grid;
    gap: 0.4rem;
    min-width: 0;
}

.field--full {
    grid-column: 1 / -1;
}

.field__label {
    font-size: var(--step--1);
    font-weight: 600;
    color: var(--ink-800);
    letter-spacing: 0.01em;
}

.field__required {
    color: var(--brand-600);
    margin-left: 0.15em;
}

/* A quiet "optional" badge beside a label reads faster than the absence of
   an asterisk, which a visitor has to notice to interpret. */
.field__optional {
    display: inline-block;
    margin-left: 0.4em;
    padding: 0.05rem 0.4rem;
    border-radius: var(--radius-pill);
    background: var(--ink-100);
    font-size: var(--step--2);
    font-weight: 600;
    text-transform: lowercase;
    letter-spacing: 0;
    /* 5.7:1 on --ink-100. */
    color: var(--ink-600);
}

.field__hint {
    font-size: var(--step--2);
    color: var(--ink-500);
    line-height: var(--leading-normal);
}

.field__hint svg {
    width: 0.9em;
    height: 0.9em;
    margin-right: 0.15em;
    vertical-align: -0.1em;
    color: var(--brand-600);
}

.input,
.textarea,
.select {
    width: 100%;
    /* 16px minimum on mobile prevents iOS from zooming on focus */
    min-height: 2.875rem;
    padding: 0.7rem 0.9rem;
    font-family: var(--font-body);
    font-size: max(1rem, var(--step-0));
    line-height: 1.45;
    color: var(--ink-900);
    background: #fff;
    border: 1px solid var(--ink-300);
    border-radius: var(--radius-sm);
    transition:
        border-color var(--duration-fast) var(--ease-out),
        box-shadow var(--duration-fast) var(--ease-out);
    appearance: none;
}

.textarea {
    min-height: 8rem;
    resize: vertical;
    line-height: var(--leading-normal);
}

.select {
    padding-right: 2.5rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%23575e56' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.5L6 6.5l5-5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.9rem center;
    background-size: 0.7rem;
    cursor: pointer;
}

.input:hover,
.textarea:hover,
.select:hover {
    border-color: var(--ink-400);
}

.input:focus,
.textarea:focus,
.select:focus {
    outline: none;
    border-color: var(--brand-600);
    box-shadow: 0 0 0 3px var(--brand-100);
}

.input::placeholder,
.textarea::placeholder {
    color: var(--ink-400);
}

.input[aria-invalid="true"],
.textarea[aria-invalid="true"],
.select[aria-invalid="true"] {
    border-color: #c0392b;
}

.input[aria-invalid="true"]:focus,
.textarea[aria-invalid="true"]:focus,
.select[aria-invalid="true"]:focus {
    box-shadow: 0 0 0 3px rgba(192, 57, 43, 0.14);
}

.field__error {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: var(--step--2);
    font-weight: 600;
    color: var(--error-text);
}

.field__error svg {
    width: 0.9rem;
    height: 0.9rem;
    flex: none;
}

/* --- Checkbox / radio ----------------------------------------------- */
.check {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-xs);
    align-items: start;
    /* The whole row is a comfortable touch target */
    padding: 0.35rem 0;
    cursor: pointer;
}

.check__input {
    width: 1.15rem;
    height: 1.15rem;
    margin: 0.2em 0 0;
    accent-color: var(--brand-600);
    flex: none;
    cursor: pointer;
}

.check__text {
    font-size: var(--step--1);
    line-height: var(--leading-normal);
    color: var(--ink-700);
}

.form-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    align-items: center;
    margin-top: var(--space-md);
    padding-top: var(--space-md);
    border-top: 1px solid var(--ink-100);
}

.form-actions--end {
    justify-content: flex-end;
}

/* On the narrowest screens buttons go full width so labels never clip */
/* 25.9375em, not 26em: refine.css turns the gallery and faculty grids to two
   columns at min-width 26em, and a max- and a min- query sharing a value both
   fire on the pixel they meet at. The .9375em offset is the house convention
   everywhere else (47.9375em/48em, 29.9375em/30em). */
@media (max-width: 25.9375em) {
    .form-actions .btn {
        width: 100%;
    }
}

/* =====================================================================
   24b. THE CLASS RANGE BAND
   ---------------------------------------------------------------------
   Three chips stating how far the school goes, used on the About,
   Admission and Class Details pages. It reuses .welcome__fact from
   section 8a rather than defining a second chip treatment, so the three
   pages and the homepage all say it the same way.
   ===================================================================== */
.class-range {
    display: grid;
    gap: var(--space-2xs);
    margin: var(--space-md) 0 var(--space-lg);
}

.class-range__note {
    margin: 0;
    font-size: var(--step--1);
    /* 4.8:1 on white, 4.5:1 on --paper-warm. */
    color: var(--ink-600);
}

/* =====================================================================
   25a. THE ADMISSION ENQUIRY FORM
   ---------------------------------------------------------------------
   A long single grid of inputs reads as paperwork. The same fields grouped
   into three named steps read as a short conversation, and — more usefully —
   a parent on a phone can see how much is left.

   Nothing here is a wizard: every field is on the page at once and the form
   submits in one go. The steps are signposting, not state.
   ===================================================================== */

/* The summary above the form: what is going to be asked for. */
.enquiry-steps {
    display: grid;
    gap: var(--space-2xs);
    margin: 0 0 var(--space-md);
    padding: 0;
    list-style: none;
}

@media (min-width: 40em) {
    .enquiry-steps {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: var(--space-xs);
    }
}

.enquiry-steps__item {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    padding: 0.6rem 0.8rem;
    border: 1px solid var(--brand-100);
    border-radius: var(--radius-md);
    background: linear-gradient(135deg, var(--brand-050), var(--paper));
}

.enquiry-steps__mark {
    display: grid;
    place-items: center;
    flex: none;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    color: #fff;
    background: linear-gradient(140deg, var(--brand-600), var(--brand-900));
}

.enquiry-steps__mark svg {
    width: 1rem;
    height: 1rem;
}

.enquiry-steps__text {
    display: grid;
    gap: 0.1rem;
    min-width: 0;
}

.enquiry-steps__title {
    font-size: var(--step--1);
    font-weight: 700;
    color: var(--brand-800);
}

.enquiry-steps__hint {
    font-size: var(--step--2);
    color: var(--ink-500);
}

/* --- The panel -------------------------------------------------------- */
/* A gold seam along the top edge, so the form reads as the point of the
   page rather than as another white card on it. */
.form-panel--enquiry {
    position: relative;
    overflow: hidden;
}

.form-panel--enquiry::before {
    content: "";
    position: absolute;
    inset: 0 0 auto;
    height: 4px;
    background: linear-gradient(90deg, var(--brand-600), var(--gold-500), var(--brand-500));
}

/* --- A step ----------------------------------------------------------- */
/*
 * A real <fieldset>, so the grouping is announced rather than merely drawn.
 * Browsers give fieldsets a border and padding of their own, and a min-width
 * that breaks grid children, so all three are reset.
 */
.form-step {
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

.form-step + .form-step {
    margin-top: var(--space-lg);
    padding-top: var(--space-md);
    border-top: 1px dashed var(--ink-200);
}

.form-step__legend {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    /* A legend is laid out outside the normal flow by default; a full width
       keeps it on its own line above the fields in every browser. */
    width: 100%;
    margin-bottom: var(--space-sm);
    padding: 0;
}

.form-step__number {
    display: grid;
    place-items: center;
    flex: none;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    background: var(--brand-100);
    font-family: var(--font-display);
    font-size: var(--step--1);
    font-weight: 600;
    /* 6.1:1 on --brand-100. */
    color: var(--brand-900);
}

.form-step__title {
    display: block;
    font-family: var(--font-display);
    font-size: var(--step-1);
    font-weight: 600;
    line-height: 1.2;
    color: var(--ink-900);
}

.form-step__hint {
    display: block;
    margin-top: 0.1rem;
    font-size: var(--step--2);
    color: var(--ink-500);
}

/* --- The stream field ------------------------------------------------- */
/*
 * Shown only once Class XI or XII is chosen. The tint marks it as having
 * appeared in response to something the visitor did, rather than as a field
 * they somehow missed.
 */
/* Padded inwards rather than bled outwards with negative margins: this is a
   grid item, and a negative inline margin would push it past the panel's
   padding on a narrow screen. */
.field--stream {
    padding: var(--space-2xs) var(--space-xs) var(--space-xs);
    border: 1px solid var(--gold-200);
    border-radius: var(--radius-md);
    background: var(--gold-100);
}

.field--stream .field__label {
    color: var(--gold-600);
}

@media (prefers-reduced-motion: no-preference) {
    .field--stream:not([hidden]) {
        animation: stream-appear var(--duration-base) var(--ease-out) both;
    }
}

@keyframes stream-appear {
    from {
        opacity: 0;
        translate: 0 -0.4rem;
    }
    to {
        opacity: 1;
        translate: 0 0;
    }
}

/* --- The submit row --------------------------------------------------- */
.form-actions--enquiry .btn svg {
    width: 1.1em;
    height: 1.1em;
}

/* Honeypot: hidden from people, visible to naive bots */
.honeypot {
    position: absolute !important;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
    opacity: 0;
}

/* =====================================================================
   26. CONTACT / INFO PANELS
   ===================================================================== */
.info-panel {
    padding: clamp(1.5rem, 4vw, 2.5rem);
    background: var(--brand-900);
    color: rgba(255, 255, 255, 0.78);
    border-radius: var(--radius-sm);
}

.info-panel__title {
    font-size: var(--step-2);
    color: #fff;
    margin-bottom: var(--space-xs);
}

.info-panel__list {
    list-style: none;
    margin: var(--space-md) 0 0;
    padding: 0;
    display: grid;
    gap: var(--space-sm);
}

.info-panel__list li {
    display: grid;
    grid-template-columns: 1.25rem 1fr;
    gap: var(--space-xs);
    align-items: start;
}

.info-panel__list svg {
    width: 1.05rem;
    height: 1.05rem;
    margin-top: 0.2em;
    color: var(--gold-200);
    flex: none;
}

.info-panel__label {
    display: block;
    font-size: var(--step--2);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: rgba(255, 255, 255, 0.5);
    margin-bottom: 0.1rem;
}

.info-panel__value {
    font-size: var(--step--1);
    line-height: var(--leading-normal);
    color: #fff;
    overflow-wrap: anywhere;
}

.info-panel__value a {
    color: #fff;
    text-decoration: none;
}

.info-panel__value a:hover {
    text-decoration: underline;
}

/* =====================================================================
   27. PROCESS STEPS
   ===================================================================== */
.steps {
    display: grid;
    gap: var(--space-md);
    counter-reset: step;
    grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
}

.step {
    counter-increment: step;
    position: relative;
    display: grid;
    gap: var(--space-2xs);
    align-content: start;
    padding-top: var(--space-md);
    border-top: 2px solid var(--ink-200);
    transition: border-color var(--duration-base) var(--ease-out);
}

.step:hover {
    border-top-color: var(--brand-600);
}

.step::before {
    content: counter(step, decimal-leading-zero);
    font-family: var(--font-display);
    font-size: var(--step-2);
    font-weight: 600;
    line-height: 1;
    color: var(--gold-600);
    font-variant-numeric: tabular-nums;
}

.step__title {
    font-size: var(--step-1);
    line-height: var(--leading-snug);
}

.step__text {
    font-size: var(--step--1);
    line-height: var(--leading-relaxed);
    color: var(--ink-600);
}

/* =====================================================================
   28. STAGE CARDS  (curriculum)
   ===================================================================== */
.stage-list {
    display: grid;
    gap: var(--space-md);
}

.stage {
    display: grid;
    gap: var(--space-xs);
    padding: clamp(1.35rem, 3.5vw, 2.25rem);
    background: #fff;
    border: 1px solid var(--ink-200);
    border-left: 3px solid var(--brand-600);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    transition: box-shadow var(--duration-base) var(--ease-out);
}

.stage:hover {
    box-shadow: var(--shadow-sm);
}

.stage__title {
    font-size: var(--step-2);
    color: var(--brand-800);
    line-height: var(--leading-snug);
}

.stage__text {
    font-size: var(--step-0);
    line-height: var(--leading-relaxed);
    color: var(--ink-600);
    max-width: var(--measure);
}

@media (min-width: 60em) {
    .stage {
        grid-template-columns: minmax(12rem, 22rem) 1fr;
        gap: var(--space-lg);
        align-items: start;
    }
}

/* =====================================================================
   29. ANCHOR NAVIGATION  (on-page jump links)
   ===================================================================== */
.anchor-nav {
    position: sticky;
    top: var(--header-height);
    z-index: var(--z-raised);
    background: rgba(255, 255, 255, 0.96);
    border-bottom: 1px solid var(--ink-200);
}

@supports (backdrop-filter: blur(8px)) {
    .anchor-nav {
        background: rgba(255, 255, 255, 0.88);
        backdrop-filter: blur(10px);
    }
}

.anchor-nav__list {
    display: flex;
    gap: var(--space-sm);
    list-style: none;
    margin: 0;
    padding: 0;
    /* Scrolls sideways within itself on small screens */
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}

.anchor-nav__list::-webkit-scrollbar {
    display: none;
}

.anchor-nav__link {
    display: inline-flex;
    align-items: center;
    min-height: 3rem;
    padding: 0.5rem 0;
    font-size: var(--step--2);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--ink-500);
    text-decoration: none;
    white-space: nowrap;
    border-bottom: 2px solid transparent;
    transition:
        color var(--duration-fast) var(--ease-out),
        border-color var(--duration-fast) var(--ease-out);
}

.anchor-nav__link:hover,
.anchor-nav__link.is-active {
    color: var(--brand-800);
    border-bottom-color: var(--brand-600);
}

/* =====================================================================
   30. REVEAL ON SCROLL
   Progressive enhancement: without JS the `is-visible` class is added
   immediately, so content is never hidden from a non-JS visitor.
   ===================================================================== */
.reveal {
    opacity: 0;
    transform: translateY(1.25rem);
    transition:
        opacity var(--duration-slow) var(--ease-out),
        transform var(--duration-slow) var(--ease-emphasis);
}

.reveal.is-visible {
    opacity: 1;
    transform: none;
}

/* Stagger children for a considered, sequential entrance */
.reveal-group > * {
    opacity: 0;
    transform: translateY(1.25rem);
    transition:
        opacity var(--duration-slow) var(--ease-out),
        transform var(--duration-slow) var(--ease-emphasis);
}

.reveal-group.is-visible > * {
    opacity: 1;
    transform: none;
}

.reveal-group.is-visible > *:nth-child(1) { transition-delay: 0ms; }
.reveal-group.is-visible > *:nth-child(2) { transition-delay: 90ms; }
.reveal-group.is-visible > *:nth-child(3) { transition-delay: 180ms; }
.reveal-group.is-visible > *:nth-child(4) { transition-delay: 270ms; }
.reveal-group.is-visible > *:nth-child(5) { transition-delay: 360ms; }
.reveal-group.is-visible > *:nth-child(6) { transition-delay: 450ms; }

@media (prefers-reduced-motion: reduce) {
    .reveal,
    .reveal-group > * {
        opacity: 1;
        transform: none;
        transition: none;
    }
}

/* =====================================================================
   31. BACK TO TOP
   ===================================================================== */
.to-top {
    position: fixed;
    right: clamp(0.85rem, 3vw, 1.75rem);
    bottom: clamp(0.85rem, 3vw, 1.75rem);
    z-index: var(--z-raised);
    display: grid;
    place-items: center;
    width: 2.875rem;
    height: 2.875rem;
    border-radius: 50%;
    background: var(--brand-800);
    color: #fff;
    border: 1px solid var(--brand-700);
    box-shadow: var(--shadow-md);
    opacity: 0;
    visibility: hidden;
    transform: translateY(0.75rem);
    transition:
        opacity var(--duration-base) var(--ease-out),
        transform var(--duration-base) var(--ease-out),
        visibility var(--duration-base),
        background-color var(--duration-base) var(--ease-out);
    /* Keeps clear of the iOS home indicator */
    margin-bottom: env(safe-area-inset-bottom);
}

.to-top.is-visible {
    opacity: 1;
    visibility: visible;
    transform: none;
}

.to-top:hover {
    background: var(--brand-900);
}

.to-top svg {
    width: 1.05rem;
    height: 1.05rem;
}

/* =====================================================================
   32. PAGINATION
   ===================================================================== */
.pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    margin-top: var(--space-lg);
    list-style: none;
    padding: 0;
}

/* 44px square: these are the smallest things on the site anyone has to hit,
   and they sit in a row where the neighbours are the wrong page. */
.pagination a,
.pagination span {
    display: grid;
    place-items: center;
    min-width: 2.75rem;
    min-height: 2.75rem;
    padding: 0 0.7rem;
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-sm);
    font-size: var(--step--1);
    font-weight: 600;
    color: var(--ink-600);
    text-decoration: none;
    font-variant-numeric: tabular-nums;
    transition:
        background-color var(--duration-fast) var(--ease-out),
        border-color var(--duration-fast) var(--ease-out),
        color var(--duration-fast) var(--ease-out);
}

.pagination a:hover {
    border-color: var(--brand-200);
    background: var(--brand-050);
    color: var(--brand-800);
}

.pagination [aria-current="page"] {
    background: var(--brand-700);
    border-color: var(--brand-700);
    color: #fff;
}

.pagination .is-disabled {
    opacity: 0.4;
    pointer-events: none;
}

/* =====================================================================
   33. BLOG
   ===================================================================== */

/* --- Card grid ------------------------------------------------------ */
.post-grid {
    display: grid;
    gap: var(--space-md);
    grid-template-columns: repeat(auto-fill, minmax(min(18rem, 100%), 1fr));
}

@media (min-width: 46em) {
    .post-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 70em) {
    .post-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.post-card {
    position: relative;
    isolation: isolate;
    border-radius: var(--radius-lg);
    background: rgba(255, 255, 255, 0.86);
    border: 1px solid var(--ink-200);
    box-shadow: var(--glass-shadow);
    overflow: hidden;
    transition:
        transform var(--duration-base) var(--ease-out),
        box-shadow var(--duration-base) var(--ease-out),
        border-color var(--duration-base) var(--ease-out);
}

@supports (backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px)) {
    .post-card {
        background: var(--glass-light);
        border-color: var(--glass-light-border);
        -webkit-backdrop-filter: blur(var(--glass-blur-md)) saturate(1.6);
        backdrop-filter: blur(var(--glass-blur-md)) saturate(1.6);
    }
}

.post-card:hover {
    transform: translateY(-3px);
    box-shadow: var(--glass-shadow-lg);
    border-color: rgba(255, 255, 255, 0.95);
}

/* The whole card is the link, so the target is large and obvious. */
.post-card__link {
    display: grid;
    grid-template-rows: auto 1fr;
    height: 100%;
    text-decoration: none;
    color: inherit;
}

.post-card__media {
    display: block;
    aspect-ratio: 3 / 2;
    overflow: hidden;
    background: var(--ink-100);
}

.post-card__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--duration-slower) var(--ease-out);
}

.post-card:hover .post-card__media img {
    transform: scale(1.04);
}

.post-card__body {
    display: grid;
    gap: var(--space-2xs);
    align-content: start;
    padding: var(--space-md);
}

.post-card__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2xs);
    font-size: var(--step--2);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--brand-700);
}

.post-card__title {
    font-family: var(--font-display);
    font-size: var(--step-1);
    font-weight: 600;
    line-height: var(--leading-snug);
    letter-spacing: -0.01em;
    color: var(--ink-900);
    text-wrap: balance;
}

.post-card:hover .post-card__title {
    color: var(--brand-800);
}

.post-card__excerpt {
    font-size: var(--step--1);
    line-height: var(--leading-relaxed);
    color: var(--ink-600);
    /* Three lines keeps every card the same height regardless of length. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.post-card__foot {
    margin-top: var(--space-2xs);
    padding-top: var(--space-2xs);
    border-top: 1px solid var(--ink-100);
    font-size: var(--step--2);
    color: var(--ink-500);
}

/* --- Featured (most recent) post ------------------------------------ */
.post-feature {
    position: relative;
    isolation: isolate;
    border-radius: var(--radius-lg);
    background: rgba(255, 255, 255, 0.88);
    border: 1px solid var(--ink-200);
    box-shadow: var(--glass-shadow);
    overflow: hidden;
    transition:
        transform var(--duration-base) var(--ease-out),
        box-shadow var(--duration-base) var(--ease-out);
}

@supports (backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px)) {
    .post-feature {
        background: var(--glass-light);
        border-color: var(--glass-light-border);
        -webkit-backdrop-filter: blur(var(--glass-blur-lg)) saturate(1.6);
        backdrop-filter: blur(var(--glass-blur-lg)) saturate(1.6);
    }
}

.post-feature:hover {
    transform: translateY(-3px);
    box-shadow: var(--glass-shadow-lg);
}

.post-feature__link {
    display: grid;
    text-decoration: none;
    color: inherit;
}

/* Side by side once there is room for the image to be worth showing. */
@media (min-width: 52em) {
    .post-feature__link {
        grid-template-columns: 1.1fr 1fr;
        align-items: stretch;
    }
}

.post-feature__media {
    display: block;
    overflow: hidden;
    background: var(--ink-100);
    aspect-ratio: 16 / 10;
}

@media (min-width: 52em) {
    .post-feature__media {
        aspect-ratio: auto;
        min-height: 100%;
    }
}

.post-feature__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--duration-slower) var(--ease-out);
}

.post-feature:hover .post-feature__media img {
    transform: scale(1.03);
}

.post-feature__body {
    display: grid;
    gap: var(--space-xs);
    align-content: center;
    padding: clamp(1.5rem, 4vw, 2.75rem);
}

.post-feature__title {
    font-family: var(--font-display);
    font-size: var(--step-3);
    font-weight: 600;
    line-height: var(--leading-tight);
    letter-spacing: -0.015em;
    color: var(--ink-900);
    text-wrap: balance;
}

.post-feature:hover .post-feature__title {
    color: var(--brand-800);
}

.post-feature__excerpt {
    font-size: var(--step-0);
    line-height: var(--leading-relaxed);
    color: var(--ink-600);
}

/* =====================================================================
   34. ARTICLE  (single blog post)
   ===================================================================== */
.article__head {
    padding-block: var(--space-xl) var(--space-lg);
    background:
        radial-gradient(38rem 26rem at 15% 0%, rgba(20, 176, 131, 0.20) 0%, transparent 60%),
        radial-gradient(30rem 22rem at 90% 30%, rgba(245, 181, 38, 0.20) 0%, transparent 58%),
        radial-gradient(26rem 20rem at 60% 100%, rgba(52, 174, 232, 0.14) 0%, transparent 60%),
        var(--paper-warm);
}

/* The breadcrumb sits on a light background here, not over a photograph. */
.breadcrumb--light .breadcrumb__list li {
    color: var(--ink-500);
}

.breadcrumb--light .breadcrumb__list li + li::before {
    color: var(--ink-300);
}

.breadcrumb--light a {
    color: var(--brand-700);
}

.breadcrumb--light a:hover {
    color: var(--brand-800);
}

.breadcrumb--light [aria-current="page"] {
    color: var(--ink-600);
}

.article__category {
    margin-top: var(--space-md);
    font-size: var(--step--2);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-widest);
    color: var(--brand-700);
}

.article__title {
    margin-top: var(--space-xs);
    font-size: var(--step-5);
    line-height: 1.08;
    letter-spacing: -0.02em;
    text-wrap: balance;
}

.article__standfirst {
    margin-top: var(--space-sm);
    font-family: var(--font-display);
    font-size: var(--step-2);
    font-style: italic;
    line-height: var(--leading-snug);
    color: var(--ink-600);
    max-width: var(--measure);
}

.article__byline {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2xs) var(--space-sm);
    margin-top: var(--space-md);
    padding-top: var(--space-sm);
    border-top: 1px solid var(--ink-200);
    font-size: var(--step--1);
    color: var(--ink-500);
}

.article__byline span + span::before {
    content: "·";
    margin-right: var(--space-sm);
    color: var(--ink-300);
}

/* --- Cover image ---------------------------------------------------- */
.article__cover {
    margin: 0;
    padding-block: var(--space-lg);
    background: var(--paper-warm);
}

.article__cover img {
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    border-radius: var(--radius-lg);
    box-shadow: var(--glass-shadow-lg);
}

/* --- Body ------------------------------------------------------------
   Long-form reading, so this is deliberately NOT glass: plain background,
   generous line height, and a comfortable measure. */
.article__body {
    font-size: var(--step-1);
}

.article__body > * + * {
    margin-top: var(--space-md);
}

.article__body p {
    line-height: 1.8;
    color: var(--ink-700);
}

.article__body h2 {
    margin-top: var(--space-xl);
    font-size: var(--step-3);
    color: var(--brand-800);
}

.article__body h3 {
    margin-top: var(--space-lg);
    font-size: var(--step-1);
}

.article__body ul,
.article__body ol {
    padding-left: 1.4em;
}

.article__body li {
    line-height: 1.75;
    color: var(--ink-700);
}

.article__body li + li {
    margin-top: var(--space-xs);
}

.article__body strong {
    color: var(--ink-900);
}

.article__body blockquote {
    margin-block: var(--space-lg);
    padding: var(--space-sm) var(--space-md);
    border-left: 3px solid var(--brand-600);
    background: var(--brand-050);
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
    font-size: var(--step-1);
}

.article__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    margin-top: var(--space-xl);
    padding-top: var(--space-md);
    border-top: 1px solid var(--ink-200);
}

/* =====================================================================
   19. SPES BOT
   ---------------------------------------------------------------------
   A launcher in the bottom-right corner and the panel it opens.

   Two things drove the layout. First, the back-to-top button already lives
   in that corner, so the launcher sits above it rather than on top of it and
   the two are stacked deliberately. Second, on a phone the panel is not a
   floating card — a card 320px wide on a 360px screen is a card with a
   useless margin — so it becomes a sheet anchored to the bottom edge.

   Nothing here is decorative for its own sake. The panel has a shadow so it
   reads as being above the page, the bubbles are shaped so the speaker is
   obvious without a label, and the typing indicator exists because a wait
   with no feedback feels broken.
   ===================================================================== */

/* --- Launcher --------------------------------------------------------- */
.chat-launcher {
    position: fixed;
    /* Clear of the back-to-top button, which is 2.75rem plus its own inset. */
    right: clamp(0.85rem, 2.5vw, 1.5rem);
    bottom: calc(clamp(0.85rem, 2.5vw, 1.5rem) + 3.6rem);
    z-index: var(--z-header);

    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 1rem 0.5rem 0.5rem;
    border: 1px solid rgba(255, 255, 255, 0.28);
    border-radius: var(--radius-pill);
    color: #fff;
    background: linear-gradient(135deg, var(--brand-600), var(--brand-900));
    box-shadow: var(--shadow-lg);
    cursor: pointer;
    transition:
        translate var(--duration-base) var(--ease-out),
        box-shadow var(--duration-base) var(--ease-out),
        opacity var(--duration-base) var(--ease-out);
}

.chat-launcher:hover {
    translate: 0 -2px;
    box-shadow: var(--shadow-xl);
}

/* While the panel is open the launcher gets out of the way. It keeps its
   place in the layout so focus is not thrown around when it returns. */
.chat-launcher.is-hidden {
    opacity: 0;
    pointer-events: none;
    translate: 0 0.5rem;
}

.chat-launcher__mark {
    display: grid;
    place-items: center;
    width: 2.4rem;
    height: 2.4rem;
    flex: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.16);
}

.chat-launcher__mark svg {
    width: 1.4rem;
    height: 1.4rem;
}

.chat-launcher__text {
    display: grid;
    text-align: left;
    line-height: 1.2;
}

.chat-launcher__name {
    font-size: var(--step--1);
    font-weight: 700;
    letter-spacing: var(--tracking-wide);
}

.chat-launcher__hint {
    font-size: var(--step--2);
    color: rgba(255, 255, 255, 0.76);
}

/* A slow pulse on the mark, once, to catch the eye without nagging. */
@media (prefers-reduced-motion: no-preference) {
    .chat-launcher__mark::after {
        content: "";
        position: absolute;
        inset: 0;
        border-radius: inherit;
        border: 2px solid rgba(255, 255, 255, 0.55);
        animation: chat-ping 2.6s var(--ease-out) 3;
    }

    .chat-launcher__mark {
        position: relative;
    }
}

@keyframes chat-ping {
    0%   { opacity: 0.8; scale: 1; }
    70%  { opacity: 0; scale: 1.7; }
    100% { opacity: 0; scale: 1.7; }
}

/* --- Panel ------------------------------------------------------------ */
.chat-panel {
    position: fixed;
    right: clamp(0.85rem, 2.5vw, 1.5rem);
    bottom: clamp(0.85rem, 2.5vw, 1.5rem);
    z-index: calc(var(--z-header) + 1);

    display: flex;
    flex-direction: column;
    width: min(23rem, calc(100vw - 1.7rem));
    /* Tall enough for a conversation, never taller than the screen. */
    max-height: min(32rem, calc(100svh - 5rem));
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-lg);
    background: var(--paper);
    box-shadow: var(--shadow-xl);
    overflow: hidden;

    /* Closed state. visibility is what takes it out of the tab order. */
    opacity: 0;
    visibility: hidden;
    translate: 0 1rem;
    transition:
        opacity var(--duration-base) var(--ease-out),
        translate var(--duration-base) var(--ease-emphasis),
        visibility var(--duration-base);
}

.chat-panel.is-open {
    opacity: 1;
    visibility: visible;
    translate: 0 0;
}

.chat-panel__head {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex: none;
    padding: 0.7rem 0.75rem 0.7rem 0.9rem;
    color: #fff;
    background: linear-gradient(135deg, var(--brand-700), var(--brand-900));
}

.chat-panel__avatar {
    display: grid;
    place-items: center;
    width: 2.25rem;
    height: 2.25rem;
    flex: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.16);
}

.chat-panel__avatar svg {
    width: 1.35rem;
    height: 1.35rem;
}

.chat-panel__titles {
    display: grid;
    flex: 1 1 auto;
    min-width: 0;
    line-height: 1.25;
}

.chat-panel__title {
    font-family: var(--font-display);
    font-size: var(--step-0);
    font-weight: 600;
}

.chat-panel__subtitle {
    display: flex;
    align-items: center;
    gap: 0.35em;
    font-size: var(--step--2);
    color: rgba(255, 255, 255, 0.78);
    /* A long school name must not push the close button off the edge. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The "online" dot. Gold rather than green, because the panel is green. */
.chat-panel__dot {
    width: 0.45rem;
    height: 0.45rem;
    flex: none;
    border-radius: 50%;
    background: var(--gold-400);
}

.chat-panel__close {
    display: grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    flex: none;
    border: 0;
    border-radius: 50%;
    color: #fff;
    background: rgba(255, 255, 255, 0.12);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out);
}

.chat-panel__close:hover {
    background: rgba(255, 255, 255, 0.26);
}

.chat-panel__close svg {
    width: 1rem;
    height: 1rem;
}

/* --- Transcript ------------------------------------------------------- */
.chat-panel__log {
    flex: 1 1 auto;
    min-height: 6rem;
    overflow-y: auto;
    overscroll-behavior: contain;
    display: grid;
    align-content: start;
    gap: 0.7rem;
    padding: var(--space-sm);
    background: var(--paper-warm);
    font-size: var(--step--1);
    line-height: var(--leading-normal);
}

.chat-msg {
    display: flex;
    align-items: flex-end;
    gap: 0.45rem;
    max-width: 100%;
}

.chat-msg__avatar {
    display: grid;
    place-items: center;
    width: 1.65rem;
    height: 1.65rem;
    flex: none;
    border-radius: 50%;
    color: #fff;
    background: var(--brand-700);
}

.chat-msg__avatar svg {
    width: 1rem;
    height: 1rem;
}

.chat-msg__bubble {
    /* Never the full width: a bubble that reaches both edges stops looking
       like a bubble and starts looking like a paragraph. */
    max-width: 85%;
    padding: 0.55rem 0.8rem;
    border-radius: var(--radius-md);
    /* A long web address in an answer must wrap, not widen the panel. */
    overflow-wrap: anywhere;
}

.chat-msg--bot .chat-msg__bubble {
    border: 1px solid var(--ink-200);
    border-bottom-left-radius: var(--radius-xs);
    background: var(--paper);
    color: var(--ink-800);
}

.chat-msg--user {
    /* The visitor's own words on the right, as every messaging app does it. */
    flex-direction: row-reverse;
    margin-left: auto;
}

.chat-msg--user .chat-msg__bubble {
    border-bottom-right-radius: var(--radius-xs);
    background: var(--brand-700);
    color: #fff;
}

.chat-msg--error .chat-msg__bubble {
    border: 1px solid var(--error-border);
    background: var(--error-bg);
    color: var(--error-text);
}

/* --- Typing indicator ------------------------------------------------- */
.chat-typing {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding-block: 0.3rem;
}

.chat-typing span {
    width: 0.4rem;
    height: 0.4rem;
    border-radius: 50%;
    background: var(--ink-400);
    animation: chat-typing 1.2s var(--ease-in-out) infinite;
}

.chat-typing span:nth-child(2) { animation-delay: 0.15s; }
.chat-typing span:nth-child(3) { animation-delay: 0.3s; }

@keyframes chat-typing {
    0%, 60%, 100% { opacity: 0.3; translate: 0 0; }
    30%           { opacity: 1;   translate: 0 -0.2rem; }
}

@media (prefers-reduced-motion: reduce) {
    .chat-typing span {
        animation: none;
        opacity: 0.55;
    }
}

/* --- Composer --------------------------------------------------------- */
.chat-panel__form {
    display: flex;
    align-items: flex-end;
    gap: 0.4rem;
    flex: none;
    padding: var(--space-2xs) var(--space-xs);
    border-top: 1px solid var(--ink-200);
    background: var(--paper);
}

.chat-panel__input {
    flex: 1 1 auto;
    min-width: 0;
    /* Grows with the question up to a limit, set by the script. */
    max-height: 6rem;
    padding: 0.5rem 0.65rem;
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-md);
    background: var(--paper);
    color: var(--ink-800);
    font: inherit;
    font-size: var(--step--1);
    line-height: var(--leading-normal);
    resize: none;
}

.chat-panel__input:focus-visible {
    border-color: var(--brand-500);
    outline: 2px solid var(--brand-200);
    outline-offset: 1px;
}

.chat-panel__send {
    display: grid;
    place-items: center;
    width: 2.5rem;
    height: 2.5rem;
    flex: none;
    border: 0;
    border-radius: var(--radius-md);
    color: #fff;
    background: var(--brand-600);
    cursor: pointer;
    transition:
        background-color var(--duration-fast) var(--ease-out),
        opacity var(--duration-fast) var(--ease-out);
}

.chat-panel__send:hover:not(:disabled) {
    background: var(--brand-800);
}

.chat-panel__send:disabled {
    opacity: 0.5;
    cursor: default;
}

.chat-panel__send svg {
    width: 1.15rem;
    height: 1.15rem;
}

.chat-panel__footnote {
    flex: none;
    margin: 0;
    padding: 0.5rem var(--space-sm) 0.7rem;
    border-top: 1px solid var(--ink-100);
    background: var(--paper);
    font-size: 0.68rem;
    line-height: 1.45;
    color: var(--ink-500);
}

.chat-panel__footnote a {
    color: var(--brand-700);
}

/* --- On a phone the panel is a sheet ---------------------------------- */
/* 29.9375em, not 30em: the gallery grid and the job-alert form row both switch
   at min-width 30em, and a max- and a min- query sharing a value both fire on
   the pixel they meet at. */
@media (max-width: 29.9375em) {
    .chat-launcher {
        /* No room for the wording beside the mark; the mark alone does it. */
        padding: 0.5rem;
    }

    .chat-launcher__text {
        display: none;
    }

    .chat-panel {
        right: 0;
        left: 0;
        bottom: 0;
        width: auto;
        max-height: min(80svh, 34rem);
        border-inline: 0;
        border-bottom: 0;
        border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    .chat-launcher,
    .chat-panel {
        transition: none;
    }

    .chat-launcher:hover {
        translate: none;
    }

    .chat-launcher__mark::after {
        animation: none;
    }
}

/* --- Administrator's preview ------------------------------------------ */
/* Shown only to a signed-in administrator, while no API key is configured.
   It is deliberately a different colour from the live launcher: nobody
   should mistake a preview for a working assistant. */
.chat-launcher--preview {
    background: linear-gradient(135deg, var(--ink-600), var(--ink-900));
}

.chat-launcher--preview .chat-launcher__hint {
    color: var(--gold-200);
}

/* No pulse on the preview: it is not inviting anyone to click. */
.chat-launcher--preview .chat-launcher__mark::after {
    animation: none;
}

.chat-panel__setup {
    flex: none;
    padding: var(--space-xs) var(--space-sm) var(--space-sm);
    border-top: 1px solid var(--ink-200);
    background: var(--paper);
    font-size: var(--step--2);
    line-height: var(--leading-normal);
    color: var(--ink-700);
}

.chat-panel__setup p {
    margin: 0 0 0.5rem;
}

.chat-panel__setup p:last-child {
    margin-bottom: 0;
}

.chat-panel__setup-title {
    display: flex;
    align-items: center;
    gap: 0.4em;
    font-size: var(--step--1);
    font-weight: 700;
    color: var(--ink-900);
}

.chat-panel__setup-title svg {
    width: 1em;
    height: 1em;
    flex: none;
    color: var(--brand-700);
}

.chat-panel__setup code {
    padding: 0.05em 0.35em;
    border-radius: var(--radius-xs);
    background: var(--ink-100);
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 0.95em;
    /* A path or a key name must not be broken across lines mid-word. */
    white-space: nowrap;
}

.chat-panel__setup-note {
    color: var(--ink-500);
}

/* =====================================================================
   30. THE STAFF LIST
   ---------------------------------------------------------------------
   The school keeps its faculty as three tables headed PGT, PRT and TGT,
   and most rows are a name, a designation and a qualification with no
   photograph. Presented as portrait cards that became a wall of coloured
   initials, which told a visitor nothing; a table suits the data.

   It is a real <table> with a <thead> and row headers, so the
   name-to-designation relationship is announced rather than merely drawn,
   and it collapses to stacked rows on a phone rather than scrolling
   sideways.
   ===================================================================== */
.staff-block + .staff-block {
    margin-top: var(--space-xl);
}

.staff-table__wrap {
    /* A long qualification can still force a scroll on a narrow tablet.
       Contained here so it never widens the page itself. */
    overflow-x: auto;
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-md);
    background: var(--paper);
    box-shadow: var(--shadow-sm);
}

.staff-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--step--1);
}

.staff-table thead th {
    padding: 0.85rem 1rem;
    text-align: left;
    font-size: var(--step--2);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wider);
    color: #fff;
    background: linear-gradient(120deg, var(--brand-800), var(--brand-900));
    white-space: nowrap;
}

.staff-table tbody th,
.staff-table tbody td {
    padding: 0.7rem 1rem;
    border-top: 1px solid var(--ink-100);
    vertical-align: middle;
    text-align: left;
    font-weight: 400;
    color: var(--ink-800);
}

/* Zebra striping, faint: it is a navigation aid across a wide row, not a
   decoration. */
.staff-table tbody tr:nth-child(even) {
    background: var(--brand-050);
}

.staff-table tbody tr:hover {
    background: var(--brand-100);
}

/* Wide enough for the "Sl no." heading the school's own list uses, which the
   rule above keeps on one line. */
.staff-table__num {
    width: 4.5rem;
    color: var(--ink-500);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.staff-table__name {
    font-weight: 600;
    color: var(--ink-900);
}

.staff-table__person {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    min-width: 0;
}

.staff-table__avatar {
    flex: none;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    object-fit: cover;
    background: var(--ink-100);
}

/* Initials where there is no photograph. Deliberately quiet — the name
   beside it is the content; this is just a marker. */
.staff-table__avatar--initials {
    display: grid;
    place-items: center;
    font-family: var(--font-display);
    font-size: var(--step--2);
    font-weight: 600;
    /* 5.1:1 on --brand-100. */
    color: var(--brand-800);
    background: var(--brand-100);
}

.staff-table__tag {
    display: inline-block;
    padding: 0.15rem 0.55rem;
    border: 1px solid var(--brand-200);
    border-radius: var(--radius-pill);
    background: var(--paper);
    font-size: var(--step--2);
    font-weight: 700;
    /* 5.1:1 on white. */
    color: var(--brand-800);
    white-space: nowrap;
}

.staff-table__qual {
    color: var(--ink-700);
}

.staff-table__blank {
    color: var(--ink-400);
}

/* --- Phones ----------------------------------------------------------
   The table becomes a stack of labelled rows. A four-column table cannot
   be read on a 360px screen, and sideways scrolling inside a page that
   also scrolls down is worse than no table at all.
   -------------------------------------------------------------------- */
@media (max-width: 47.9375em) {
    .staff-table__wrap {
        overflow-x: visible;
        border: 0;
        background: none;
        box-shadow: none;
    }

    .staff-table thead {
        /* Not display:none — the headings are still wanted by a screen
           reader, which reads the row headers below in order. */
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .staff-table,
    .staff-table tbody,
    .staff-table tbody tr,
    .staff-table tbody th,
    .staff-table tbody td {
        display: block;
        width: auto;
    }

    .staff-table tbody tr {
        margin-bottom: var(--space-2xs);
        padding: 0.85rem 1rem;
        border: 1px solid var(--ink-200);
        border-radius: var(--radius-md);
        background: var(--paper);
        box-shadow: var(--shadow-xs);
    }

    .staff-table tbody tr:nth-child(even),
    .staff-table tbody tr:hover {
        background: var(--paper);
    }

    .staff-table tbody th,
    .staff-table tbody td {
        padding: 0;
        border: 0;
    }

    /* The row number is noise once the rows are cards. */
    .staff-table__num {
        display: none;
    }

    /*
     * Each value carries its column heading, the same way the class strength
     * and disclosure tables do. Without it a card was a name, a pill and a
     * line of letters with nothing to say that the last one was a
     * qualification — and on this page that is thirty-four cards in a row.
     *
     * Laid out as label-then-value on one line: both values are short, and
     * stacking the label above a two-word value wastes a line each time.
     */
    .staff-table tbody td[data-label] {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: var(--space-xs);
        margin-top: 0.35rem;
        padding-top: 0.35rem;
        border-top: 1px dashed var(--ink-100);
    }

    .staff-table tbody td[data-label]::before {
        content: attr(data-label);
        flex: none;
        font-size: var(--step--2);
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: var(--tracking-wide);
        color: var(--ink-500);
    }

    /* A long qualification wraps rather than pushing the card open. */
    .staff-table__qual {
        text-align: right;
        overflow-wrap: anywhere;
    }

    .staff-table__avatar {
        width: 2.5rem;
        height: 2.5rem;
    }
}

/* =====================================================================
   30a. THE VIEW SWITCH
   ---------------------------------------------------------------------
   Radio buttons, not JavaScript: it works with the keyboard, it works
   without scripting, and the browser handles the state. The panels are
   shown by a sibling selector on :has(), and the list view is the default
   in any browser that does not support it.
   ===================================================================== */
.faculty-views {
    display: flex;
    justify-content: flex-end;
    margin-bottom: var(--space-md);
}

.view-switch {
    display: inline-flex;
    gap: 0.2rem;
    margin: 0;
    padding: 0.2rem;
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-pill);
    background: var(--ink-100);
}

.view-switch__input {
    /* Off screen rather than display:none, so it stays focusable. */
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.view-switch__label {
    display: inline-flex;
    align-items: center;
    gap: 0.4em;
    padding: 0.4rem 0.9rem;
    border-radius: var(--radius-pill);
    font-size: var(--step--2);
    font-weight: 600;
    color: var(--ink-600);
    cursor: pointer;
    transition:
        background-color var(--duration-fast) var(--ease-out),
        color var(--duration-fast) var(--ease-out);
}

.view-switch__label svg {
    width: 0.95em;
    height: 0.95em;
}

.view-switch__label:hover {
    color: var(--brand-800);
}

.view-switch__input:checked + .view-switch__label {
    color: #fff;
    background: var(--brand-700);
    box-shadow: var(--shadow-xs);
}

/* A visible focus ring, since the input itself is off screen. */
.view-switch__input:focus-visible + .view-switch__label {
    outline: 2px solid var(--brand-700);
    outline-offset: 2px;
}

/* --- Which view is showing ------------------------------------------
   The switch sits before the panels in the markup but is not their
   sibling, so the state is read from the document with :has(). In a
   browser without :has() support the cards stay hidden and the list is
   shown — the switch then does nothing, which is a small loss rather than
   a broken page, and the list is the view that suits the data anyway.
   ------------------------------------------------------------------- */
.faculty-stack--switchable .faculty-stack__view--cards {
    display: none;
}

body:has(#faculty-view-cards:checked) .faculty-stack--switchable .faculty-stack__view--cards {
    display: block;
}

body:has(#faculty-view-cards:checked) .faculty-stack--switchable .faculty-stack__view--table {
    display: none;
}

/* The switch is pointless where :has() is unavailable, so it is only
   drawn where the panels can actually respond to it. */
@supports not selector(:has(*)) {
    .faculty-views {
        display: none;
    }
}

/* =====================================================================
   31. CAREER OPPORTUNITIES
   ===================================================================== */

/* --- The band at the foot of the faculty page ----------------------- */
.careers-band {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    color: #fff;
    background: linear-gradient(135deg, var(--brand-800) 0%, var(--brand-900) 62%, #084c3b 100%);
}

.careers-band__inner {
    display: grid;
    gap: var(--space-md);
    align-items: center;
}

@media (min-width: 52em) {
    .careers-band__inner {
        grid-template-columns: minmax(0, 1fr) auto;
        gap: var(--space-lg);
    }
}

.careers-band__title {
    margin: var(--space-3xs) 0 0;
    font-size: var(--step-4);
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: #fff;
}

.careers-band__text {
    max-width: 52ch;
    margin: var(--space-2xs) 0 0;
    font-size: var(--step-0);
    line-height: var(--leading-relaxed);
    /* 7.2:1 on --brand-900. */
    color: rgba(255, 255, 255, 0.82);
}

.careers-band__actions .btn svg {
    width: 1.1em;
    height: 1.1em;
}

/* The eyebrow needs a light treatment on this band; the default is a
   mid green that disappears against it. */
.eyebrow--on-dark {
    color: var(--gold-200);
}

/* --- The vacancy list ----------------------------------------------- */
.vacancy-list {
    display: grid;
    gap: var(--space-md);
}

.vacancy {
    position: relative;
    overflow: hidden;
    padding: clamp(1.25rem, 3vw, 2rem);
    border: 1px solid var(--ink-200);
    border-left: 4px solid var(--brand-600);
    border-radius: var(--radius-md);
    background: var(--paper);
    box-shadow: var(--shadow-sm);
    transition: box-shadow var(--duration-base) var(--ease-out);
}

.vacancy:hover {
    box-shadow: var(--shadow-md);
}

.vacancy__head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    align-items: flex-start;
    justify-content: space-between;
}

.vacancy__title {
    margin: 0;
    font-size: var(--step-2);
    line-height: 1.2;
    color: var(--ink-900);
}

.vacancy__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: var(--space-2xs) 0 0;
    padding: 0;
    list-style: none;
}

/* One palette per kind of fact, so type, pay and deadline are told apart
   at a glance rather than read in sequence. */
.vacancy__tag {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    padding: 0.2rem 0.65rem;
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-pill);
    background: var(--ink-100);
    font-size: var(--step--2);
    font-weight: 600;
    color: var(--ink-700);
}

.vacancy__tag svg {
    width: 0.9em;
    height: 0.9em;
    flex: none;
}

/* 5.1:1 on --brand-050. */
.vacancy__tag--type {
    border-color: var(--brand-200);
    background: var(--brand-050);
    color: var(--brand-800);
}

/* 5.5:1 on --gold-100. */
.vacancy__tag--salary {
    border-color: var(--gold-200);
    background: var(--gold-100);
    color: var(--gold-600);
}

/* 9:1 on --info-bg. */
.vacancy__tag--closes {
    border-color: var(--info-border);
    background: var(--info-bg);
    color: var(--info-text);
}

.vacancy__body {
    margin-top: var(--space-sm);
}

/* --- The fold-out form ---------------------------------------------- */
/*
 * A <details>, so a page advertising six posts stays readable: the
 * descriptions are what a visitor scans, and only the one form they want
 * is open. Markup rather than script, so it is keyboard-operable and
 * works with scripting off.
 */
.vacancy__apply {
    margin-top: var(--space-sm);
    border-top: 1px dashed var(--ink-200);
    padding-top: var(--space-sm);
}

.vacancy__apply-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-xs);
    padding: 0.6rem 0.9rem;
    border: 1px solid var(--brand-200);
    border-radius: var(--radius-sm);
    background: var(--brand-050);
    font-size: var(--step--1);
    font-weight: 700;
    color: var(--brand-800);
    cursor: pointer;
    list-style: none;
    transition: background-color var(--duration-fast) var(--ease-out);
}

/* Safari draws its own triangle without this. */
.vacancy__apply-toggle::-webkit-details-marker {
    display: none;
}

.vacancy__apply-toggle:hover {
    background: var(--brand-100);
}

.vacancy__apply-toggle:focus-visible {
    outline: 2px solid var(--brand-700);
    outline-offset: 2px;
}

.vacancy__apply-label {
    display: inline-flex;
    align-items: center;
    gap: 0.45em;
}

.vacancy__apply-label svg {
    width: 1em;
    height: 1em;
    flex: none;
}

.vacancy__apply-chevron svg {
    width: 1.1em;
    height: 1.1em;
    transition: rotate var(--duration-base) var(--ease-out);
}

.vacancy__apply[open] .vacancy__apply-chevron svg {
    rotate: 180deg;
}

.vacancy__form {
    margin-top: var(--space-sm);
}

/* Inside a vacancy the form is already framed by the card, so it drops
   its own border and padding rather than nesting two panels. */
.vacancy__form .form-panel {
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
}

/* --- The form ------------------------------------------------------- */
.form-panel--application::before {
    content: "";
    position: absolute;
    inset: 0 0 auto;
    height: 4px;
    background: linear-gradient(90deg, var(--brand-600), var(--gold-500), var(--brand-500));
}

.form-panel--application {
    position: relative;
    overflow: hidden;
}

/* The vacancy copy has no seam: it is inside a card that already has one
   down its left edge. */
.vacancy__form .form-panel--application::before {
    display: none;
}

/* Which post this form is for, stated rather than asked. */
.application-for {
    display: flex;
    align-items: center;
    gap: 0.5em;
    margin: 0 0 var(--space-sm);
    padding: 0.55rem 0.85rem;
    border-radius: var(--radius-sm);
    background: var(--brand-050);
    font-size: var(--step--1);
    /* 5.1:1 on --brand-050. */
    color: var(--brand-800);
}

.application-for svg {
    width: 1.05em;
    height: 1.05em;
    flex: none;
    color: var(--brand-600);
}

/* A file input is styled by the browser and cannot be restyled far, so
   this only makes it match the height and edge of the other fields. */
.file-input {
    width: 100%;
    padding: 0.55rem 0.7rem;
    font-family: var(--font-body);
    font-size: max(0.95rem, var(--step--1));
    color: var(--ink-800);
    background: var(--paper);
    border: 1px dashed var(--ink-300);
    border-radius: var(--radius-sm);
    cursor: pointer;
}

.file-input:hover {
    border-color: var(--brand-400);
    background: var(--brand-050);
}

.file-input:focus-visible {
    outline: none;
    border-color: var(--brand-600);
    border-style: solid;
    box-shadow: 0 0 0 3px var(--brand-100);
}

.file-input[aria-invalid="true"] {
    border-color: #c0392b;
    border-style: solid;
}

/* =====================================================================
   32. MANDATORY PUBLIC DISCLOSURE
   ---------------------------------------------------------------------
   Five tables in the format CBSE prescribes. The content is fixed by the
   Board, so the only thing design can contribute is legibility: a clear
   heading per section, a header row that survives scrolling on a phone,
   and a view button that plainly reads as a document link.

   Every table collapses to stacked rows below 48em. A five-column
   compliance table cannot be read on a 360px screen, and sideways
   scrolling inside a page that also scrolls down is worse than no table.
   The data-label attributes in the markup are what the stacked rows use
   as their field names.
   ===================================================================== */
.mpd-block + .mpd-block {
    margin-top: var(--space-xl);
}

/* --- The section heading --------------------------------------------- */
/* Underlined, as the Board's own published format has it, but set in the
   site's type rather than as an imitation of a scanned document. */
.mpd-heading {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin: 0 0 var(--space-sm);
    padding-bottom: var(--space-2xs);
    border-bottom: 2px solid var(--brand-200);
    font-family: var(--font-display);
    font-size: var(--step-2);
    font-weight: 600;
    line-height: 1.2;
    color: var(--brand-800);
}

.mpd-heading__letter {
    display: grid;
    place-items: center;
    flex: none;
    width: 2rem;
    height: 2rem;
    border-radius: var(--radius-sm);
    background: linear-gradient(140deg, var(--brand-600), var(--brand-900));
    font-size: var(--step-0);
    font-weight: 700;
    color: #fff;
}

/* The result and "other documents" blocks have no letter of their own. */
.mpd-heading--plain {
    font-size: var(--step-1);
    border-bottom-color: var(--ink-200);
}

/* --- The table ------------------------------------------------------- */
.mpd-table__wrap {
    overflow-x: auto;
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-md);
    background: var(--paper);
    box-shadow: var(--shadow-sm);
}

.mpd-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--step--1);
}

.mpd-table thead th {
    padding: 0.8rem 1rem;
    text-align: left;
    vertical-align: bottom;
    font-size: var(--step--2);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--ink-800);
    background: var(--ink-100);
    border-bottom: 1px solid var(--ink-200);
    white-space: nowrap;
}

.mpd-table tbody th,
.mpd-table tbody td {
    padding: 0.7rem 1rem;
    border-top: 1px solid var(--ink-100);
    text-align: left;
    vertical-align: top;
    font-weight: 400;
    color: var(--ink-800);
}

.mpd-table tbody tr:nth-child(even) {
    background: var(--brand-050);
}

.mpd-table tbody tr:hover {
    background: var(--brand-100);
}

.mpd-table__num {
    width: 3.5rem;
    color: var(--ink-500);
    font-variant-numeric: tabular-nums;
}

/* The prescribed wording. Not bold: it is the question, and the answer
   beside it is what the reader came for. */
.mpd-table__label {
    font-weight: 500;
    color: var(--ink-900);
    /* Long prescribed headings need to wrap, not stretch the table. */
    min-width: 16rem;
}

.mpd-table__value {
    color: var(--ink-700);
    overflow-wrap: anywhere;
}

.mpd-table__doc {
    width: 10rem;
    white-space: nowrap;
}

/* A row that is a sub-item of the one above it — the PGT/TGT/PRT counts
   under "total no. of teachers". */
.mpd-table__row--sub .mpd-table__label {
    padding-left: 2rem;
    color: var(--ink-700);
}

.mpd-table__bullet {
    margin-right: 0.35em;
    color: var(--brand-500);
}

/* Said plainly rather than left blank: an empty cell in a compliance
   table looks like an oversight, and a reader cannot tell whether the
   school has nothing to declare or has not got round to it. */
.mpd-table__pending {
    font-size: var(--step--2);
    font-style: italic;
    color: var(--ink-500);
}

/* --- The view button ------------------------------------------------- */
/* Blue, deliberately: it is the one control on this page, every visitor
   recognises a blue button as a link to a document, and the Board's own
   format uses one. 4.6:1 against white text. */
.mpd-view {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    padding: 0.35rem 0.9rem;
    border-radius: var(--radius-sm);
    background: linear-gradient(180deg, #2f86d8, #1b6cbb);
    box-shadow: var(--shadow-xs);
    font-size: var(--step--2);
    font-weight: 700;
    color: #fff;
    text-decoration: none;
    transition:
        background-color var(--duration-fast) var(--ease-out),
        transform var(--duration-fast) var(--ease-out);
}

.mpd-view svg {
    width: 0.9em;
    height: 0.9em;
    flex: none;
}

.mpd-view:hover {
    background: linear-gradient(180deg, #1b6cbb, #14568f);
    color: #fff;
    text-decoration: none;
}

.mpd-view:active {
    transform: translateY(1px);
}

.mpd-view:focus-visible {
    outline: 2px solid var(--brand-700);
    outline-offset: 2px;
}

/* --- Phones ---------------------------------------------------------- */
@media (max-width: 47.9375em) {
    .mpd-table__wrap {
        overflow-x: visible;
        border: 0;
        background: none;
        box-shadow: none;
    }

    /* The headings stay for screen readers, which read the row headers
       below in order; they are simply not drawn. */
    .mpd-table thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .mpd-table,
    .mpd-table tbody,
    .mpd-table tbody tr,
    .mpd-table tbody th,
    .mpd-table tbody td {
        display: block;
        width: auto;
    }

    .mpd-table tbody tr {
        margin-bottom: var(--space-2xs);
        padding: 0.85rem 1rem;
        border: 1px solid var(--ink-200);
        border-left: 3px solid var(--brand-400);
        border-radius: var(--radius-md);
        background: var(--paper);
        box-shadow: var(--shadow-xs);
    }

    .mpd-table tbody tr:nth-child(even),
    .mpd-table tbody tr:hover {
        background: var(--paper);
    }

    .mpd-table tbody th,
    .mpd-table tbody td {
        padding: 0;
        border: 0;
        min-width: 0;
    }

    /* The row number is noise once the rows are cards. */
    .mpd-table__num {
        display: none;
    }

    .mpd-table__label {
        font-weight: 600;
    }

    /* Each value gets the column heading in front of it, taken from the
       markup's data-label, so a stacked row still says what it is. */
    .mpd-table tbody td[data-label]:not(.mpd-table__num) {
        margin-top: 0.45rem;
    }

    .mpd-table tbody td[data-label]:not(.mpd-table__num)::before {
        content: attr(data-label);
        display: block;
        margin-bottom: 0.1rem;
        font-size: var(--step--2);
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: var(--tracking-wide);
        color: var(--ink-500);
    }

    .mpd-table__row--sub .mpd-table__label {
        padding-left: 0;
    }

    .mpd-table__doc {
        width: auto;
    }
}

/* =====================================================================
   33. CLASS STRENGTH
   ---------------------------------------------------------------------
   Sections, intake and the roll, class by class, with a grand total. A
   statutory table, so the figures have to be scannable down a column —
   which is what the tabular numerals and the right alignment are for.

   The grand total is a real <tfoot>, so it is announced as a summary row
   rather than as one more class, and it stays put if the table is ever
   scrolled inside its own box.

   Collapses to stacked cards below 56em. Seven columns cannot be read on
   a phone, and sideways scrolling inside a page that also scrolls down is
   worse than no table at all.
   ===================================================================== */
.strength {
    margin-bottom: var(--space-xl);
}

.strength__wrap {
    margin-top: var(--space-sm);
    overflow-x: auto;
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-md);
    background: var(--paper);
    box-shadow: var(--shadow-sm);
}

.strength__table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--step--1);
}

.strength__table thead th {
    padding: 0.75rem 0.9rem;
    text-align: left;
    vertical-align: bottom;
    font-size: var(--step--2);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    line-height: var(--leading-snug);
    color: #fff;
    background: linear-gradient(120deg, var(--brand-800), var(--brand-900));
}

.strength__table tbody th,
.strength__table tbody td {
    padding: 0.65rem 0.9rem;
    border-top: 1px solid var(--ink-100);
    text-align: left;
    vertical-align: middle;
    font-weight: 400;
    color: var(--ink-800);
}

/* Striping, faint: a reading aid across a seven-column row, not decoration. */
.strength__table tbody tr:nth-child(even) {
    background: var(--brand-050);
}

.strength__table tbody tr:hover {
    background: var(--brand-100);
}

.strength__num {
    width: 3.25rem;
    color: var(--ink-500);
    font-variant-numeric: tabular-nums;
}

.strength__class {
    font-weight: 600;
    color: var(--ink-900);
    white-space: nowrap;
}

/* The name a parent knows, where the statutory one differs. */
.strength__alias {
    display: block;
    margin-top: 0.1rem;
    font-size: var(--step--2);
    font-weight: 500;
    color: var(--ink-500);
}

/*
 * Figures are right-aligned with tabular numerals, so digits line up down
 * the column and a reader can compare two classes at a glance. This is the
 * whole reason a table beats a list here.
 */
.strength__figure {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.strength__table thead .strength__figure {
    text-align: right;
}

/* The per-class total, given weight: it is the column most people read. */
.strength__figure--total {
    font-weight: 700;
    color: var(--brand-800);
}

.strength__blank {
    color: var(--ink-400);
}

/* --- The grand total ------------------------------------------------- */
.strength__grand th,
.strength__grand td {
    padding: 0.85rem 0.9rem;
    border-top: 2px solid var(--brand-300);
    background: var(--paper-deep);
    font-weight: 700;
    color: var(--brand-900);
}

.strength__grand-label {
    text-align: right;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    font-size: var(--step--2);
}

.strength__grand-note {
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
    color: var(--ink-600);
}

.strength__grand .strength__figure {
    font-size: var(--step-0);
}

/* --- Phones and small tablets ---------------------------------------- */
@media (max-width: 55.9375em) {
    .strength__wrap {
        overflow-x: visible;
        border: 0;
        background: none;
        box-shadow: none;
    }

    /* Kept for screen readers, which read the row headers below in order. */
    .strength__table thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .strength__table,
    .strength__table tbody,
    .strength__table tfoot,
    .strength__table tbody tr,
    .strength__table tfoot tr,
    .strength__table tbody th,
    .strength__table tbody td,
    .strength__table tfoot th,
    .strength__table tfoot td {
        display: block;
        width: auto;
    }

    .strength__table tbody tr,
    .strength__table tfoot tr {
        margin-bottom: var(--space-2xs);
        padding: 0.85rem 1rem;
        border: 1px solid var(--ink-200);
        border-left: 3px solid var(--brand-400);
        border-radius: var(--radius-md);
        background: var(--paper);
        box-shadow: var(--shadow-xs);
    }

    .strength__table tbody tr:nth-child(even),
    .strength__table tbody tr:hover {
        background: var(--paper);
    }

    .strength__table tbody th,
    .strength__table tbody td,
    .strength__table tfoot th,
    .strength__table tfoot td {
        padding: 0;
        border: 0;
        text-align: left;
    }

    /* The row number is noise once the rows are cards. */
    .strength__num {
        display: none;
    }

    .strength__class {
        font-size: var(--step-0);
        white-space: normal;
    }

    /*
     * Each figure carries its column name, from the markup's data-label.
     *
     * The row number is excluded explicitly. It carries a data-label too, and
     * `.strength__table td[data-label]` (0,2,1) outweighs the `.strength__num`
     * rule above (0,1,0) — so without this guard `display: flex` beat
     * `display: none` and every card opened with a dashed "SL NO. 1" row, the
     * exact noise that rule exists to remove. The disclosure table has always
     * had the same guard; this one was written without it.
     */
    .strength__table td[data-label]:not(.strength__num) {
        display: flex;
        justify-content: space-between;
        gap: var(--space-xs);
        margin-top: 0.35rem;
        padding-top: 0.35rem;
        border-top: 1px dashed var(--ink-100);
    }

    .strength__table td[data-label]:not(.strength__num)::before {
        content: attr(data-label);
        font-size: var(--step--2);
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: var(--tracking-wide);
        color: var(--ink-500);
    }

    /* The grand total stands out as a card in its own right. */
    .strength__grand {
        border-left-color: var(--brand-700) !important;
        background: var(--paper-deep) !important;
    }

    .strength__grand-label {
        text-align: left;
        font-size: var(--step--1);
    }
}

/* =====================================================================
   34. JOB ALERTS
   ---------------------------------------------------------------------
   One field at the foot of the careers page. It has to look like an offer
   rather than a newsletter sign-up, because that is what it is: the school
   telling a teacher it will write to them.

   White ground with red type, where it used to be a dark green slab. Red is
   the one colour on this site that is not green — see --maroon-* in
   base.css — so it marks the band out as something other than another
   section of the page, and it no longer competes with the green footer
   immediately below it.

   --maroon-700 is 10.8:1 on white and --maroon-500 is 7.4:1, so both carry
   text at any size here.
   ===================================================================== */
.alerts-band {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    color: var(--maroon-700);
    background: var(--paper);
    /* The rule is what makes a white band on a white page read as a band. */
    border-top: 3px solid var(--maroon-500);
    border-bottom: 1px solid var(--maroon-100);
}

/* The band used to include partials/decoration.php, whose glows and gold
   seam exist to stop a large area of flat green reading as a printed slab.
   On white they had nothing to light, so the include was dropped. */
.alerts-band__eyebrow {
    color: var(--maroon-500);
}

.alerts-band__inner {
    display: grid;
    gap: var(--space-md);
    align-items: center;
}

@media (min-width: 56em) {
    .alerts-band__inner {
        grid-template-columns: minmax(0, 1fr) minmax(min(24rem, 100%), 0.9fr);
        gap: var(--space-lg);
    }
}

.alerts-band__title {
    margin: var(--space-3xs) 0 0;
    font-size: var(--step-3);
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: var(--maroon-700);
}

.alerts-band__text {
    max-width: 48ch;
    margin: var(--space-2xs) 0 0;
    font-size: var(--step--1);
    line-height: var(--leading-relaxed);
    /* 10.8:1 on white. */
    color: var(--maroon-700);
}

/* Something went wrong on the last attempt. The alert carries its own
   surface and its own semantic colour, which is why it is not tinted red
   along with the rest of the band: an error must not look like the design. */
.alerts-band__result {
    margin-bottom: var(--space-xs);
}

.alerts-form__label {
    display: block;
    margin-bottom: 0.35rem;
    color: var(--maroon-700);
}

/* The field and its button on one line where there is room, stacked on a
   phone — a 44px target next to a text box is too tight at 360px. */
.alerts-form__row {
    display: grid;
    gap: var(--space-2xs);
}

@media (min-width: 30em) {
    .alerts-form__row {
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: start;
    }
}

/* The one action in the band takes the band's red rather than the site
   green, so it belongs to the thing it sits in. White on --maroon-700 is
   10.8:1; the hover shade keeps 7.4:1. */
.alerts-form__row .btn {
    --btn-bg: var(--maroon-700);
    --btn-fg: #fff;
    --btn-border: var(--maroon-700);
    min-height: 2.875rem;
}

.alerts-form__row .btn:hover {
    --btn-bg: var(--maroon-500);
    --btn-border: var(--maroon-500);
    --btn-fg: #fff;
    color: #fff;
}

.alerts-form__row .btn svg {
    width: 1.05em;
    height: 1.05em;
}

.alerts-form__hint {
    display: flex;
    align-items: flex-start;
    gap: 0.4em;
    margin: var(--space-2xs) 0 0;
    font-size: var(--step--2);
    line-height: var(--leading-normal);
    /* 7.4:1 on white. */
    color: var(--maroon-500);
}

.alerts-form__hint svg {
    width: 0.95em;
    height: 0.95em;
    flex: none;
    margin-top: 0.15em;
    color: var(--maroon-500);
}

/* --- Once they are on the list ---------------------------------------
   The form is replaced rather than annotated. A sentence above a field the
   reader has just finished with makes them read to find out that nothing
   more is needed; a button that has turned green and says "Subscribed"
   says it without being read.

   Green, against a band that is otherwise red, so the change of state is
   unmistakable. --success-text is the palette's darkest green and is used
   here as a fill — white on it is 7.5:1, which scripts/contrast-check.php
   asserts alongside the other pairings.
   -------------------------------------------------------------------- */
.alerts-done {
    display: grid;
    gap: var(--space-xs);
    justify-items: start;
}

.alerts-done__badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2xs);
    min-height: 2.875rem;
    padding: 0.8em 1.7em;
    border: 1px solid var(--success-text);
    border-radius: var(--radius-pill);
    background: var(--success-text);
    color: #fff;
    font-size: var(--step--1);
    font-weight: 600;
    letter-spacing: var(--tracking-wide);
    box-shadow: var(--shadow-sm);
}

.alerts-done__badge svg {
    width: 1.15em;
    height: 1.15em;
    flex: none;
}

.alerts-done__text {
    max-width: 44ch;
    margin: 0;
    font-size: var(--step--2);
    line-height: var(--leading-normal);
    color: var(--maroon-700);
}

/*
 * The state arrives on a fresh page load — subscribing is a POST that
 * redirects — so the animation runs once as the band is painted. Motion is
 * opt-in, as everywhere else on the site.
 */
@media (prefers-reduced-motion: no-preference) {
    .alerts-done__badge {
        animation: subscribed-in 420ms var(--ease-out) both;
    }

    .alerts-done__badge svg {
        animation: subscribed-tick 360ms var(--ease-out) 160ms both;
    }
}

@keyframes subscribed-in {
    from {
        opacity: 0;
        transform: translateY(0.4rem) scale(0.94);
    }
    60% {
        transform: translateY(0) scale(1.04);
    }
    to {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

@keyframes subscribed-tick {
    from {
        opacity: 0;
        transform: scale(0.3);
    }
    to {
        opacity: 1;
        transform: scale(1);
    }
}

/* =====================================================================
   35. FACULTY OVERVIEW
   ---------------------------------------------------------------------
   The counts by designation, above the staff tables. On a phone this is
   what a visitor reads instead of scrolling three tables, which is why it
   comes first and why every tile is a link down to its own section.
   ===================================================================== */
.faculty-overview {
    margin-bottom: var(--space-lg);
}

.faculty-overview__grid {
    display: grid;
    gap: var(--space-2xs);
    grid-template-columns: repeat(auto-fit, minmax(min(9rem, 100%), 1fr));
    margin-top: var(--space-sm);
}

.faculty-tile {
    display: grid;
    gap: 0.15rem;
    padding: var(--space-sm) var(--space-xs);
    border: 1px solid var(--brand-200);
    border-radius: var(--radius-md);
    background: linear-gradient(160deg, var(--brand-050), var(--paper));
    text-align: center;
    text-decoration: none;
    box-shadow: var(--shadow-xs);
    transition:
        border-color var(--duration-fast) var(--ease-out),
        box-shadow var(--duration-fast) var(--ease-out),
        transform var(--duration-fast) var(--ease-out);
}

.faculty-tile:hover {
    border-color: var(--brand-500);
    box-shadow: var(--shadow-md);
    text-decoration: none;
    transform: translateY(-2px);
}

.faculty-tile:focus-visible {
    outline: 2px solid var(--brand-700);
    outline-offset: 2px;
}

.faculty-tile__count {
    font-family: var(--font-display);
    font-size: var(--step-3);
    font-weight: 600;
    line-height: 1;
    color: var(--brand-800);
}

.faculty-tile__label {
    font-size: var(--step--2);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--ink-700);
}

.faculty-tile__note {
    font-size: var(--step--2);
    color: var(--ink-500);
}

/* The total, marked out from the per-designation tiles beside it. */
.faculty-tile--total {
    border-color: var(--brand-700);
    background: linear-gradient(160deg, var(--brand-700), var(--brand-900));
}

.faculty-tile--total .faculty-tile__count {
    color: #fff;
}

.faculty-tile--total .faculty-tile__label {
    /* 5.1:1 on --brand-800, the midpoint of the gradient. */
    color: var(--gold-200);
}

.faculty-tile--total .faculty-tile__note {
    color: rgba(255, 255, 255, 0.72);
}
