/* ============================================================================
   landing.css — the public front page (resources/views/welcome.blade.php)

   Lives here rather than in a <style> block inside the Blade view for three
   reasons:

     1. Blade treats `@word` as a directive and `{{ }}` as an echo. A CSS
        at-rule or an asset() call inside a style block is a silent hazard:
        `url("{{ asset('x') }}")` puts a stray quote in the middle of a
        value, and an at-rule Blade happens to recognise disappears. From a
        real stylesheet, `url("../images/…")` resolves against /css/ and
        there is nothing to escape.
     2. It is cacheable. The view is re-rendered per request; this is not.
     3. bin/ui-check reads the public CSS files, so these tokens,
        contrasts and motion rules get audited with everything else.

   Token prefix is --lp- (landing page). Keeping this page's palette and
   spacing separate makes the school brand easy to swap without changing the
   signed-in portal or the wider public-site layout.
   ========================================================================= */

:root {
    /* ---- Swappable school palette ---------------------------------------
       Maroon ties into the current portal brand; green and blue bring
       distinct academic and care accents; ochre warms small details. */
    --lp-primary: #5b0617;
    --lp-school-green: #245b49;
    --lp-school-blue: #31546b;
    --lp-school-green-wash: #e6eee9;
    --lp-school-blue-wash: #e5edf2;
    --lp-warm-accent: #9a4b1d;
    --lp-on-primary: #ffffff;
    --lp-primary-container: #7a1f2b;
    --lp-on-primary-container: #ffffff;
    --lp-tertiary: #263238;

    /* ---- Text on the dark surfaces --------------------------------------
       Tokens rather than rgba(255,255,255,0.78) inline. Two reasons, and the
       cosmetic one is the lesser: a translucent white composites against
       whatever is behind it, so its real contrast depends on the gradient
       underneath and cannot be read off the declaration. These are solid
       values measured against both dark surfaces — #f0dfe2 is 7.9:1 on
       --lp-primary-container and 10.9:1 on --lp-tertiary. */
    --lp-on-invert: #ffffff;
    --lp-on-invert-variant: #f0dfe2;

    /* ---- Surfaces -------------------------------------------------------- */
    --lp-surface: #f9f9f7;
    --lp-surface-lowest: #ffffff;
    --lp-surface-low: #f3f3f0;
    --lp-surface-high: #e9e9e4;
    --lp-on-surface: #1a1c1b;
    --lp-on-surface-variant: #45494a;
    --lp-outline-variant: #cdcfcb;
    --lp-hero-wash-rgb: 249, 249, 247;

    /* ---- Type -----------------------------------------------------------
       Instrument Sans is self-hosted and preloaded by the view; the variable
       face tops out at 700, so no rule here asks for 800 (it would be
       synthetically emboldened and render differently per platform).

       The display face is a system serif stack rather than a webfont. The
       approved design used Source Serif 4 from Google Fonts, which would
       undo the self-hosting work and add a third-party request to the first
       paint of the first page. ui-serif / Iowan / Georgia are all
       transitional serifs and carry the same sans-body-serif-display
       contrast. Swapping in a self-hosted Source Serif 4 later is a
       one-line change here. */
    --lp-font-sans: "Instrument Sans", -apple-system, BlinkMacSystemFont, ui-sans-serif, system-ui, "Segoe UI", sans-serif;
    --lp-font-display: ui-serif, "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif;

    /* ---- Shape and depth ------------------------------------------------- */
    --lp-radius-sm: 4px;
    --lp-radius-md: 6px;
    --lp-radius-lg: 8px;
        --lp-shadow-sm: 0 2px 10px rgba(26, 28, 27, 0.06);
    --lp-shadow-md: 0 18px 44px -20px rgba(26, 28, 27, 0.26);
    --lp-shadow-lg: 0 28px 70px -28px rgba(26, 28, 27, 0.34);
    --lp-ease: cubic-bezier(0.16, 1, 0.3, 1);

    /* ---- Measure ---------------------------------------------------------
       One variable for the content width so the header, every section and
       the footer line up without each repeating a min() expression. */
    --lp-measure: 1180px;
    --lp-gutter: clamp(1rem, 4vw, 2.5rem);
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

@media (prefers-reduced-motion: no-preference) {
    html {
        scroll-behavior: smooth;
    }
}

body {
    margin: 0;
    background: var(--lp-surface);
    color: var(--lp-on-surface);
    font-family: var(--lp-font-sans);
    font-size: 1rem;
    line-height: 1.6;
    letter-spacing: 0;
    -webkit-font-smoothing: antialiased;
}

img {
    max-width: 100%;
    height: auto;
    display: block;
}

a {
    color: inherit;
}

/* Every in-page anchor sits under a sticky header. Without this, clicking a
   nav link parks the heading behind the bar. 7rem covers the announcement
   strip plus the header at its tallest. */
[id] {
    scroll-margin-top: 7rem;
}

/* One visible focus treatment for the whole page. :focus-visible so mouse
   users do not get a ring on every click, but keyboard users always do. */
:focus-visible {
    outline: 3px solid var(--lp-school-blue);
    outline-offset: 3px;
    border-radius: 4px;
}

.lp-announce :focus-visible,
.lp-panel--invert :focus-visible,
.lp-footer :focus-visible {
    outline-color: var(--lp-on-invert);
}

.lp-shell {
    /* No `overflow: hidden` here. It would clip the sticky header's
       positioning context in Safari and silently disable scroll-driven
       reveal in some engines. Horizontal overflow is prevented by the
       grids themselves instead. */
    min-height: 100svh;
    display: flex;
    flex-direction: column;
}

.lp-wrap {
    width: min(var(--lp-measure), 100%);
    margin-inline: auto;
    padding-inline: var(--lp-gutter);
}

/* ---------------------------------------------------------------------------
   Skip link
   --------------------------------------------------------------------------- */

.lp-skip {
    position: fixed;
    left: 1rem;
    top: -4rem;
    z-index: 200;
    padding: 0.7rem 1.1rem;
    color: var(--lp-on-primary);
    background: var(--lp-primary);
    border-radius: var(--lp-radius-sm);
    font-weight: 700;
    text-decoration: none;
    transition: top 0.18s var(--lp-ease);
}

.lp-skip:focus {
    top: 1rem;
}

/* ---------------------------------------------------------------------------
   Announcement strip + header

   The header is `sticky`, not `fixed`. The approved design used a fixed
   header with `padding-top: 7rem` on <main> to compensate — a constant that
   is wrong the moment the announcement text wraps to two lines, which it
   does on any phone. Sticky needs no compensation at all: the strip and the
   bar take their natural height and the content starts below them.
   --------------------------------------------------------------------------- */

.lp-announce {
    background: var(--lp-tertiary);
    color: var(--lp-on-invert);
    font-size: 0.85rem;
    line-height: 1.45;
}

.lp-announce__inner {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem 1rem;
    flex-wrap: wrap;
    padding-block: 0.6rem;
    text-align: center;
}

.lp-announce__label {
    flex-shrink: 0;
    padding: 0.1rem 0.6rem;
    border-radius: var(--lp-radius-md);
    background: rgba(255, 255, 255, 0.16);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: uppercase;
}

.lp-announce__link {
    color: var(--lp-on-invert);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
}

.lp-header {
    position: sticky;
    top: 0;
    z-index: 100;
    background: rgba(var(--lp-hero-wash-rgb), 0.86);
    backdrop-filter: saturate(180%) blur(18px);
    -webkit-backdrop-filter: saturate(180%) blur(18px);
    border-bottom: 1px solid transparent;
    transition: border-color 0.2s var(--lp-ease), box-shadow 0.2s var(--lp-ease);
}

/* Added by the view's script once the page has scrolled past the hero top.
   Gives the bar an edge only when there is content behind it. */
.lp-header.is-stuck {
    border-bottom-color: var(--lp-outline-variant);
    box-shadow: var(--lp-shadow-sm);
}

.lp-header__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    min-height: 4.5rem;
}

