@import url("theme_settings/theme_settings.css");
@import url("https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,700;1,400;1,700&family=Oswald:wght@600;700&display=swap");

:root {
    /* Theme tokens — every reference includes a diagnostic fallback so
       a missing theme_settings.css is visually obvious during review. */
    --color-1:        var(--color-1-theme, #00ff00);
    --color-2:        var(--color-2-theme, #ff00ff);
    --color-over-1:   var(--color-over-1-theme, #000000);
    --color-over-2:   var(--color-over-2-theme, #ffffff);
    --color-1-isDark: var(--color-1-theme-isDark, 0);
    --color-2-isDark: var(--color-2-theme-isDark, 0);

    /* Design literal, outside the CMS theme system: the admin exposes no
       third brand color, so this holds its value directly rather than
       resolving a --color-3-theme. It stands in for the source mockup's cream
       neutral. Having no CMS-guaranteed --color-over-3 pair, anything set on
       it needs a literal foreground checked for contrast. */
    --color-3: rgb(240, 240, 240);
    --color-over-3: #000;

    /* CTA accent — the block that sits rotated behind every call to action.
       Same design-literal status as --color-3: no CMS counterpart, no
       --color-over-4 pair, so it backs decoration only, never text. */
    --color-4: #DB7A73;

    /* Breakpoint tokens — media queries can't read custom properties,
       so the rem values repeat in @media (min-width: …) below. */
    --size-sm: 48rem;     /* tablet */
    --size-md: 64rem;     /* desktop */
    --size-lg: 85.375rem; /* large desktop */
    --size-xl: 120rem;    /* max content width */
}

html { height: 100%; }

body {
    margin: 0;
    min-height: 100%;
    display: flex;
    flex-direction: column;
    font-family: 'Open Sans', sans-serif;
    color: #333;
}

h1, h2, h3, h4 {
    font-family: 'Oswald', sans-serif;
    font-weight: 600;
}

/* Section titles share one scale. Kept here rather than in each section block
   so the step-up at 85.375rem (--size-lg, 1366px) can't be beaten by a
   per-section font-size declared later in the file. */
.hero__spot-title,
.news__heading,
.events__heading,
.staff-spotlights__title {
    font-size: 2rem;
}
@media (min-width: 85.375rem) {
    .hero__spot-title,
    .news__heading,
    .events__heading,
    .staff-spotlights__title {
        font-size: 2.5rem;
    }
}

.site-header,
.site-footer { flex: none; }

#content_main {
    flex: 1 0 auto;
    width: 100%;
    box-sizing: border-box;
    max-width: var(--inside-content-max, var(--size-lg));
    padding: var(--inside-content-pad-y, 1.5rem) var(--inside-content-pad-x, clamp(0.5rem, 5%, 3rem));
    margin-inline: auto;
    background-color: #fff;
}

/* Homepage reset — the .site-homepage wrapper in index.jsp gates this. */
body:has(.site-homepage) #content_main {
    max-width: none;
    padding: 0;
    background-color: transparent;
}

/* CMS-rendered page title on inside pages. margin-block keeps the
   CMS-supplied inline margins (which center the title on wide
   viewports) intact. filter: brightness keeps a light theme color
   legible when --color-1 is itself the foreground. */
.pageTitle {
    color: var(--color-1);
    filter: brightness(var(--color-1-isDark));
    font-size: 2rem;
    line-height: 1.25;
    margin-block: 0 1.5rem;
}

.site-header .site-skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 100;
    padding: 0.5rem 1rem;
    background-color: var(--color-1);
    color: var(--color-over-1);
    text-decoration: none;
}
.site-header .site-skip-link:focus-visible {
    left: 0;
}

/* Screen-reader-only text. The CMS system stylesheet also defines
   .hidden-text with the same technique; declaring it here keeps the
   pattern available regardless of system-stylesheet load order. */
.hidden-text {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
}

/* ==================== Page-level background video ====================
   One video, rendered once at the top of body (see header.jsp), shared by
   the identity band and the hero section below it so both read as one
   continuous clip instead of two independently-playing copies. Positioned
   against the page (no positioned ancestor) rather than fixed, so it
   scrolls normally and simply gets painted over by the opaque sections
   further down the page. Height is generous on purpose — any overshoot
   past the hero is hidden by that opaque content, so it doesn't need to
   track the hero's actual (variable) height. */
.site-bg-video {
    position: absolute;
    top: 0;
    left: 0;
    z-index: -1;
    width: 100%;
    height: max(100vh, 75rem);
    object-fit: cover;
}
.site-bg-video--embed iframe,
.site-bg-video--embed object,
.site-bg-video--embed embed {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

/* ==================== Header & Navigation ==================== */

/* No background-color here: the identity band shows the page-level
   .site-bg-video through it (see body). The nav bar paints its own opaque
   background (.site-nav) so it's unaffected. */
.site-header {
    position: relative;
    display: grid;
    grid-template-areas:
        "nav"
        "identity";
    grid-template-columns: 1fr;
    color: var(--color-over-3);
}
@media (min-width: 64rem) {
    .site-header {
        grid-template-areas:
            "nav"
            "identity";
        grid-template-columns: 1fr;
    }
}

.site-header__identity {
    position: relative;
    grid-area: identity;
    padding: 1rem;
    text-align: center;
}
/* Tint film over the shared background video showing through from behind
   (see .site-bg-video) — keeps the logo/name legible without hiding the
   video entirely. */
.site-header__identity::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    background-color: color-mix(in srgb, var(--color-3), transparent 20%);
}
.site-header__logo-link {
    position: relative;
    z-index: 1;
}
/* Extra top padding below 600px clears the burger, which sits in the header's
   top-right corner at these widths. */
@media (max-width: 37.4375rem) {
    .site-header__identity { padding-top: calc(1rem + 44px); }
}
@media (min-width: 64rem) {
    .site-header__identity { text-align: left; }
}
.site-header__logo-link {
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    color: inherit;
    text-decoration: none;
}
.site-header__logo {
    height: 106px;
    width: auto;
}
.site-header__name {
    font-family: 'Oswald', sans-serif;
    font-size: 1.75rem;
    font-weight: 600;
    color: var(--color-1);
    filter: brightness(var(--color-1-isDark));
}

/* [Structural] Nav bar band — desktop shows the horizontal nav, mobile shows
   the hamburger nav. Both variants occupy the same grid area. */
.site-nav {
    grid-area: nav;
    background-color: var(--color-1);
}
.site-nav .nav-menu {
    display: flex;
    flex-direction: column;
    list-style: none;
    margin: 0;
    padding: 0;
}
.site-nav .nav-item-inner,
.site-nav .dropdown-toggle {
    color: var(--color-over-1);
    background: none;
    border: 0;
    font: inherit;
    cursor: pointer;
}
.site-nav .dropdown-toggle { text-decoration: none; }
.site-nav .sub-menu-item > a:hover,
.site-nav .sub-menu-item > a:focus-visible {
    background-color: color-mix(in srgb, var(--color-1), #fff 15%);
}
.site-nav .nav-item-inner,
.site-nav .sub-menu-item > a {
    display: block;
    padding: 0.75rem 1rem;
}

/* Dropdown disclosure icon */
.dropdown-toggle::after {
    font-family: 'Material Symbols Outlined';
    font-variation-settings: 'FILL' 1;
    text-transform: none;
    content: 'expand_more';
    display: inline-block;
    line-height: 1;
    transition: transform 0.2s ease;
}
.nav-item:hover > .dropdown-toggle::after,
.nav-item:focus-within > .dropdown-toggle::after {
    transform: rotate(180deg);
}

/* [Structural] Level-2 holder watches for .show; level-3 has no holder. */
.site-nav .sub-menu-holder { display: none; }
.site-nav .sub-menu-holder:has(.sub-menu.show) { display: block; }
.site-nav .sub-menu .sub-menu { display: none; }
.site-nav .sub-menu .sub-menu.show { display: block; }

.site-nav .sub-menu {
    list-style: none;
    margin: 0;
    padding: 0;
    background-color: color-mix(in srgb, var(--color-1), #000 10%);
}
.site-nav .sub-menu .nav-item-inner {
    color: var(--color-over-1);
}

/* ---- Mobile nav ---- */
.site-nav--desktop { display: none; }
.site-nav--mobile { display: block; }

/* Hidden from 64rem up, so this base rule is the mobile one. */
.menu-toggle {
    position: absolute;
    top: 0;
    right: 0;
    width: 2.75rem;
    height: 2.75rem;
    background: none;
    border: 0;
    color: var(--color-1);
    cursor: pointer;
}
.menu-toggle::after {
    font-family: 'Material Symbols Outlined';
    font-variation-settings: 'FILL' 1;
    text-transform: none;
    content: 'menu';
    font-size: 1.75rem;
}
.menu-toggle[aria-expanded="true"]::after { content: 'close'; }

.site-nav--mobile .nav-menu {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 50;
    background-color: var(--color-1);
}
.site-nav--mobile .nav-menu.show { display: flex; }

/* Top-level dropdown items need the same label+toggle row treatment as
   sub-menu items below, or the toggle (a block-level button) wraps onto its
   own line under the label instead of sitting beside it. */
.site-nav--mobile .nav-item.dropdown,
.site-nav--mobile .sub-menu-item.dropdown {
    display: grid;
    grid-template-columns: 1fr auto;
}
.site-nav--mobile .sub-menu-holder,
.site-nav--mobile .sub-menu .sub-menu {
    grid-column: 1 / -1;
}
.site-nav--mobile .sub-menu-item > a { padding-left: 2rem; }
.site-nav--mobile .sub-menu .sub-menu .sub-menu-item > a { padding-left: 3rem; }

@media (min-width: 64rem) {
    .site-nav--desktop {
        display: flex;
        align-items: center;
        justify-content: center;
    }
    .site-nav--mobile { display: none; }
    .menu-toggle { display: none; }

    .site-nav--desktop .nav-menu {
        flex: 0 0 auto;
        flex-direction: row;
        justify-content: center;
    }

    /* Level-1 overlay pattern: label and toggle share one cell */
    .site-nav--desktop .nav-item {
        position: relative;
        display: grid;
    }
    .site-nav--desktop .nav-item.dropdown > .nav-item-inner,
    .site-nav--desktop .nav-item.dropdown > div.nav-item-inner {
        grid-column: 1;
        grid-row: 1;
        position: relative;
        z-index: 1;
        margin-right: 2rem;
    }
    .site-nav--desktop .nav-item.dropdown > div.nav-item-inner {
        pointer-events: none;
    }
    .site-nav--desktop .nav-menu > .nav-item > .dropdown-toggle {
        grid-column: 1;
        grid-row: 1;
        width: 100%;
        height: 100%;
        display: flex;
        justify-content: flex-end;
        align-items: center;
        padding-right: 0.5rem;
    }
    /* Text and the dropdown arrow share one grid cell; centering both the
       same way (flex + align-items) keeps their optical baselines matched
       regardless of each glyph's own font metrics. */
    .site-nav--desktop .nav-item-inner {
        display: flex;
        align-items: center;
        height: 100%;
        padding-top: 1.5rem;
        padding-bottom: 1.5rem;
        box-sizing: border-box;
    }

    /* Tighter horizontal spacing between 64rem and 80rem: at tablet-ish
       widths, five nav items plus the translate widget at full desktop
       spacing don't fit — the row overflowed and clipped both ends
       (Board of Education on the left, the translate widget on the right).
       Padding tightens back up past 80rem. */
    @media (max-width: 79.9375rem) {
        .site-nav--desktop .nav-item-inner {
            padding-left: 0.5rem;
            padding-right: 0.5rem;
        }
        .site-nav--desktop .nav-item.dropdown > .nav-item-inner,
        .site-nav--desktop .nav-item.dropdown > div.nav-item-inner {
            margin-right: 1.25rem;
        }
        #google_translate_element {
            font-size: 0.8125rem;
        }
    }

    /* Level-2 dropdown panel */
    .site-nav--desktop .sub-menu-holder {
        position: absolute;
        top: 100%;
        left: 0;
        min-width: 14rem;
        z-index: 60;
    }
    .site-nav--desktop .nav-item.drop-left .sub-menu-holder {
        left: auto;
        right: 0;
    }
    .site-nav--desktop .sub-menu-item.dropdown {
        display: grid;
        grid-template-columns: 1fr auto;
    }
    .site-nav--desktop .sub-menu-item.dropdown > .dropdown-toggle {
        grid-column: 2;
        width: auto;
    }

    /* Level-3 flyout */
    .site-nav--desktop .sub-menu .sub-menu {
        position: absolute;
        top: 0;
        left: 100%;
        min-width: 14rem;
    }
    .site-nav--desktop .nav-item.drop-left .sub-menu-item.dropdown > .sub-menu {
        left: auto;
        right: 100%;
    }
}

/* ---- Nav-bar translate widget ---- */
#google_translate_element {
    display: none;
}
@media (min-width: 64rem) {
    #google_translate_element {
        display: block;
        flex: 0 0 auto;
        padding: 0.375rem 0.5rem;
        background-color: #fff;
        border-radius: 8px;
    }
}

