/* ==========================================================================
   transitions.css – cross-page transitions + scroll-reveal animations
   ========================================================================== */

/* Reserve scrollbar gutter so pages don't horizontally jump between long
   and short content. `scrollbar-gutter: stable` is the modern replacement
   for the old `overflow-y: scroll` hack — it reserves space for the
   scrollbar without forcing it always-visible. */
html {
  scrollbar-gutter: stable;
}

/* --------------------------------------------------------------------------
   Cross-page transitions
   Page-enter is driven entirely by a CSS @keyframes animation on initial
   render — no JS coordination required, so there's no flash-of-visible
   content. Page-exit is opt-in via the .page-exit class added by JS when
   an internal link is clicked.

   Animates: main + breadcrumb header + profile-header. The navbar is
   intentionally excluded so it acts as a stable anchor across navigations.
   -------------------------------------------------------------------------- */

@keyframes pageEnter {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes pageExit {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-8px); }
}

/* fill-mode: backwards — applies the `from` keyframe during animation-delay
   (so there's no flash-of-visible-content), then REVERTS to the element's
   natural state once the animation completes. Crucially, this leaves no
   residual `transform` on <main>: a lingering transform creates a containing
   block for position:fixed descendants, which would break Bootstrap modals
   (off-center, un-closeable, backdrop above content). */
main,
header > .header,
header > .profile-header {
  animation: pageEnter 0.45s cubic-bezier(0.22, 1, 0.36, 1) backwards;
}

/* slight stagger so header lands a touch before main */
header > .header,
header > .profile-header {
  animation-delay: 0s;
}

main {
  animation-delay: 0.05s;
}

/* exit animation triggered by JS adding .page-exit to <body> */
body.page-exit main,
body.page-exit header > .header,
body.page-exit header > .profile-header {
  animation: pageExit 0.35s cubic-bezier(0.55, 0, 0.7, 0.4) both;
}

/* --------------------------------------------------------------------------
   Reveal-on-scroll utility
   Add class="reveal" to any element to fade it up as it scrolls into view.
   The IntersectionObserver in transitions.js toggles `.visible`.
   -------------------------------------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity   0.65s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.65s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: opacity, transform;
}

.reveal.visible {
  opacity: 1;
  transform: translateY(0);
}

/* --------------------------------------------------------------------------
   Respect user motion preference
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  main,
  header > .header,
  header > .profile-header,
  .reveal,
  .card-subtle,
  .member-card,
  .course-animate-in,
  .course-animate-out {
    animation: none !important;
    transition: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}
