/* ═══════════════════════════════════════════════════════════════════════
   MOTION — refined, institutional
   ───────────────────────────────────────────────────────────────────────
   Load AFTER components/pages, BEFORE accessibility.css.

   Principles for a school site:
     · Motion clarifies, it never performs. Short durations (180–450ms),
       small distances (≤16px), no bounce or overshoot.
     · Nothing animates that a family is trying to read. Policy prose,
       document rows, and tables stay still.
     · Every effect degrades to "already visible". If JS never runs, or
       the visitor asks for reduced motion, the page is complete and
       static — content is never hidden behind an animation.

   THE REDUCED-MOTION RULE IS AT THE BOTTOM AND OVERRIDES EVERYTHING.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  --motion-fast:   .18s;
  --motion:        .28s;
  --motion-slow:   .45s;
  /* Gentle deceleration — no elastic or back easing anywhere */
  --motion-ease:   cubic-bezier(.22, .61, .36, 1);
  --motion-rise:   14px;   /* how far a revealed element travels */
}

/* ═══════════════════════════════════════════════════════════════════════
   1. SCROLL REVEAL
   ───────────────────────────────────────────────────────────────────────
   js/reveal.js adds .motion-ready to <html> and .is-in to elements as
   they enter the viewport.

   Elements are ONLY hidden once .motion-ready confirms JS is running.
   Without JS the [data-reveal] attribute has no visual effect at all —
   this is why content can never be trapped invisible.
   ═══════════════════════════════════════════════════════════════════════ */
.motion-ready [data-reveal] {
  opacity: 0;
  transform: translateY(var(--motion-rise));
  transition: opacity var(--motion-slow) var(--motion-ease),
              transform var(--motion-slow) var(--motion-ease);
  will-change: opacity, transform;
}
.motion-ready [data-reveal].is-in {
  opacity: 1;
  transform: none;
}
/* Once revealed, drop the hint so we are not holding layers forever */
.motion-ready [data-reveal].is-done { will-change: auto; }

/* Stagger children — cards in a grid arrive in sequence, not as a block.
   Capped at 6 so a 45-row policy list never waits 4 seconds. */
.motion-ready [data-reveal-stagger] > * {
  opacity: 0;
  transform: translateY(var(--motion-rise));
  transition: opacity var(--motion-slow) var(--motion-ease),
              transform var(--motion-slow) var(--motion-ease);
}
.motion-ready [data-reveal-stagger].is-in > *        { opacity: 1; transform: none; }
.motion-ready [data-reveal-stagger].is-in > *:nth-child(1) { transition-delay: 0ms; }
.motion-ready [data-reveal-stagger].is-in > *:nth-child(2) { transition-delay: 70ms; }
.motion-ready [data-reveal-stagger].is-in > *:nth-child(3) { transition-delay: 140ms; }
.motion-ready [data-reveal-stagger].is-in > *:nth-child(4) { transition-delay: 210ms; }
.motion-ready [data-reveal-stagger].is-in > *:nth-child(5) { transition-delay: 280ms; }
.motion-ready [data-reveal-stagger].is-in > *:nth-child(n+6) { transition-delay: 350ms; }

/* ═══════════════════════════════════════════════════════════════════════
   2. MEDIA & CARDS
   ═══════════════════════════════════════════════════════════════════════ */

/* Image zoom on hover — the frame stays put, the picture drifts in. */
.card-media,
.sport-card .card-media,
.division-card-media,
.campus-card > img { overflow: hidden; }

.card-media img,
.division-card-media img,
.sport-card img,
.campus-card > img {
  transition: transform var(--motion-slow) var(--motion-ease);
}
.card:hover .card-media img,
.sport-card:hover img,
.division-card:hover .division-card-media img,
.campus-card:hover > img { transform: scale(1.045); }

/* Cards lift on hover — 2px, enough to register, not enough to jump */
.card, .sport-card, .staff-card, .tile, .stat-card, .division-card {
  transition: transform var(--motion) var(--motion-ease),
              box-shadow var(--motion) var(--motion-ease),
              border-color var(--motion) var(--motion-ease);
}

/* Arrow nudge on card links */
.card-link, .division-cta {
  transition: gap var(--motion-fast) var(--motion-ease),
              color var(--motion-fast) var(--motion-ease);
}

/* ═══════════════════════════════════════════════════════════════════════
   3. MENUS
   ═══════════════════════════════════════════════════════════════════════ */

/* Desktop dropdowns — fade + a short drop. [hidden] still hides them
   for assistive tech; the animation only decorates the visible state. */