.lp-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.7rem;
    min-width: 0;
    text-decoration: none;
    font-weight: 600;
    letter-spacing: 0;
}

.lp-brand__mark {
    flex-shrink: 0;
    width: 2.5rem;
    height: 2.5rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    color: var(--lp-on-primary);
    background: linear-gradient(140deg, var(--lp-primary-container), var(--lp-primary));
    font-family: var(--lp-font-display);
    font-size: 1.1rem;
    font-weight: 700;
    box-shadow: 0 10px 24px -10px rgba(91, 6, 23, 0.5);
}

.lp-brand__name {
    font-size: 1rem;
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lp-nav {
    display: none;
    align-items: center;
    gap: 0.25rem;
}

.lp-nav a {
    min-height: 2.75rem;
    display: inline-flex;
    align-items: center;
    padding: 0.65rem 0.8rem;
    border-radius: var(--lp-radius-md);
    color: var(--lp-on-surface-variant);
    font-size: 0.925rem;
    font-weight: 500;
    text-decoration: none;
    transition: background 0.16s var(--lp-ease), color 0.16s var(--lp-ease);
}

.lp-nav a:hover,
.lp-nav a:focus-visible {
    background: var(--lp-surface-high);
    color: var(--lp-on-surface);
}

.lp-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
}

.lp-portal {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    /* 44px minimum height — the WCAG target-size floor, and the difference
       between a reliable tap and three attempts on a phone. */
    min-height: 2.75rem;
    padding: 0.5rem 1.1rem;
    border-radius: var(--lp-radius-md);
    color: var(--lp-on-primary);
    background: var(--lp-primary);
    font-size: 0.9rem;
    font-weight: 600;
    text-decoration: none;
    transition: transform 0.16s var(--lp-ease), box-shadow 0.16s var(--lp-ease), background 0.16s var(--lp-ease);
}

.lp-portal:hover {
    background: var(--lp-primary-container);
    transform: translateY(-1px);
    box-shadow: var(--lp-shadow-md);
}