.site-header .site-header__logo-link { color: inherit; }

/* ==================== Call to action ====================
   Shared by every primary CTA: a rotated accent block offset behind the
   button face. The anchor is only the positioning context — the face lives on
   .cta__label so that both layers are positioned siblings painted in DOM
   order, the accent first and the face over it. The accent can't instead sit
   at z-index -1 under a filled anchor: negative-index children paint before
   in-flow block backgrounds, so the section's own background would cover it. */
.cta {
    position: relative;
    display: inline-block;
    text-decoration: none;
    font-weight: 700;
}
.cta::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 8px;
    background-color: var(--color-4);
    transform: translate(6px, 6px) rotate(-3deg);
}
.cta__label {
    position: relative;
    display: block;
    padding: 0.75rem 1.5rem;
    border: 2px solid var(--color-2);
    border-radius: 8px;
    background-color: var(--color-1);
    transition: background-color 0.2s ease, border-color 0.2s ease;
}
/* The system stylesheet colors every a:link/:visited/:hover at #333 and loads
   after this file, so the label needs a specificity bump to keep the
   --color-over-1 pairing its background depends on. */
body .cta.cta { color: var(--color-over-1); }
body .cta.cta:hover,
body .cta.cta:focus-visible {
    color: #000;
    transition: color 0.2s ease;
}
body .cta:hover .cta__label,
body .cta:focus-visible .cta__label {
    background-color: #fff;
    border-color: var(--color-1);
}

