/* ==========================================================================
   SLCOMM — shared UI polish layer
   Loaded on every page after the page's own inline <style> block, so the
   rules here intentionally win where they overlap.

   Two jobs:
     1. Keep fixed-navbar spacing correct on every page and viewport.
     2. Give the whole site one consistent, smooth motion language.
   ========================================================================== */

:root {
  /* Easing curves. --ease-out is the workhorse for hovers and reveals;
     --ease-spring adds a slight overshoot for lifts. */
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

  --dur-fast: 220ms;
  --dur-base: 380ms;
  --dur-slow: 620ms;

  /* --nav-h is the navbar's real measured height, set by navbar.js.
     --nav-offset is how far the page content must start below it, which is
     the same value except on the homepage, where the full-height hero is
     meant to sit behind the navbar. The fallbacks match the old hard-coded
     values so nothing shifts before JS runs. */
  --nav-h: 80px;
  --nav-offset: 80px;
}

/* The homepage hero is full-viewport and deliberately runs under the
   transparent navbar, so it takes no top offset. */
body.has-hero {
  --nav-offset: 0px;
}

/* --------------------------------------------------------------------------
   1. Fixed-navbar alignment
   The pages used to hard-code `body { padding-top: 80px }`. When the brand
   text wrapped to a second line the navbar grew past 80px and the page header
   slid underneath it. Padding now tracks the measured height instead.
   -------------------------------------------------------------------------- */
body {
  padding-top: var(--nav-offset) !important;
}

/* The long college name is what pushed the navbar over 80px. Hold it on one
   line and step the size down by viewport instead of letting it wrap. */
.navbar-brand {
  font-size: 1.3rem !important;
  line-height: 1.25;
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-out);
}

@media (max-width: 1199px) {
  .navbar-brand { font-size: 1.15rem !important; }
}

@media (max-width: 991px) {
  /* Below the lg breakpoint the menu collapses and the brand shares the bar
     with only the toggler, so wrapping is safe and nowrap would overflow. */
  .navbar-brand {
    font-size: 1rem !important;
    white-space: normal;
    max-width: calc(100% - 70px);
  }
}

@media (max-width: 575px) {
  .navbar-brand { font-size: 0.9rem !important; }
}

/* Anchor targets clear the fixed navbar instead of hiding behind it. */
:target,
[id] {
  scroll-margin-top: calc(var(--nav-h) + 16px);
}

html {
  scroll-behavior: smooth;
}

/* --------------------------------------------------------------------------
   2. Navbar motion
   -------------------------------------------------------------------------- */
.navbar {
  transition:
    background-color var(--dur-base) var(--ease-out),
    box-shadow var(--dur-base) var(--ease-out),
    padding var(--dur-base) var(--ease-out) !important;
  will-change: background-color, padding;
}

.navbar.scrolled {
  /* Tighten the bar slightly on scroll — reads as responsive without
     shifting the content, since padding is measured back into --nav-h. */
  padding-top: 7px !important;
  padding-bottom: 7px !important;
  backdrop-filter: saturate(140%) blur(6px);
  -webkit-backdrop-filter: saturate(140%) blur(6px);
}

/* Gold underline that wipes in under the active/hovered nav item. */
.navbar .nav-link {
  transition: color var(--dur-fast) var(--ease-out) !important;
}

/* Bootstrap builds the dropdown caret out of ::after, so the underline is
   scoped to plain links only rather than fighting it. */
.navbar .nav-link:not(.dropdown-toggle)::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 2px;
  height: 2px;
  background: var(--gold, #c9a347);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-base) var(--ease-out);
}

.navbar .nav-link:not(.dropdown-toggle):hover::after,
.navbar .nav-link:not(.dropdown-toggle).active::after {
  transform: scaleX(1);
}

@media (max-width: 991px) {
  /* In the stacked mobile menu a full-width bar under every item is noise. */
  .navbar .nav-link:not(.dropdown-toggle)::after {
    display: none;
  }
}