.lp-burger {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 2.75rem;
    min-width: 2.75rem;
    padding: 0.5rem 0.9rem;
    border: 1px solid var(--lp-outline-variant);
    border-radius: var(--lp-radius-md);
    background: var(--lp-surface-lowest);
    color: var(--lp-on-surface);
    font-family: inherit;
    font-size: 0.875rem;
    font-weight: 600;
    cursor: pointer;
}

.lp-burger__bars {
    display: inline-flex;
    flex-direction: column;
    gap: 3px;
    width: 16px;
}

.lp-burger__bars span {
    height: 2px;
    border-radius: 2px;
    background: currentColor;
}

/* ---------------------------------------------------------------------------
   Mobile drawer

   The approved design had `hidden xl:flex` on the nav and no toggle anywhere,
   which left every viewport under 1280px — all phones, all tablets, and a
   fair number of laptops — with no navigation at all. This is the same
   toggle pattern the previous page used, kept because it works: a real
   <button> with aria-expanded, a panel driven by the `hidden` attribute, and
   `display: none !important` on `[hidden]` so the attribute always wins over
   the `display: grid` below.
   --------------------------------------------------------------------------- */

.lp-drawer {
    display: grid;
    gap: 0.15rem;
    padding-bottom: 1rem;
    border-top: 1px solid var(--lp-outline-variant);
}

.lp-drawer[hidden] {
    display: none !important;
}

.lp-drawer a {
    display: flex;
    align-items: center;
    min-height: 2.75rem;
    padding: 0.6rem 0.25rem;
    border-bottom: 1px solid var(--lp-outline-variant);
    color: var(--lp-on-surface);
    font-weight: 500;
    text-decoration: none;
}

.lp-drawer a:last-child {
    border-bottom: 0;
}

.lp-drawer a:hover,
.lp-drawer a:focus-visible {
    color: var(--lp-primary);
}

/* ---------------------------------------------------------------------------
   Hero

   Background is declared twice on purpose: a plain url() first as the
   fallback, then image-set(). A browser without image-set() support (~3% of
   visitors) ignores the second declaration entirely and keeps the first, so
   removing the plain url() leaves those visitors with no hero at all. The
   assets check in bin/ui-check flags exactly that deletion.

   The WebP is 123 KB against the PNG's 2.2 MB, which is the whole point on a
   mobile connection.
   --------------------------------------------------------------------------- */

.lp-hero {
    position: relative;
    display: flex;
    align-items: center;
    /* Short of a full viewport so the section below stays partly visible —
       a visitor should be able to see there is more page without scrolling
       blind. svh rather than vh so mobile browser chrome does not push the
       hero taller than the screen. */
    min-height: 60svh;
    padding-block: clamp(2.5rem, 7vw, 5.5rem);
    /* The photo carries the school story. A light veil follows its open left
       side for readable copy while leaving the learners visible at right. */
    background-color: var(--lp-surface-low);
    background-image:
        linear-gradient(100deg, rgba(var(--lp-hero-wash-rgb), 0.96) 0%, rgba(var(--lp-hero-wash-rgb), 0.9) 42%, rgba(var(--lp-hero-wash-rgb), 0.4) 66%, rgba(var(--lp-hero-wash-rgb), 0.06) 100%),
        url("../images/school-hero-campus.png");
    background-image:
        linear-gradient(100deg, rgba(var(--lp-hero-wash-rgb), 0.96) 0%, rgba(var(--lp-hero-wash-rgb), 0.9) 42%, rgba(var(--lp-hero-wash-rgb), 0.4) 66%, rgba(var(--lp-hero-wash-rgb), 0.06) 100%),
        image-set(
            url("../images/school-hero-campus.webp") type("image/webp"),
            url("../images/school-hero-campus.png") type("image/png")
        );
    background-size: cover;
    background-position: center;
}

.lp-hero__inner {
    position: relative;
    z-index: 1;
    max-width: 44rem;
}

@media (prefers-reduced-motion: no-preference) {
    .lp-eyebrow,
    .lp-hero h1,
    .lp-lead,
    .lp-cta-row {
        animation: lp-hero-enter 520ms var(--lp-ease) both;
    }

    .lp-hero h1 { animation-delay: 60ms; }
    .lp-lead { animation-delay: 120ms; }
    .lp-cta-row { animation-delay: 180ms; }
}

@keyframes lp-hero-enter {
    from { opacity: 0; transform: translateY(12px); }
    to { opacity: 1; transform: translateY(0); }
}

.lp-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1.25rem;
    padding: 0.35rem 0.9rem;
    border: 1px solid var(--lp-outline-variant);
    border-radius: var(--lp-radius-md);
    background: rgba(255, 255, 255, 0.84);
    color: var(--lp-on-surface);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: uppercase;
}

.lp-eyebrow::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    /* Warm accent dot — the one spot of a second brand colour on the veil. */
    background: var(--lp-warm-accent);
}