/* ==================== Hero: Shuffle + Spotlight 1 ==================== */

/* No background-color here: the section shows the page-level
   .site-bg-video through it (see body), continuing the same clip from the
   identity band above. */
.hero {
    position: relative;
    padding: 2rem 1rem;
}
/* Tint film over the shared video for text/carousel contrast. */
.hero::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    background-color: color-mix(in srgb, var(--color-3), transparent 20%);
}
.hero__inner {
    position: relative;
    z-index: 1;
}
/* minmax(0, …) on every track: a bare 1fr or auto track takes its minimum
   from content, and the slide track's intrinsic width is the sum of its
   slides — enough to push the whole grid past the viewport. */
.hero__inner {
    display: grid;
    grid-template-areas:
        "media"
        "spot";
    grid-template-columns: minmax(0, 1fr);
    gap: 2rem;
    max-width: var(--size-xl);
    margin-inline: auto;
    box-sizing: border-box;
}
.hero__spot { grid-area: spot; }
.hero__media { grid-area: media; }

@media (min-width: 48rem) {
    .hero { padding: 3rem 2rem; }
    .hero__inner {
        grid-template-areas: "spot hero";
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        align-items: center;
    }
    .hero__media { grid-area: hero; }
}

.hero__spot-title {
    color: var(--color-1);
    filter: brightness(var(--color-1-isDark));
    margin: 0 0 1rem;
}
.hero__spot-body {
    margin: 0 0 1.5rem;
    line-height: 1.5;
}
.hero .hero__spot-body a { color: inherit; }

/* .hero__media sizes and centres the media column. The circular frame lives
   on the slide, so nothing here borders, rounds or clips — slide height
   comes from the image, which is square at source. */
.hero__media {
    position: relative;
    width: min(100%, 26rem);
    margin-inline: auto;
}

/* ---- Swiper carousel, scoped to .hero__carousel (nested inside .hero__media) ---- */
/* position: relative per hero.md — this is the swiper-container element, and
   the containing block for the autoplay toggle that sits outside
   .swiper-holder. width: 100% on .swiper is also canonical: without an
   explicit width Swiper measures pre-layout and computes 2^25px slides. */
.hero__carousel {
    position: relative;
    width: 100%;
}
.hero__carousel .swiper { width: 100%; }

/* The slide is the circular frame. */
.hero__carousel .swiper-slide {
    border-radius: 50%;
    overflow: hidden;
}
/* Split ground behind the slide image: color-1 over the top half, color-2
   over the bottom, showing through the 24px gutter. */
.hero__carousel .hero__slide-inner {
    box-sizing: border-box;
    padding: 24px;
    background: linear-gradient(to bottom, var(--color-1) 50%, var(--color-2) 50%);
}
/* A color-2 semicircle across the bottom of the media — a 2:1 box domed by a
   border-radius whose vertical radius is its full height, so it reads as the
   top half of a circle. One shape for the carousel rather than one per slide.
   Absolute rather than shifted by a negative margin: a margin big enough to
   place it would also subtract that much from the container's height. */
.hero__carousel::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    aspect-ratio: 2 / 1;
    border-radius: 50% 50% 0 0 / 100% 100% 0 0;
    background-color: var(--color-2);
}
.hero__carousel figure { margin: 0; }
.hero__carousel .swiper-slide img {
    display: block;
    width: 100%;
    border-radius: 50%;
}
/* Prev/next and the autoplay toggle sit together at the bottom of the slider
   rather than at its edges, so each button's own absolute placement, insets
   and centring margin are cleared and the row positions them as one cluster. */