@media (min-width: 992px) {
  /* Fade + rise the dropdown panels rather than snapping them open.
     Top-level menus keep Bootstrap's click-to-open behaviour — this only
     animates the .show state Bootstrap already toggles. Submenus keep the
     CSS hover behaviour the site has always used. */
  .navbar .dropdown-menu {
    display: block;
    opacity: 0;
    visibility: hidden;
    transform: translateY(10px);
    pointer-events: none;
    transition:
      opacity var(--dur-fast) var(--ease-out),
      transform var(--dur-fast) var(--ease-out),
      visibility var(--dur-fast) linear;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.22);
  }

  .navbar .dropdown-menu.show {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    pointer-events: auto;
  }

  /* Submenus fly out sideways from their parent item. */
  .navbar .dropdown-submenu > .dropdown-menu {
    transform: translateX(-8px);
  }

  .navbar .dropdown-submenu:hover > .dropdown-menu {
    opacity: 1;
    visibility: visible;
    transform: translateX(0);
    pointer-events: auto;
  }
}

.dropdown-item {
  transition:
    background-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    padding-left var(--dur-fast) var(--ease-out) !important;
}

.dropdown-item:hover {
  padding-left: 26px !important;
}

/* --------------------------------------------------------------------------
   3. Card motion
   One lift-and-shadow treatment shared by every card variant on the site.
   -------------------------------------------------------------------------- */
.facility-card,
.news-card,
.commander-card,
.personnel-card,
.document-section,
.gallery-item {
  transition:
    transform var(--dur-base) var(--ease-spring),
    box-shadow var(--dur-base) var(--ease-out) !important;
  will-change: transform;
}

.facility-card:hover,
.news-card:hover,
.commander-card:hover,
.personnel-card:hover,
.gallery-item:hover {
  transform: translateY(-8px) !important;
  box-shadow: 0 18px 38px rgba(10, 42, 90, 0.16) !important;
}

/* Image zoom inside cards — slower and smoother than the old 0.5s linear. */
.facility-image img,
.news-card img,
.gallery-item img,
.commander-image img,
.personnel-image img {
  transition: transform var(--dur-slow) var(--ease-out) !important;
  backface-visibility: hidden;
}

.facility-card:hover .facility-image img,
.news-card:hover img,
.gallery-item:hover img {
  transform: scale(1.07) !important;
}

.facility-overlay {
  transition: opacity var(--dur-base) var(--ease-out) !important;
}

.facility-link i {
  transform: scale(0.7);
  opacity: 0;
  transition:
    transform var(--dur-base) var(--ease-spring),
    opacity var(--dur-base) var(--ease-out);
}

.facility-card:hover .facility-link i {
  transform: scale(1);
  opacity: 1;
}

/* --------------------------------------------------------------------------
   4. Buttons and links
   -------------------------------------------------------------------------- */
.btn {
  transition:
    background-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-spring),
    box-shadow var(--dur-fast) var(--ease-out) !important;
}

.btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 18px rgba(10, 42, 90, 0.18);
}

.btn:active {
  transform: translateY(0);
  transition-duration: 90ms !important;
}

/* --------------------------------------------------------------------------
   5. Back-to-top
   -------------------------------------------------------------------------- */
.back-to-top {
  opacity: 0;
  visibility: hidden;
  transform: translateY(16px) scale(0.9);
  transition:
    opacity var(--dur-base) var(--ease-out),
    transform var(--dur-base) var(--ease-spring),
    visibility var(--dur-base) linear,
    background-color var(--dur-fast) var(--ease-out) !important;
  z-index: 900;
}