.lp-hero h1 {
    margin: 0 0 1.1rem;
    color: var(--lp-on-surface);
    font-family: var(--lp-font-display);
    font-size: 3.5rem;
    line-height: 1.04;
    letter-spacing: 0;
    font-weight: 600;
    text-wrap: balance;
}

.lp-lead {
    margin: 0 0 2rem;
    max-width: 36rem;
    color: var(--lp-on-surface-variant);
    font-size: 1.1rem;
    line-height: 1.6;
    text-wrap: pretty;
}

.lp-cta-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.lp-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 3rem;
    padding: 0.7rem 1.5rem;
    border: 1px solid transparent;
    border-radius: var(--lp-radius-md);
    font-family: inherit;
    font-size: 0.95rem;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    transition: transform 0.16s var(--lp-ease), box-shadow 0.16s var(--lp-ease), background 0.16s var(--lp-ease), border-color 0.16s var(--lp-ease);
}

.lp-btn--filled {
    color: var(--lp-on-primary);
    background: var(--lp-primary);
    box-shadow: 0 14px 30px -16px rgba(91, 6, 23, 0.65);
}

.lp-btn--filled:hover {
    background: var(--lp-primary-container);
    transform: translateY(-2px);
    box-shadow: var(--lp-shadow-lg);
}

.lp-btn--tonal {
    color: var(--lp-primary);
    background: var(--lp-surface-lowest);
    border-color: var(--lp-outline-variant);
}

.lp-btn--tonal:hover {
    background: var(--lp-surface-low);
    transform: translateY(-2px);
    box-shadow: var(--lp-shadow-md);
}

.lp-btn--ghost {
    color: var(--lp-on-surface);
    background: transparent;
    border-color: var(--lp-outline-variant);
}

.lp-btn--ghost:hover {
    background: rgba(255, 255, 255, 0.6);
    transform: translateY(-2px);
}

/* The ghost outline, restated for use inside .lp-panel--invert. Previously an
   inline style="color:#fff; border-color:rgba(...)" on that one button —
   which no stylesheet can audit and no reduced-motion block can reach. */
.lp-btn--on-invert {
    color: var(--lp-on-invert);
    background: transparent;
    border-color: rgba(255, 255, 255, 0.45);
}

.lp-btn--on-invert:hover {
    background: rgba(255, 255, 255, 0.14);
    border-color: var(--lp-on-invert);
    transform: translateY(-2px);
}

/* Keep the primary action in the school brand color on the light photo veil.
   Scoped to .lp-hero so section actions retain their standard treatment. */
.lp-hero .lp-btn--filled {
    color: var(--lp-on-primary);
    background: var(--lp-primary);
    box-shadow: var(--lp-shadow-md);
}

.lp-hero .lp-btn--filled:hover {
    background: var(--lp-primary-container);
    transform: translateY(-2px);
    box-shadow: var(--lp-shadow-lg);
}

/* ---------------------------------------------------------------------------
   Stats strip
   --------------------------------------------------------------------------- */

.lp-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 1rem;
    margin-top: 2.75rem;
}

.lp-stat {
    padding: 1.1rem 1.25rem;
    border: 1px solid var(--lp-outline-variant);
    border-radius: var(--lp-radius-md);
    background: rgba(255, 255, 255, 0.82);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    transition: transform 0.2s var(--lp-ease), box-shadow 0.2s var(--lp-ease);
}

.lp-stat:hover {
    transform: translateY(-3px);
    box-shadow: var(--lp-shadow-md);
}

.lp-stat__value {
    display: block;
    font-family: var(--lp-font-display);
    font-size: 1.55rem;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: 0;
    color: var(--lp-primary);
}

.lp-stat__label {
    display: block;
    margin-top: 0.3rem;
    color: var(--lp-on-surface-variant);
    font-size: 0.875rem;
    line-height: 1.45;
}

/* Compact trust band: three concise school-specific signals immediately
   after the hero, without turning each point into another large card. */
.lp-proof-band {
    background: var(--lp-surface-lowest);
    border-bottom: 1px solid var(--lp-outline-variant);
}

.lp-proof-points {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 1.25rem;
    margin: 0;
    padding-block: 1.5rem;
    list-style: none;
}

.lp-proof-point {
    display: grid;
    align-content: start;
    gap: 0.2rem;
    padding-left: 0.9rem;
    border-left: 3px solid var(--lp-school-green);
}

.lp-proof-point__title {
    color: var(--lp-on-surface);
    font-weight: 700;
}

.lp-proof-point__body {
    color: var(--lp-on-surface-variant);
    font-size: 0.9rem;
    line-height: 1.45;
}

/* ---------------------------------------------------------------------------
   Sections
   --------------------------------------------------------------------------- */

.lp-section {
    padding-block: clamp(3.25rem, 8vw, 6rem);
}

.lp-section--tint {
    background: var(--lp-surface-low);
}

.lp-section--raise {
    /* Pulls the first band up under the hero so the join reads as one
       surface rather than two stacked screens. */
    background: var(--lp-surface);
}

.lp-head {
    max-width: 44rem;
    margin-bottom: 2.5rem;
}