.hero__controls {
    position: absolute;
    bottom: 28px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 10;
    display: flex;
    align-items: center;
}
.hero__carousel .swiper-button-prev,
.hero__carousel .swiper-button-next {
    --swiper-navigation-color: #fff;
    --swiper-navigation-bg: rgba(0, 0, 0, 0.5);
    --swiper-navigation-size: 2rem;
    /* Swiper's button is 27x44 with no surface, and <button> brings its own
       border and padding — both neutralized for the filled circular pair. */
    position: static;
    inset: auto;
    margin: 0;
    width: 2.75rem;
    height: 2.75rem;
    border: 0;
    padding: 0;
    border-radius: 50%;
    background-color: var(--swiper-navigation-bg);
}
.hero__carousel .swiper-button-prev::after,
.hero__carousel .swiper-button-next::after {
    font-family: 'Material Symbols Outlined';
    font-variation-settings: 'FILL' 1;
    text-transform: none;
    font-size: var(--swiper-navigation-size);
}
.hero__carousel .swiper-button-prev::after { content: 'arrow_left'; }
.hero__carousel .swiper-button-next::after { content: 'arrow_right'; }
/* Below 64rem the arrows are the only way to advance — no autoplay, no hover —
   so they render regardless of the shuffle's navigation setting. This departs
   from hero.md, which gates them on navigation type at every width; the gate
   applies from 64rem up (see the media block below). */