.nav-drop {
  animation: dropIn var(--motion) var(--motion-ease) both;
  transform-origin: top center;
}
@keyframes dropIn {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

.drop-link { transition: background var(--motion-fast) var(--motion-ease),
                         border-color var(--motion-fast) var(--motion-ease),
                         padding-left var(--motion-fast) var(--motion-ease); }
.drop-link:hover, .drop-link:focus-visible { padding-left: calc(var(--sp-4) + 4px); }

/* Mobile panel — slides in from the right */
#mobile-nav { animation: panelIn var(--motion) var(--motion-ease) both; }
@keyframes panelIn {
  from { opacity: 0; transform: translateX(24px); }
  to   { opacity: 1; transform: none; }
}
/* Mobile sub-menus */
.mnav-sub { animation: subIn var(--motion-fast) var(--motion-ease) both; }
@keyframes subIn {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

/* Utility + nav link colour changes */
.utility-link, .nav-link, .footer-links a, .side-nav a, .doc-dl, .pill {
  transition: color var(--motion-fast) var(--motion-ease),
              background var(--motion-fast) var(--motion-ease),
              border-color var(--motion-fast) var(--motion-ease);
}

/* ═══════════════════════════════════════════════════════════════════════
   4. ACCORDIONS  (FAQ + document sections)
   ───────────────────────────────────────────────────────────────────────
   Panels use [hidden], so they cannot be height-animated without JS
   measuring them. Fading the content in on open gives the same softness
   with none of the layout-thrash or the a11y cost of faking [hidden].
   ═══════════════════════════════════════════════════════════════════════ */
.faq-panel:not([hidden]),
.doc-section-panel:not([hidden]) {
  animation: panelOpen var(--motion) var(--motion-ease) both;
}
@keyframes panelOpen {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

.faq-trigger, .doc-section-btn { transition: background var(--motion-fast) var(--motion-ease); }
.faq-icon, .doc-chevron, .nav-caret, .caret {
  transition: transform var(--motion) var(--motion-ease),
              background var(--motion) var(--motion-ease);
}

/* ═══════════════════════════════════════════════════════════════════════
   5. HERO — Ken Burns drift
   ───────────────────────────────────────────────────────────────────────
   A very slow scale + pan. 28s per cycle so it reads as "alive" rather
   than as movement. Alternates so it never snaps back to the start.
   ═══════════════════════════════════════════════════════════════════════ */
@keyframes kenBurns {
  from { transform: scale(1.02) translate3d(0, 0, 0); }
  to   { transform: scale(1.10) translate3d(-1.2%, -1%, 0); }
}

.page-hero-img,
.ph-slide img {
  animation: kenBurns 28s var(--motion-ease) infinite alternate;
  will-change: transform;
}

/* Homepage hero video gets the same treatment, gentler still */
.hero-video, .hero-poster-fallback {
  animation: kenBurns 40s var(--motion-ease) infinite alternate;
}

/* Panthers slideshow: only the visible slide drifts, so the others are
   not burning compositor time. */
.ph-slide img { animation-play-state: paused; }
.ph-slide.is-active img { animation-play-state: running; }

/* ═══════════════════════════════════════════════════════════════════════
   6. BUTTONS & SMALL INTERACTIONS
   ═══════════════════════════════════════════════════════════════════════ */
.btn { transition: background var(--motion-fast) var(--motion-ease),
                   color var(--motion-fast) var(--motion-ease),
                   border-color var(--motion-fast) var(--motion-ease),
                   transform var(--motion-fast) var(--motion-ease),
                   box-shadow var(--motion-fast) var(--motion-ease); }

.social-btn { transition: background var(--motion-fast) var(--motion-ease),
                          color var(--motion-fast) var(--motion-ease),
                          border-color var(--motion-fast) var(--motion-ease),
                          transform var(--motion-fast) var(--motion-ease); }
.social-btn:hover { transform: translateY(-2px); }

/* Skip link slide — already defined in accessibility.css, kept in sync */
.skip-link { transition: transform var(--motion) var(--motion-ease); }

/* ═══════════════════════════════════════════════════════════════════════
   7. REDUCED MOTION — the override that wins
   ───────────────────────────────────────────────────────────────────────
   Everything above collapses. Revealed content is shown immediately and
   unconditionally, so nothing is ever left invisible.
   accessibility.css carries a second, broader guard as a backstop.
   ═══════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {

  .motion-ready [data-reveal],
  .motion-ready [data-reveal-stagger] > * {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }

  .page-hero-img,
  .ph-slide img,
  .hero-video,
  .hero-poster-fallback {
    animation: none !important;
    transform: none !important;
  }

  .nav-drop, #mobile-nav, .mnav-sub,
  .faq-panel, .doc-section-panel {
    animation: none !important;
  }

  .card:hover .card-media img,
  .sport-card:hover img,
  .division-card:hover .division-card-media img,
  .campus-card:hover > img,
  .social-btn:hover { transform: none !important; }
}