.lp-kicker {
    display: block;
    margin-bottom: 0.75rem;
    color: var(--lp-school-green);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: uppercase;
}

.lp-head h2 {
    margin: 0 0 0.75rem;
    font-family: var(--lp-font-display);
    font-size: 2.25rem;
    line-height: 1.12;
    letter-spacing: 0;
    font-weight: 600;
    text-wrap: balance;
}

.lp-head p {
    margin: 0;
    color: var(--lp-on-surface-variant);
    font-size: 1.05rem;
    text-wrap: pretty;
}

.lp-head__row {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.75rem;
}

.lp-head__row h2 {
    margin: 0;
    font-family: var(--lp-font-display);
    font-size: 1.8rem;
    letter-spacing: 0;
    font-weight: 600;
}

.lp-more {
    color: var(--lp-primary);
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
    font-size: 0.925rem;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}

.lp-more:hover {
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* ---------------------------------------------------------------------------
   Cards
   --------------------------------------------------------------------------- */

.lp-cards {
    display: grid;
    /* auto-fit + minmax rather than a fixed column count with a mobile
       override: the grid reflows at whatever width the content needs, so
       there is no band of viewports where cards are squeezed. */
    grid-template-columns: repeat(auto-fit, minmax(16.5rem, 1fr));
    gap: 1.25rem;
}

.lp-card {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    padding: 1.75rem;
    border: 1px solid var(--lp-outline-variant);
    border-radius: var(--lp-radius-md);
    background: var(--lp-surface-lowest);
    box-shadow: var(--lp-shadow-sm);
    transition: transform 0.22s var(--lp-ease), box-shadow 0.22s var(--lp-ease), border-color 0.22s var(--lp-ease);
}

.lp-card:hover {
    transform: translateY(-4px);
    border-color: transparent;
    box-shadow: var(--lp-shadow-md);
}

.lp-card__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    margin-bottom: 0.4rem;
    border-radius: var(--lp-radius-sm);
    color: var(--lp-school-green);
    background: var(--lp-school-green-wash);
}

.lp-card__icon svg {
    width: 1.35rem;
    height: 1.35rem;
}

.lp-card h3 {
    margin: 0;
    font-size: 1.1rem;
    font-weight: 600;
    letter-spacing: 0;
}

.lp-card p {
    margin: 0;
    color: var(--lp-on-surface-variant);
    font-size: 0.95rem;
    text-wrap: pretty;
}

.lp-card__link {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    min-height: 2.75rem;
    margin-top: auto;
    padding: 0.35rem 0;
    color: var(--lp-primary);
    font-size: 0.9rem;
    font-weight: 600;
    text-decoration: none;
}