.hero__carousel {
    --swiper-pagination-color: var(--color-over-2);
    --swiper-pagination-bullet-text-color: var(--color-2);
    --swiper-pagination-bullet-size: 1.5rem;
}
.hero__carousel .numbered-pagination .swiper-pagination-bullet {
    place-content: center;
    color: var(--swiper-pagination-bullet-text-color, #000);
}

/* [Structural] figcaption — mobile: below image in flow; desktop: overlay */
.hero__carousel figcaption {
    background-color: rgba(0, 0, 0, 0.85);
    color: #fff;
    margin: 0;
    padding: 0.5rem 1rem;
}
@media (min-width: 48rem) {
    .hero__carousel figcaption {
        position: absolute;
        left: 0;
        right: 0;
        background-color: rgba(0, 0, 0, 0.75);
    }
    .hero__carousel figcaption.caption-position-top { top: 0; }
    .hero__carousel figcaption.caption-position-bottom { bottom: 0; }

    .hero__carousel .navigation-position-top    { --swiper-pagination-top: 0.5rem; --swiper-pagination-bottom: auto; }
    .hero__carousel .navigation-position-bottom { --swiper-pagination-bottom: 0.5rem; --swiper-pagination-top: auto; }
    .hero__carousel .navigation-position-left   { --swiper-pagination-left: 0.5rem; --swiper-pagination-right: auto; }
    .hero__carousel .navigation-position-right  { --swiper-pagination-right: 0.5rem; --swiper-pagination-left: auto; }

    /* Caption offsets — prevents pagination from overlapping caption text */
    .hero__carousel .navigation-position-top    figcaption.caption-position-top    { padding-top:    calc(var(--swiper-pagination-bullet-size, 1rem) + 1rem); }
    .hero__carousel .navigation-position-bottom figcaption.caption-position-bottom { padding-bottom: calc(var(--swiper-pagination-bullet-size, 1rem) + 1rem); }
    .hero__carousel .navigation-position-left   figcaption                         { padding-left:   calc(var(--swiper-pagination-bullet-size, 1rem) + 1rem); }
    .hero__carousel .navigation-position-right  figcaption                         { padding-right:  calc(var(--swiper-pagination-bullet-size, 1rem) + 1rem); }

    /* Arrows always occupy left and right edges */
    .hero__carousel .navigation-type-1 figcaption { padding-left: calc(var(--swiper-navigation-size, 44px) + 0.5rem); padding-right: calc(var(--swiper-navigation-size, 44px) + 0.5rem); }
}
@media (max-width: 47.9375rem) {
    .hero__carousel .swiper-pagination-vertical {
        flex-direction: row;
        width: auto;
    }
}

/* Autoplay toggle — a flow item in .hero__controls, so its own absolute
   placement and insets are cleared; the row does the positioning. Hidden below
   64rem by CSS alone, per hero.md's rule that this is never a JS decision.
   64rem rather than the doc's 48rem: autoplay is desktop-only here, and the
   arrows take over advancing below it. */
.hero__carousel .swiper-autoplay-toggle-button {
    position: static;
    inset: auto;
    margin: 0;
    display: none;
    width: 2.25rem;
    height: 2.25rem;
    border: 0;
    border-radius: 50%;
    background-color: rgba(0, 0, 0, 0.5);
    color: #fff;
    cursor: pointer;
}
@media (min-width: 64rem) {
    .hero__carousel .swiper-autoplay-toggle-button { display: block; }

    /* From here up the shuffle's own navigation setting governs the arrows,
       per hero.md — only navigation type 1 shows them. */
    .hero__carousel:not(:has(.navigation-type-1)) .swiper-button-prev,
    .hero__carousel:not(:has(.navigation-type-1)) .swiper-button-next {
        display: none;
    }

    /* Arrows and autoplay are alternatives, never both: once the toggle is in
       play the arrows stand down. Keyed on the toggle actually being in the
       DOM, so a shuffle with no rotate time keeps its arrows at every width. */
    .hero__controls:has(.swiper-autoplay-toggle-button) .swiper-button-prev,
    .hero__controls:has(.swiper-autoplay-toggle-button) .swiper-button-next {
        display: none;
    }
}
.hero__carousel .swiper-autoplay-toggle-button::after {
    font-family: 'Material Symbols Outlined';
    font-variation-settings: 'FILL' 1;
    text-transform: none;
    content: 'pause';
    font-size: 1.25rem;
}
.hero__carousel .swiper-autoplay-toggle-button.paused::after { content: 'play_arrow'; }

/* ==================== Icon color flattening ====================
   Canonical .flat-icon-colors mechanism (see components/links.md): flattens
   two-tone brand SVGs (.color-fill / .transparency-change paths, gated on
   .color-flatten) and uniform single-tone icons alike to currentColor.
   Applied to Quick Links and Infographic tile icons, which sit on themed
   circular badges; header/pre-footer social icons omit this class to keep
   their native brand colors. */
.flat-icon-colors svg.color-flatten .color-fill { fill: currentColor; }
.flat-icon-colors svg.color-flatten .transparency-change { fill: transparent; }
.flat-icon-colors svg:not(.color-flatten) { fill: currentColor; }

/* ==================== Shared carousel chrome ====================
   Quick Links / Recent News / Upcoming Events all use the filled-square
   button pair with arrow glyphs (the hero uses its own circular button
   pair, styled separately under .hero__carousel above). */
.quicklinks__carousel,
.news__carousel,
.events__carousel {
    position: relative;
}
/* Keeps the arrows at the track's edges, so the container is padded to
   clear them. Padding rather than a margin on .swiper: absolutely
   positioned children offset against the padding box, so the buttons stay put
   while the track narrows — and .swiper keeps the definite width Swiper needs
   to avoid computing a 2^25px slide track. */
.news__carousel {
    padding-inline: 64px;
}
.quicklinks__carousel .swiper,
.news__carousel .swiper,
.events__carousel .swiper {
    width: 100%;
}
.quicklinks__carousel .swiper-button-prev,
.quicklinks__carousel .swiper-button-next,
.news__carousel .swiper-button-prev,
.news__carousel .swiper-button-next,
.events__carousel .swiper-button-prev,
.events__carousel .swiper-button-next {
    width: 2.75rem;
    height: 2.75rem;
    /* <button> brings its own border and padding; Swiper doesn't clear them. */
    border: 0;
    padding: 0;
    border-radius: 0.5rem;
    background-color: var(--color-1);
    color: var(--color-over-1);
    --swiper-navigation-size: 1.5rem;
}
.quicklinks__carousel .swiper-button-prev::after,
.quicklinks__carousel .swiper-button-next::after,
.news__carousel .swiper-button-prev::after,
.news__carousel .swiper-button-next::after,
.events__carousel .swiper-button-prev::after,
.events__carousel .swiper-button-next::after {
    font-family: 'Material Symbols Outlined';
    font-variation-settings: 'FILL' 1;
    text-transform: none;
}
.quicklinks__carousel .swiper-button-prev::after,
.news__carousel .swiper-button-prev::after,
.events__carousel .swiper-button-prev::after { content: 'arrow_left'; }
.quicklinks__carousel .swiper-button-next::after,
.news__carousel .swiper-button-next::after,
.events__carousel .swiper-button-next::after { content: 'arrow_right'; }

.quicklinks__carousel:has(.swiper-button-prev.swiper-button-disabled):has(.swiper-button-next.swiper-button-disabled) .swiper-button,
.news__carousel:has(.swiper-button-prev.swiper-button-disabled):has(.swiper-button-next.swiper-button-disabled) .swiper-button,
.events__carousel:has(.swiper-button-prev.swiper-button-disabled):has(.swiper-button-next.swiper-button-disabled) .swiper-button {
    display: none;
}

/* ==================== Quick Links ==================== */

.quicklinks {
    background-color: var(--color-1);
    color: var(--color-over-1);
    padding: 2.5rem 1rem;
    text-align: center;
}
.quicklinks__inner {
    max-width: 1000px;
    margin-inline: auto;
}

/* Open-book frame (pics/quicklinks-book.svg, inlined by index.jsp). A single
   grid cell holds both layers: the art spans every track, the carousel takes
   the inner `page` area, and the track sizes are what hold the slides inside
   the paper well instead of over the cover. The edge tracks are asymmetric
   below 42rem because the left edge is the binding, not a cover.

   Below 42rem only the book's right-hand page is shown: the frame takes that
   page's aspect ratio and the art is drawn at twice the frame width and
   shifted left by one frame width, so the spread's right half fills it. A
   single page is tall enough for a column of two tiles; the full spread at
   this width would not be. */
.quicklinks__book {
    display: grid;
    grid-template-columns: 8% 1fr 8%;
    grid-template-rows: 16% 1fr 16%;
    grid-template-areas:
        ".  .     ."
        ".  page  ."
        ".  .     .";
    aspect-ratio: 499 / 626;
    overflow: hidden;
}
.quicklinks__book-art {
    grid-area: 1 / 1 / -1 / -1;
    min-width: 0;
    width: 200%;
    height: 100%;
    transform: translateX(-50%);
}
.quicklinks__book-art .book-cover  { fill: var(--color-2); }
.quicklinks__book-art .book-paper  { fill: color-mix(in srgb, var(--color-1), #fff 94%); }
.quicklinks__book-art .book-edge-a { fill: color-mix(in srgb, var(--color-1), #fff 88%); }
.quicklinks__book-art .book-edge-b { fill: color-mix(in srgb, var(--color-1), #fff 80%); }
.quicklinks__book-art .book-ring   { fill: var(--color-1); }
.quicklinks__book-art .book-ring-cap { fill: color-mix(in srgb, var(--color-1), #000 45%); }
/* Below 42rem, only the binding-side sliver of the cover is visible next to
   the page (see .quicklinks__book-art's crop/shift comment above), leaving
   the rings looking small against that empty margin. Scaling them up fills
   that space without touching the page-track proportions — growing from the
   left edge (not the center) so they extend rightward into the gutter
   instead of past the book's own left edge, where .quicklinks__book's
   overflow: hidden would otherwise clip them into half-rings. */
@media (max-width: 41.9375rem) {
    .quicklinks__book-art .book-ring,
    .quicklinks__book-art .book-ring-cap {
        transform-box: fill-box;
        transform-origin: left center;
        transform: scale(1.4);
    }
}
.quicklinks__book-art .book-gloss  { fill: color-mix(in srgb, var(--color-1), #fff 85%); }

/* Page-turn cue on the decorative book art, synced to the fake flip in
   index.jsp (the .is-flipping-prev / .is-flipping-next classes Swiper
   toggles during the transition, one per click direction). The cover and
   rings (spine) stay put; only the clicked side's paper layers lift, as if
   that page is turning, while the tile content fades over it. fill-box
   pivots each path from its own bounding box rather than the SVG
   viewport's — the right page pivots from its left edge (the spine sits to
   its left); the left page mirrors that from its right edge. */
.quicklinks__book-art .book-paper,
.quicklinks__book-art .book-edge-a,
.quicklinks__book-art .book-edge-b {
    transform-box: fill-box;
}
.quicklinks__book-art .book-paper--right,
.quicklinks__book-art .book-edge-a--right,
.quicklinks__book-art .book-edge-b--right {
    transform-origin: left center;
}
.quicklinks__book-art .book-paper--left,
.quicklinks__book-art .book-edge-a--left,
.quicklinks__book-art .book-edge-b--left {
    transform-origin: right center;
}
.quicklinks__book:has(.swiper.is-flipping-next) .book-paper--right,
.quicklinks__book:has(.swiper.is-flipping-next) .book-edge-a--right,
.quicklinks__book:has(.swiper.is-flipping-next) .book-edge-b--right {
    animation: quicklinks-page-turn-right 0.45s ease;
}
.quicklinks__book:has(.swiper.is-flipping-prev) .book-paper--left,
.quicklinks__book:has(.swiper.is-flipping-prev) .book-edge-a--left,
.quicklinks__book:has(.swiper.is-flipping-prev) .book-edge-b--left {
    animation: quicklinks-page-turn-left 0.45s ease;
}
@keyframes quicklinks-page-turn-right {
    0%, 100% { transform: none; }
    50% { transform: perspective(600px) translateX(-12%) rotateY(-145deg) scaleX(0.5); }
}
@keyframes quicklinks-page-turn-left {
    0%, 100% { transform: none; }
    50% { transform: perspective(600px) translateX(12%) rotateY(145deg) scaleX(0.5); }
}

/* width stays at the shared chrome's 100% — resolved against the `page` area
   here. Leaving it auto lets Swiper compute a 2^25px slide track. */
.quicklinks__carousel .swiper {
    grid-area: page;
    position: relative;
    z-index: 99;
    min-width: 0;
}
/* The slide track is a <ul>; without this reset its UA padding offsets every
   slide from the track by 40px. */
.quicklinks__carousel .swiper-wrapper {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* One page holds a column of two tiles at every width. */
.quicklinks__page {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 6%;
    list-style: none;
    margin: 0;
    padding: 0;
    height: 100%;
    transition: opacity 0.2s ease;
}
/* Faked page-turn: while Swiper slides the underlying pages into position
   (see quicklinksSwiperConfig's speed + transition hooks in index.jsp), the
   pages themselves fade out and back in, hiding the actual slide motion. */
.quicklinks__carousel .swiper.is-flipping-next .quicklinks__page,
.quicklinks__carousel .swiper.is-flipping-prev .quicklinks__page {
    opacity: 0;
}
.quicklinks__item {
    display: flex;
    min-height: 0;
}

/* Tile: a --color-2 circle with the title band painted over the photo's lower
   half rather than beside it, so the photo stays a full circle underneath.
   The photo's ring is a full circular border, but the band covers its lower
   half — so only the arc across the top is ever visible. */
/* Sized down below 42rem: the book's page track is shorter there (single
   page, not the full two-page spread), and two 160px tiles plus the column
   gap don't fit its height — the top and bottom tiles were clipping flat
   against the book's overflow:hidden edge instead of staying round. This
   breakpoint matches quicklinksSwiperConfig's slidesPerView breakpoint in
   index.jsp (672px / 42rem) — keep them in sync, or the tile size and the
   one/two-page layout fall out of step. */
.quicklinks__tile {
    position: relative;
    display: block;
    width: 120px;
    height: 120px;
    border-radius: 50%;
    overflow: hidden;
    background-color: var(--color-2);
    text-decoration: none;
}
@media (min-width: 42rem) {
    .quicklinks__tile {
        width: 160px;
        height: 160px;
    }
}
.quicklinks__tile-photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    border: 12px solid var(--color-1);
    border-radius: 50%;
    object-fit: cover;
    transition: transform 0.3s ease;
}
@media (min-width: 42rem) {
    .quicklinks__tile-photo { border-width: 16px; }
}
.quicklinks__tile:hover .quicklinks__tile-photo,
.quicklinks__tile:focus-visible .quicklinks__tile-photo {
    transform: scale(1.15);
}
.quicklinks__tile-title {
    position: absolute;
    inset: 50% 0 0;
    display: flex;
    align-items: start;
    justify-content: center;
    padding: 4px 10px;
    background-color: var(--color-2);
    font-weight: 700;
    font-size: clamp(0.7rem, 2.2vw, 1rem);
    line-height: 1.2;
    text-align: center;
    transition: background-color 0.3s ease, color 0.3s ease;
}
@media (min-width: 42rem) {
    .quicklinks__tile-title { padding: 6px 26px; }
}
.quicklinks .quicklinks__tile { color: var(--color-over-2); }
.quicklinks .quicklinks__tile:hover .quicklinks__tile-title,
.quicklinks .quicklinks__tile:focus-visible .quicklinks__tile-title {
    background-color: var(--color-1);
    color: var(--color-over-1);
}

/* Arrows sit in a row beneath the book rather than overlaying it, so the
   Swiper defaults (absolute, side insets, centring margin) are cleared. */
.quicklinks__controls {
    display: flex;
    justify-content: center;
    gap: 1rem;
    margin-top: 1.5rem;
}
.quicklinks__carousel .swiper-button-prev,
.quicklinks__carousel .swiper-button-next {
    position: static;
    inset: auto;
    margin: 0;
    /* The shared chrome fills these with --color-1, which this section now
       uses as its own band; swap to the --color-2 pair to stay visible. */
    background-color: var(--color-2);
    color: var(--color-over-2);
}

@media (min-width: 42rem) {
    /* Both pages of the spread are in view from here up, so the art is drawn
       at frame width and both edge tracks clear a cover. */
    .quicklinks__book {
        grid-template-columns: 9% 1fr 9%;
        aspect-ratio: 999 / 626;
    }
    .quicklinks__book-art {
        width: 100%;
        transform: none;
    }
}

/* ==================== Recent News (custom placement, directly after Quick Links) ==================== */

.news {
    padding: 2.5rem 1rem;
    background-color: var(--color-3);
    color: var(--color-over-3);
    text-align: center;
}
.news__inner {
    max-width: var(--size-lg);
    margin-inline: auto;
}
.news__heading {
    margin: 0 0 1.5rem;
}
.news .news__heading {
    color: var(--color-1);
    filter: brightness(var(--color-1-isDark));
}
/* No clipping on the card: the photo's offset shadow overhangs it. The card
   carries no fill — the section's --color-3 ground shows through. */
.news__card {
    text-align: left;
    height: 100%;
    box-sizing: border-box;
}
/* Torn-paper photo mount, three layers stacked by explicit z-index because
   the shadow has to sit under an in-flow image: ::after is the accent shadow,
   the image itself is raised above it, and ::before is the tape on top. The
   image takes the mask's own 274x231 ratio — stretching the mask to a
   different aspect distorts the torn edge. Both masks are plain SVG files
   fetched by CSS, so neither is inlined. */
.news__card-photo,
.staff-spotlights__photo {
    position: relative;
}
.news__card-photo img,
.news__card-photo::after,
.staff-spotlights__photo img,
.staff-spotlights__photo::after {
    width: 100%;
    aspect-ratio: 274 / 231;
    -webkit-mask-image: url("/pics/thumbnail-shape-a.svg");
    mask-image: url("/pics/thumbnail-shape-a.svg");
    -webkit-mask-size: 100% 100%;
    mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
}
.news__card-photo img,
.staff-spotlights__photo img {
    position: relative;
    z-index: 1;
    object-fit: cover;
    display: block;
}
.news__card-photo::after,
.staff-spotlights__photo::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    z-index: 0;
    translate: 8px 8px;
    background-color: var(--color-4);
}
.news__card-photo::before,
.staff-spotlights__photo::before {
    content: '';
    position: absolute;
    top: 0;
    left: 50%;
    translate: -50% 0;
    z-index: 2;
    width: 114px;
    height: 42px;
    -webkit-mask-image: url("/pics/thumbnail-shape-b.svg");
    mask-image: url("/pics/thumbnail-shape-b.svg");
    -webkit-mask-size: 100% 100%;
    mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
}
.news__card-photo::before {
    background-color: color-mix(in srgb, var(--color-1), transparent 40%);
}
/* Spotlight messages only: white tape instead of the news cards' blue,
   since these sit on a --color-1 (blue) section background where the blue
   tape would nearly disappear. */
.staff-spotlights__photo::before {
    background-color: color-mix(in srgb, #fff, transparent 25%);
}
.news__card-title {
    margin: 1rem 1rem 0.5rem;
    font-size: 1.125rem;
}
.news .news__card-title a {
    color: var(--color-1);
    filter: brightness(var(--color-1-isDark));
    text-decoration: none;
}
.news .news__card-title a:hover,
.news .news__card-title a:focus-visible { text-decoration: underline; }
.news__card-summary {
    margin: 0 1rem 1rem;
    color: #555;
    line-height: 1.5;
}
.news__cta { margin-top: 2rem; }

/* ==================== Upcoming Events ==================== */

/* Both gradient stops sit at the same offset, so the band is a hard edge
   rather than a fade — it separates this section from the white one above,
   which its --color-3 ground would otherwise merge into. */
.events {
    --events-band-offset: 218px;
    padding: 2.5rem 1rem;
    background-color: var(--color-3);
    background-image: linear-gradient(to bottom,
        var(--color-1) var(--events-band-offset),
        transparent var(--events-band-offset));
    color: var(--color-over-3);
    text-align: center;
}
.events__inner {
    max-width: var(--size-lg);
    margin-inline: auto;
}
.events__heading {
    margin: 0 0 1.5rem;
}
.events .events__heading {
    color: var(--color-over-1);
}
/* The card is only the column; the date and body are the two visual blocks
   and each owns its padding and its half of the corners. The card carries no
   fill of its own — one behind the date's rounded top corners would show
   through them as notches. */
.events__card {
    display: flex;
    flex-direction: column;
    text-align: center;
    height: 100%;
    box-sizing: border-box;
}

/* Date badge with the clipboard clip: ::before is the bar, ::after the bump
   centred on its top edge, the two reading as one hook. The badge is the
   positioning context and pads its top so the date clears them. */
.events__card-date {
    position: relative;
    background-color: var(--color-2);
    color: var(--color-over-2);
    border-radius: 0.5rem 0.5rem 0 0;
    padding: 2.75rem 1rem 1rem;
    display: flex;
    justify-content: center;
    gap: 0.375rem;
    font-size: 1.5rem;
}
/* Clipboard clip on the events date badge. The bar and the bump together
   read as one hook; the host element supplies its own position: relative
   and enough top padding to clear them. */
.events__card-date::before {
    content: '';
    position: absolute;
    top: 1.25rem;
    left: 50%;
    translate: -50% 0;
    width: 100px;
    height: 14px;
    border-radius: 999px;
    background-color: var(--color-1);
}
.events__card-date::after {
    content: '';
    position: absolute;
    top: 0.75rem;
    left: 50%;
    translate: -50% 0;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background-color: var(--color-1);
}
.events__card-month,
.events__card-day {
    font-weight: 700;
}
.events__card-body {
    padding: 1rem;
    flex: 1 0 auto;
    background-color: var(--color-1);
    color: var(--color-over-1);
    border-radius: 0 0 0.5rem 0.5rem;
}
.events__card-title {
    margin: 0 0 0.5rem;
    font-size: 1.0625rem;
}
/* The body prefix wins the colour back from the system stylesheet. The hover
   and focus states are a separate rule so their underline outranks the reset
   above — folded into it, text-decoration: none applies at every state. */
body .events .events__card-title a {
    color: var(--color-over-1);
    text-decoration: none;
}
body .events .events__card-title a:hover,
body .events .events__card-title a:focus-visible {
    text-decoration: underline;
}
.events__card-time,
.events__card-location {
    margin: 0.25rem 0 0;
    font-size: 0.875rem;
    color: var(--color-over-1);
}

/* Arrows and the CTA share one row below the carousel; the buttons drop their
   absolute edge placement so the row positions them. */
.events__controls {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    margin-top: 2rem;
}
.events__carousel .swiper-button-prev,
.events__carousel .swiper-button-next {
    position: static;
    inset: auto;
    margin: 0;
}
.events__cta { margin-top: 0; }

/* ==================== Spotlight 2 — Staff Spotlights ==================== */

.staff-spotlights {
    background-color: var(--color-1);
    color: var(--color-over-1);
    padding: 2.5rem 1rem;
}
.staff-spotlights__inner {
    display: grid;
    grid-template-columns: 1fr;
    gap: 2.5rem;
    max-width: var(--size-lg);
    margin-inline: auto;
}
@media (min-width: 42rem) {
    .staff-spotlights__inner {
        grid-template-columns: repeat(3, 1fr);
    }
}
.staff-spotlights__card {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}
/* Shape comes from the shared torn-paper mask treatment above (same as
   .news__card-photo) — this only sizes/places it within the card. */
.staff-spotlights__photo {
    width: 100%;
    max-width: 320px;
    margin-bottom: 1.5rem;
}
/* Inherits the section's --color-over-1. */
.staff-spotlights__title {
    color: inherit;
    margin: 0 0 1rem;
}
.staff-spotlights__body {
    --summary-lines-limit: 16;
    align-self: stretch;
    margin: 0 0 1.5rem;
    line-height: 1.6;
    text-align: left;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: var(--summary-lines-limit);
    overflow: hidden;
}
.staff-spotlights .staff-spotlights__body a { color: inherit; }

/* ==================== Footer ==================== */

/* Three layers, bottom to top: a flat --color-1 fill, the photo, and a
   --color-1 tint over it.

   The tint carries the text contrast. At 75% the photo's bright window
   areas pushed the address, phone and "Contact Us" runs down to 4.28–4.50:1
   against white, under the 4.5:1 AA floor for 16px/400 text; because the
   photo is sized with cover, the failing crop moves with the viewport
   rather than staying put. 85% holds a 4.83:1 floor against pure white,
   so every crop clears AA at every width.

   The flat fill underneath never composites into that figure — the photo
   is opaque and covers the element. It's there for the window before a
   2MB JPEG arrives, and for when it doesn't. */
.site-footer {
    background-color: var(--color-1);
    background-image:
        linear-gradient(color-mix(in srgb, var(--color-1), transparent 15%), color-mix(in srgb, var(--color-1), transparent 15%)),
        url("/pics/footer_bg_image.jpg");
    background-size: cover;
    background-position: center;
    /* Parallax: the image stays pinned to the viewport while the footer
       content scrolls over it. iOS Safari doesn't support fixed background
       attachment and just falls back to normal scroll — harmless, not a
       broken state. */
    background-attachment: fixed;
    color: var(--color-over-1);
    padding-top: 2.5rem;
}
/* Single left-aligned column below 48rem; from there up, identity/address/
   links/edlios stack in a 1fr column with the social icon spanning an
   auto-width column beside them. auto rather than a fixed track because the
   social nav is omitted entirely when its CMS category is empty — an auto
   column collapses to zero instead of leaving a dead gutter. */
.site-footer__inner {
    display: grid;
    grid-template-areas:
        "identity"
        "address"
        "linksrow"
        "social";
    gap: 1.5rem;
    padding: 0 1rem 2rem;
    text-align: left;
    max-width: var(--size-xl);
    margin-inline: auto;
    box-sizing: border-box;
}
@media (min-width: 48rem) {
    .site-footer__inner {
        grid-template-columns: 1fr auto;
        grid-template-areas:
            "identity social"
            "address  social"
            "linksrow linksrow";
    }
}
.site-footer__identity {
    grid-area: identity;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
}
.site-footer__logo { height: 106px; width: auto; }
.site-footer__name {
    font-family: 'Oswald', sans-serif;
    font-size: 1.75rem;
    font-weight: 600;
}
.site-footer__contact {
    grid-area: address;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    font-style: normal;
}
.site-footer .site-footer__contact a { color: inherit; }
/* Links left, Edlio logos right, on one line — wraps to stacked on
   narrow widths since it's real content, not decoration. */
.site-footer__links-row {
    grid-area: linksrow;
    display: flex;
    flex-flow: row wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem 2rem;
}
.site-footer__links ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-flow: row wrap;
    gap: 0.5rem 1.5rem;
}
.site-footer .site-footer__links a { color: inherit; }
/* Sits where .site-footer__links used to (the auto-width column beside
   identity/address/linksrow) — see the grid-template-areas above. */
.site-footer__social {
    grid-area: social;
    display: flex;
    align-items: center;
    padding-right: 2rem;
}
.site-footer__social ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    gap: 1rem;
}
.site-footer .site-footer__social a { color: inherit; }
.site-footer__social-icon svg,
.site-footer__social-icon img {
    width: 32px;
    height: 32px;
}
.site-footer__attribution {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 1.5rem;
}
.site-footer .site-footer__attribution a {
    color: inherit;
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    text-decoration: none;
}
.site-footer__attribution svg { fill: currentColor; }
.site-footer__attribution a:first-child svg { width: 140px; height: 20px; }
.site-footer__attribution a:last-child svg { height: 1.5rem; width: auto; }

/* ==================== Reduced motion ==================== */

/* Every transition and animation in this file is ornamental — a hover
   nudge, the chevron spin, the Quick Links page-turn — so reduced-motion
   viewers lose nothing by having them removed.

   Each selector repeats its original verbatim and the block sits last in
   the file, so source order carries it at equal specificity and no
   !important is needed.

   Not covered here: the hero's 5s autoplay, which is Swiper's and is
   answered by its pause button (WCAG 2.2.2), and Swiper's own 450ms
   slide timing, which is set in JS. */
@media (prefers-reduced-motion: reduce) {
    .dropdown-toggle::after,
    .cta__label,
    .quicklinks__page,
    .quicklinks__tile-photo,
    .quicklinks__tile-title {
        transition-duration: 0s;
    }

    body .cta.cta:hover,
    body .cta.cta:focus-visible {
        transition-duration: 0s;
    }

    /* Hold the pages visible rather than letting them snap to 0 and back:
       zeroing the fade's duration alone would turn it into a flash, which
       is the opposite of the request. */
    .quicklinks__carousel .swiper.is-flipping-next .quicklinks__page,
    .quicklinks__carousel .swiper.is-flipping-prev .quicklinks__page {
        opacity: 1;
    }

    .quicklinks__book:has(.swiper.is-flipping-next) .book-paper--right,
    .quicklinks__book:has(.swiper.is-flipping-next) .book-edge-a--right,
    .quicklinks__book:has(.swiper.is-flipping-next) .book-edge-b--right,
    .quicklinks__book:has(.swiper.is-flipping-prev) .book-paper--left,
    .quicklinks__book:has(.swiper.is-flipping-prev) .book-edge-a--left,
    .quicklinks__book:has(.swiper.is-flipping-prev) .book-edge-b--left {
        animation: none;
    }
}