.back-to-top.active,
.back-to-top.show {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.back-to-top:hover {
  transform: translateY(-4px) scale(1.06);
}

/* --------------------------------------------------------------------------
   6. Scroll reveal
   navbar.js adds .reveal to content blocks and flips .is-visible when they
   enter the viewport. Without JS nothing gets .reveal, so content stays
   visible — the effect is purely additive.
   -------------------------------------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(26px);
  transition:
    opacity var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
  will-change: opacity, transform;
}

.reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* Stagger items within a row so grids cascade instead of popping as one block. */
.reveal[data-reveal-delay="1"] { transition-delay: 70ms; }
.reveal[data-reveal-delay="2"] { transition-delay: 140ms; }
.reveal[data-reveal-delay="3"] { transition-delay: 210ms; }
.reveal[data-reveal-delay="4"] { transition-delay: 280ms; }
.reveal[data-reveal-delay="5"] { transition-delay: 350ms; }

/* --------------------------------------------------------------------------
   7. Page header entrance
   -------------------------------------------------------------------------- */
.page-header {
  overflow: hidden;
}

.page-header h1 {
  animation: slcomm-rise var(--dur-slow) var(--ease-out) both;
}

.page-header p,
.page-header .breadcrumb {
  animation: slcomm-rise var(--dur-slow) var(--ease-out) 120ms both;
}

@keyframes slcomm-rise {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   8. Page transitions
   Navigating between pages was a hard cut. The incoming page fades up from
   the stylesheet itself (so there is no flash of full-opacity content before
   the animation starts), and navbar.js fades the outgoing page before it
   hands off to the browser.

   Deliberately opacity-only: a transform on <body> would make it the
   containing block for position:fixed children, which would tear the fixed
   navbar loose from the viewport for the duration of the animation.
   -------------------------------------------------------------------------- */
@keyframes slcomm-page-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

body {
  animation: slcomm-page-in 300ms var(--ease-out) both;
}

/* Painted behind the fading page, so the hand-off reads as the site's own
   background rather than a white flash. */
html {
  background-color: #f8f9fa;
}

html.slcomm-leaving body {
  opacity: 0;
  transition: opacity 170ms var(--ease-out);
  animation: none;
}

/* A page captured mid-fade must never print blank. */
@media print {
  body,
  html.slcomm-leaving body {
    animation: none !important;
    opacity: 1 !important;
  }
}

/* --------------------------------------------------------------------------
   9. Entry intro — the crest spins as a 3D coin, then the curtain opens.

   The whole overlay is injected by navbar.js and shown once per browser
   session. Nothing here exists in the page markup, so if the script never
   runs there is no overlay to get stuck behind.
   -------------------------------------------------------------------------- */
.slcomm-intro {
  position: fixed;
  inset: 0;
  z-index: 20000;
  overflow: hidden;
  cursor: pointer;
}

/* Two halves that part to reveal the page. */
.slcomm-intro-panel {
  position: absolute;
  left: 0;
  right: 0;
  height: 50.5%; /* slight overlap so no hairline shows down the middle */
  background: linear-gradient(160deg, #0a2a5a 0%, #041736 100%);
  will-change: transform;
}

.slcomm-intro-panel.is-top {
  top: 0;
  animation: slcomm-curtain-up 700ms var(--ease-in-out) 1650ms both;
}

.slcomm-intro-panel.is-bottom {
  bottom: 0;
  animation: slcomm-curtain-down 700ms var(--ease-in-out) 1650ms both;
}

@keyframes slcomm-curtain-up {
  from { transform: translateY(0); }
  to   { transform: translateY(-100%); }
}

@keyframes slcomm-curtain-down {
  from { transform: translateY(0); }
  to   { transform: translateY(100%); }
}

.slcomm-intro-stage {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  perspective: 1100px;
  pointer-events: none;
}

.slcomm-coin {
  position: relative;
  width: 190px;
  height: 190px;
  transform-style: preserve-3d;
  animation: slcomm-coin 1750ms both;
  will-change: transform, opacity;
}

/* Front and back are the same crest, so the coin stays solid through the
   half-turns instead of flashing empty when it passes edge-on. */
.slcomm-coin-face {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  /* Cropped and optimised from the footer crest — transparent PNG, so the
     navy behind it shows through instead of a boxed-in background. */
  background-image: url('../images/slcomm_logo.png');
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  backface-visibility: hidden;
  /* No solid ring here: the crest carries its own gold-and-black rim, and a
     second ring on top of it reads as a mistake. Glow and drop only. */
  box-shadow:
    0 0 38px rgba(201, 163, 71, 0.5),
    0 24px 50px rgba(0, 0, 0, 0.45);
}

.slcomm-coin-face.is-back {
  transform: rotateY(180deg);
}

/* Specular sweep that reads as light catching the rim as it turns. */
.slcomm-coin-face::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: linear-gradient(115deg,
    rgba(255, 255, 255, 0) 30%,
    rgba(255, 255, 255, 0.55) 48%,
    rgba(255, 255, 255, 0) 66%);
  animation: slcomm-coin-sheen 1750ms var(--ease-in-out) both;
}

@keyframes slcomm-coin-sheen {
  0%, 22%   { opacity: 0; transform: translateX(-60%); }
  46%       { opacity: 1; }
  74%, 100% { opacity: 0; transform: translateX(60%); }
}

/* Soft contact shadow so the coin sits in space rather than floating flat. */
.slcomm-coin-shadow {
  position: absolute;
  left: 50%;
  top: calc(50% + 132px);
  width: 190px;
  height: 22px;
  margin-left: -95px;
  border-radius: 50%;
  background: radial-gradient(ellipse at center,
    rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 70%);
  animation: slcomm-coin-shadow 1750ms both;
}

@keyframes slcomm-coin-shadow {
  0%        { opacity: 0; transform: scale(0.3); }
  20%       { opacity: 0.85; transform: scale(1); }
  75%       { opacity: 0.85; transform: scale(1); }
  100%      { opacity: 0; transform: scale(1.6); }
}

/* One timeline: pop in, two full turns, settle, then zoom away.
   Per-keyframe easing keeps the spin even while the pop still overshoots. */
@keyframes slcomm-coin {
  0% {
    opacity: 0;
    transform: scale(0.2) rotateX(12deg) rotateY(0deg);
    animation-timing-function: cubic-bezier(0.34, 1.45, 0.64, 1);
  }
  18% {
    opacity: 1;
    transform: scale(1.1) rotateX(12deg) rotateY(0deg);
    animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  }
  26% {
    transform: scale(1) rotateX(12deg) rotateY(0deg);
    animation-timing-function: cubic-bezier(0.45, 0, 0.55, 1);
  }
  76% {
    opacity: 1;
    transform: scale(1) rotateX(12deg) rotateY(720deg);
    animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  }
  86% {
    opacity: 1;
    transform: scale(1.06) rotateX(0deg) rotateY(720deg);
  }
  100% {
    opacity: 0;
    transform: scale(1.85) rotateX(0deg) rotateY(720deg);
  }
}

/* Hold the page still underneath while the intro plays. */
html.slcomm-intro-active,
html.slcomm-intro-active body {
  overflow: hidden;
}

/* The page's own entrance is redundant behind the curtain. */
html.slcomm-intro-active body {
  animation: none;
  opacity: 1;
}

@media (max-width: 575px) {
  .slcomm-coin { width: 132px; height: 132px; }
  .slcomm-coin-shadow {
    width: 132px;
    margin-left: -66px;
    top: calc(50% + 96px);
  }
}

/* --------------------------------------------------------------------------
   10. Accessibility — honour reduced-motion preferences
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .reveal {
    opacity: 1 !important;
    transform: none !important;
  }

  /* navbar.js skips the fade-out entirely under reduced motion; this makes
     sure nothing can leave the page stuck at zero opacity regardless. */
  body,
  html.slcomm-leaving body {
    opacity: 1 !important;
  }
}