.lp-card__link:hover {
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* ---------------------------------------------------------------------------
   News and events
   --------------------------------------------------------------------------- */

.lp-news__date {
    color: var(--lp-on-surface-variant);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0;
}

.lp-news__title {
    margin: 0.4rem 0 0;
    font-size: 1.075rem;
    font-weight: 600;
    letter-spacing: 0;
}

.lp-news__title a {
    text-decoration: none;
}

.lp-news__title a:hover {
    color: var(--lp-primary);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.lp-events {
    display: grid;
    gap: 0.75rem;
}

.lp-event {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    padding: 1.1rem 1.25rem;
    border: 1px solid var(--lp-outline-variant);
    border-radius: var(--lp-radius-md);
    background: var(--lp-surface-lowest);
    transition: transform 0.2s var(--lp-ease), box-shadow 0.2s var(--lp-ease);
}

.lp-event:hover {
    transform: translateY(-2px);
    box-shadow: var(--lp-shadow-sm);
}

.lp-event__date {
    flex-shrink: 0;
    min-width: 3.5rem;
    padding: 0.4rem 0.5rem;
    border-radius: var(--lp-radius-sm);
    color: var(--lp-on-primary-container);
    background: var(--lp-primary-container);
    text-align: center;
    line-height: 1.15;
}

.lp-event__day {
    display: block;
    font-size: 1.15rem;
    font-weight: 700;
}

.lp-event__month {
    display: block;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: uppercase;
}

.lp-event__title {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
}

.lp-event__meta {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.2rem;
    color: var(--lp-on-surface-variant);
    font-size: 0.85rem;
}

.lp-event__meta svg {
    width: 0.95rem;
    height: 0.95rem;
    flex-shrink: 0;
}

.lp-event__body {
    margin: 0.35rem 0 0;
    color: var(--lp-on-surface-variant);
    font-size: 0.9rem;
}

.lp-empty {
    padding: 2rem 1.5rem;
    border: 1px dashed var(--lp-outline-variant);
    border-radius: var(--lp-radius-md);
    color: var(--lp-on-surface-variant);
    text-align: center;
}

/* ---------------------------------------------------------------------------
   Contact
   --------------------------------------------------------------------------- */

.lp-contact {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
    gap: 1.25rem;
}

.lp-panel {
    padding: clamp(1.5rem, 4vw, 2.25rem);
    border-radius: var(--lp-radius-lg);
    background: var(--lp-surface-lowest);
    border: 1px solid var(--lp-outline-variant);
    box-shadow: var(--lp-shadow-sm);
}

.lp-panel--spaced {
    margin-top: 1.25rem;
}

.lp-panel--invert {
    color: var(--lp-on-invert);
    background: linear-gradient(150deg, var(--lp-primary-container), var(--lp-tertiary));
    border-color: transparent;
}

.lp-panel h2,
.lp-panel h3 {
    margin: 0 0 0.6rem;
    font-family: var(--lp-font-display);
    font-size: 1.5rem;
    letter-spacing: 0;
    font-weight: 600;
}

.lp-panel > p {
    margin: 0 0 1.25rem;
    color: var(--lp-on-surface-variant);
    text-wrap: pretty;
}

.lp-panel--invert > p {
    color: var(--lp-on-invert-variant);
}

.lp-details {
    display: grid;
    gap: 0.9rem;
    margin: 0 0 1.5rem;
}

.lp-detail {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
}

.lp-detail svg {
    flex-shrink: 0;
    width: 1.15rem;
    height: 1.15rem;
    margin-top: 0.2rem;
    color: var(--lp-primary);
}

.lp-panel--invert .lp-detail svg {
    color: var(--lp-on-invert-variant);
}

.lp-detail dt {
    margin: 0;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: uppercase;
    color: var(--lp-on-surface-variant);
}

.lp-panel--invert .lp-detail dt {
    color: var(--lp-on-invert-variant);
}

.lp-detail dd {
    margin: 0.1rem 0 0;
    font-size: 0.975rem;
    font-weight: 500;
}

.lp-detail dd a {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
    text-decoration: none;
    border-bottom: 1px solid currentColor;
}

/* ---------------------------------------------------------------------------
   Footer
   --------------------------------------------------------------------------- */

.lp-footer {
    margin-top: auto;
    padding-block: clamp(2.5rem, 6vw, 4rem) 1.5rem;
    color: var(--lp-on-invert-variant);
    background: var(--lp-tertiary);
    border-radius: var(--lp-radius-lg) var(--lp-radius-lg) 0 0;
    font-size: 0.9rem;
}

.lp-footer__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: 2rem;
}

.lp-footer__title {
    margin: 0 0 0.75rem;
    color: var(--lp-on-invert);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: uppercase;
}

.lp-footer__line {
    margin: 0 0 0.5rem;
}

.lp-footer__line:last-child {
    margin-bottom: 0;
}

.lp-footer__name {
    margin: 0 0 0.5rem;
    color: var(--lp-on-invert);
    font-family: var(--lp-font-display);
    font-size: 1.2rem;
    font-weight: 600;
    letter-spacing: 0;
}

.lp-footer ul {
    margin: 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 0.1rem;
}

.lp-footer ul a {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
    color: var(--lp-on-invert);
    opacity: 0.88;
    text-decoration: none;
}

.lp-footer ul a:hover,
.lp-footer ul a:focus-visible {
    opacity: 1;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.lp-footer__base {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-top: 2.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid rgba(255, 255, 255, 0.2);
    font-size: 0.8rem;
}

/* ---------------------------------------------------------------------------
   Hero "established" badge

   A small pill under the eyebrow. Only rendered when the admin fills in
   hero_established, so it never shows an empty chip.
   --------------------------------------------------------------------------- */

.lp-hero__est {
    display: inline-flex;
    align-items: center;
    margin: 0 0 1.1rem 0.5rem;
    padding: 0.3rem 0.8rem;
    border-radius: var(--lp-radius-md);
    /* Light chip on the maroon veil so it stays legible beside the eyebrow.
       Maroon text on near-white is ~12:1. */
    background: var(--lp-surface-lowest);
    color: var(--lp-primary);
    font-size: 0.74rem;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: uppercase;
}

/* Four figures rather than three: tighten the minimum so a quad row still
   fits two-up on a tablet before the mobile flex-scroll takes over. */
.lp-stats--quad {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* Optional school offerings stay static so every item remains readable. */
.lp-offerings {
    border-block: 1px solid var(--lp-outline-variant);
    background: var(--lp-surface-lowest);
}

.lp-offerings__list {
    width: min(var(--lp-measure), 100%);
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.5rem;
    margin: 0 auto;
    padding: 1rem var(--lp-gutter);
    list-style: none;
}

.lp-offerings__item {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    color: var(--lp-on-surface-variant);
    font-size: 0.9rem;
    font-weight: 600;
}

.lp-offerings__item::before {
    content: "";
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: var(--lp-school-green);
}

/* ---------------------------------------------------------------------------
   Head of school message
   --------------------------------------------------------------------------- */

.lp-head-msg {
    max-width: 52rem;
    margin: 0 auto;
    text-align: center;
}

.lp-head-msg__quote {
    margin: 0.4rem 0 1.25rem;
    font-family: var(--lp-font-display);
    font-size: 1.8rem;
    line-height: 1.22;
    letter-spacing: 0;
    font-weight: 600;
    text-wrap: balance;
    color: var(--lp-on-surface);
}

.lp-head-msg__body {
    margin: 0 0 1.5rem;
    color: var(--lp-on-surface-variant);
    font-size: 1.02rem;
    line-height: 1.65;
    text-wrap: pretty;
}

.lp-head-msg__by {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.lp-head-msg__name {
    font-weight: 700;
    letter-spacing: 0;
}

.lp-head-msg__role {
    color: var(--lp-on-surface-variant);
    font-size: 0.88rem;
}

/* ---------------------------------------------------------------------------
   Learning-card meta tag
   --------------------------------------------------------------------------- */

.lp-card__meta {
    display: inline-flex;
    align-self: flex-start;
    padding: 0.25rem 0.7rem;
    border-radius: var(--lp-radius-md);
    background: var(--lp-school-blue-wash);
    color: var(--lp-school-blue);
    font-size: 0.74rem;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: uppercase;
}

/* ---------------------------------------------------------------------------
   Testimonials
   --------------------------------------------------------------------------- */

.lp-quotes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
    gap: 1.25rem;
}

.lp-quote {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    margin: 0;
    padding: 1.75rem;
    border: 1px solid var(--lp-outline-variant);
    border-radius: var(--lp-radius-md);
    background: var(--lp-surface-lowest);
    box-shadow: var(--lp-shadow-sm);
}

.lp-quote blockquote {
    margin: 0;
    font-family: var(--lp-font-display);
    font-size: 1.1rem;
    line-height: 1.45;
    letter-spacing: 0;
    color: var(--lp-on-surface);
    text-wrap: pretty;
}

.lp-quote figcaption {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    margin-top: auto;
}

.lp-quote__name {
    font-weight: 700;
    font-size: 0.95rem;
}

.lp-quote__role {
    color: var(--lp-on-surface-variant);
    font-size: 0.84rem;
}

/* ---------------------------------------------------------------------------
   Admissions journey
   --------------------------------------------------------------------------- */

.lp-steps {
    list-style: none;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 1.25rem;
    margin: 0 0 1.5rem;
    padding: 0;
    counter-reset: lp-step;
}

.lp-step {
    display: flex;
    gap: 1rem;
    padding: 1.5rem;
    border: 1px solid var(--lp-outline-variant);
    border-radius: var(--lp-radius-md);
    background: var(--lp-surface-lowest);
    box-shadow: var(--lp-shadow-sm);
}

.lp-step__num {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: var(--lp-radius-md);
    background: var(--lp-primary-container);
    color: var(--lp-on-primary-container);
    font-family: var(--lp-font-display);
    font-weight: 700;
    font-size: 1.05rem;
}

.lp-step__title {
    margin: 0 0 0.3rem;
    font-size: 1.05rem;
    font-weight: 600;
    letter-spacing: 0;
}

.lp-step__body {
    margin: 0;
    color: var(--lp-on-surface-variant);
    font-size: 0.92rem;
    line-height: 1.5;
    text-wrap: pretty;
}

.lp-desk-notes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 1rem 1.5rem;
    margin: 0 0 1.5rem;
}

.lp-desk-notes dt {
    margin: 0 0 0.2rem;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: uppercase;
    color: var(--lp-on-surface-variant);
}

.lp-desk-notes dd {
    margin: 0;
    font-size: 0.95rem;
}

/* ---------------------------------------------------------------------------
   Back to top

   `hidden` in the markup until the view's script shows it, so a no-JS visitor
   never gets a button that cannot scroll.
   --------------------------------------------------------------------------- */

.lp-top {
    position: fixed;
    right: clamp(1rem, 4vw, 2rem);
    bottom: clamp(1rem, 4vw, 2rem);
    /* Content-overlays band (100–299): above the page, below app chrome and
       modals. Sits under the sticky header (200) when they overlap, which is
       the behaviour you want — the button tucks behind the bar, not over it. */
    z-index: 150;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.9rem;
    height: 2.9rem;
    border: none;
    border-radius: var(--lp-radius-md);
    background: var(--lp-primary-container);
    color: var(--lp-on-primary-container);
    box-shadow: var(--lp-shadow-md);
    cursor: pointer;
    transition: transform 0.2s var(--lp-ease), background 0.2s var(--lp-ease);
}

.lp-top[hidden] {
    display: none;
}

.lp-top:hover {
    transform: translateY(-3px);
    background: var(--lp-tertiary);
}

/* ---------------------------------------------------------------------------
   Scroll reveal

   The hidden state is scoped to `.lp-reveal-ready`, a class the view's
   script puts on <html>. That ordering matters: if the script never runs —
   JS disabled, a syntax error, a blocked file — the class is never added,
   the rule below never matches, and every section is simply visible. Putting
   `opacity: 0` in the base stylesheet instead would hand a no-JS visitor a
   blank page, which is the standard way this effect breaks sites.

   The script also declines to add the class when the visitor has asked for
   reduced motion, so the reduce block at the bottom of this file is a second
   line of defence rather than the only one.
   --------------------------------------------------------------------------- */

.lp-reveal-ready [data-reveal] {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity 0.55s var(--lp-ease), transform 0.55s var(--lp-ease);
}

.lp-reveal-ready [data-reveal].is-in {
    opacity: 1;
    transform: none;
}

/* Staggered children inside one revealed block. Delay only — the transition
   itself is inherited from the rule above. */
.lp-reveal-ready [data-reveal][data-reveal-delay="1"] { transition-delay: 0.08s; }
.lp-reveal-ready [data-reveal][data-reveal-delay="2"] { transition-delay: 0.16s; }
.lp-reveal-ready [data-reveal][data-reveal-delay="3"] { transition-delay: 0.24s; }
.lp-reveal-ready [data-reveal][data-reveal-delay="4"] { transition-delay: 0.32s; }

/* Page transitions are not here. A cross-document view transition only
   happens when *both* documents opt in and both name the same elements, so
   the opt-in and the names live in a single shared file — page-transitions.css
   — linked by this page, the public site layout and the sign-in screen. Split
   across three stylesheets they would drift, and the failure is silent: the
   navigation just stops morphing. */

/* ---------------------------------------------------------------------------
   Narrow viewports

   Fixed type sizes change only at clear breakpoints; spacing and grid columns
   can remain fluid without tying text size to viewport width.
   --------------------------------------------------------------------------- */

@media (max-width: 1023px) {
    .lp-hero {
        min-height: auto;
        display: block;
        padding: 0;
        background: var(--lp-surface);
    }

    /* At tablet and phone widths, give the message and school photograph
       their own space. The old 100% 9rem background size squeezed the
       campus photo into a shallow, visibly distorted ribbon. */
    .lp-hero > .lp-wrap {
        padding-block: clamp(2.5rem, 6vw, 4rem) 2.25rem;
    }

    .lp-hero::after {
        content: "";
        display: block;
        width: 100%;
        height: clamp(12rem, 31vw, 21rem);
        background-color: var(--lp-surface-high);
        background-image: url("../images/school-hero-campus.png");
        background-image: image-set(
            url("../images/school-hero-campus.webp") type("image/webp"),
            url("../images/school-hero-campus.png") type("image/png")
        );
        background-size: cover;
        background-position: center 46%;
    }

    .lp-section--raise {
        margin-top: 0;
        border-radius: 0;
        box-shadow: none;
    }
}

@media (min-width: 768px) and (max-width: 1023px) {
    .lp-hero h1 { font-size: 3rem; }
}

@media (max-width: 767px) {
    .lp-hero h1 { font-size: 2.5rem; }
    .lp-head h2 { font-size: 1.9rem; }
    .lp-head-msg__quote { font-size: 1.5rem; }
    .lp-hero :focus-visible { outline-color: var(--lp-school-blue); }
    .lp-portal span {
        /* Keep the button, drop the word: at this width the row has to fit
           a brand, a portal button and a menu button. */
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .lp-burger > span:last-child {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .lp-stats {
        /* Keep every trust signal visible without requiring a swipe. */
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0.65rem;
    }

    .lp-stat {
        min-width: 0;
        padding: 0.9rem 1rem;
    }

    .lp-footer__base {
        justify-content: flex-start;
    }
}

/* Desktop navigation appears once there is room for it. 1024px, not the
   1280px the approved design used: at 1100px there is ample room for six
   links and hiding them there is just lost space. */
@media (min-width: 1024px) {
    .lp-nav {
        display: flex;
    }

    .lp-burger {
        display: none;
    }

    .lp-drawer {
        display: none !important;
    }
}

/* ---------------------------------------------------------------------------
   Reduced motion

   Must stay last in this file. Every rule below wins on source order at
   equal specificity, so moving this block up silently re-enables the hover
   lifts and reveal animations it is here to suppress.

   The hover lifts are movement-only — colour, border and shadow feedback all
   survive, so nothing becomes less legible by removing the transform.
   --------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 1ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 1ms !important;
        transition-delay: 0ms !important;
        scroll-behavior: auto !important;
    }

    /* Each modifier is named rather than relying on the `.lp-btn:hover`
       shorthand. The modifiers declare their own `transform`, so a bare
       `.lp-btn:hover { transform: none }` sits at lower specificity and
       loses — `!important` happens to rescue it here, but a checker that
       matches selector to selector is right to object, and the next
       modifier added without an entry would not be rescued at all. */
    .lp-portal:hover,
    .lp-btn:hover,
    .lp-btn--filled:hover,
    .lp-hero .lp-btn--filled:hover,
    .lp-btn--tonal:hover,
    .lp-btn--ghost:hover,
    .lp-btn--on-invert:hover,
    .lp-stat:hover,
    .lp-card:hover,
    .lp-event:hover,
    .lp-top:hover {
        transform: none !important;
    }

    /* Belt and braces: the script already refuses to add .lp-reveal-ready
       under this setting, but if it is ever added by other means the
       content must still be visible rather than stuck at opacity 0. */
    .lp-reveal-ready [data-reveal] {
        opacity: 1 !important;
        transform: none !important;
    }
}
