/**
 * Site UI additions — scroll-reveal animations and missing hover/focus
 * affordances. Everything here is layered on top of the template's style.css
 * and linked after it, so the original rules stay untouched.
 *
 * WHY THIS FILE EXISTS
 *
 * 1. Animations: the markup has always carried WOW.js classes (wow fadeInUp,
 *    wow zoomIn, ...) but WOW.js was never loaded, so all ~55 of those elements
 *    sat completely still. The reveal is reimplemented here on
 *    IntersectionObserver rather than pulling in WOW.js — it is unmaintained,
 *    and its own visibility handling can leave content permanently invisible if
 *    it fails to initialise.
 *
 * 2. Hover: the template's style.css has plenty of :hover rules, but the ones
 *    that matter most on a services/fleet/blog site were missing entirely —
 *    card thumbnails, fleet cards, post thumbnails, the about image and the
 *    pagination had no hover feedback at all.
 *
 * The reveal's hidden state is gated behind .cs-reveal-ready on <html>, set by a
 * synchronous inline script in <head> (see BaseLayout.astro) so it applies
 * before first paint. If JavaScript is unavailable that class is never added
 * and every element renders normally — content is never hidden behind a script
 * that might not run.
 */

/* =========================================================================
 * 1. Scroll reveal
 * ====================================================================== */

/* -------------------------------------------------------------------------
 * Keyframes (names kept identical to WOW.js so the existing markup works)
 * ---------------------------------------------------------------------- */
@keyframes csFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes csFadeInUp {
  from { opacity: 0; transform: translate3d(0, 60px, 0); }
  to { opacity: 1; transform: none; }
}

@keyframes csFadeInDown {
  from { opacity: 0; transform: translate3d(0, -60px, 0); }
  to { opacity: 1; transform: none; }
}

@keyframes csFadeInLeft {
  from { opacity: 0; transform: translate3d(-60px, 0, 0); }
  to { opacity: 1; transform: none; }
}

@keyframes csFadeInRight {
  from { opacity: 0; transform: translate3d(60px, 0, 0); }
  to { opacity: 1; transform: none; }
}

@keyframes csZoomIn {
  from { opacity: 0; transform: scale3d(0.3, 0.3, 0.3); }
  to { opacity: 1; transform: none; }
}

@keyframes csFlipInX {
  from { opacity: 0; transform: perspective(600px) rotate3d(1, 0, 0, 90deg); }
  to { opacity: 1; transform: none; }
}

/* WOW's `pulse` is a repeating attention nudge rather than a reveal, so it
   runs continuously once revealed. */
@keyframes csPulse {
  0% { transform: scale(1); }
  50% { transform: scale(1.12); }
  100% { transform: scale(1); }
}

/* -------------------------------------------------------------------------
 * Hidden state, only applied once JS has confirmed it can reveal again
 * ---------------------------------------------------------------------- */
.cs-reveal-ready .wow:not(.cs-revealed) {
  opacity: 0;
  will-change: opacity, transform;
}

.cs-reveal-ready .wow.fadeInUp:not(.cs-revealed) { transform: translate3d(0, 60px, 0); }
.cs-reveal-ready .wow.fadeInDown:not(.cs-revealed) { transform: translate3d(0, -60px, 0); }
.cs-reveal-ready .wow.fadeInLeft:not(.cs-revealed) { transform: translate3d(-60px, 0, 0); }
.cs-reveal-ready .wow.fadeInRight:not(.cs-revealed) { transform: translate3d(60px, 0, 0); }
.cs-reveal-ready .wow.zoomIn:not(.cs-revealed) { transform: scale3d(0.3, 0.3, 0.3); }

/* -------------------------------------------------------------------------
 * Revealed state
 * ---------------------------------------------------------------------- */
.wow.cs-revealed {
  animation-duration: 0.9s;
  animation-fill-mode: both;
  animation-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1);
  /* Stagger set per element by initScrollReveal() in main.js. */
  animation-delay: var(--cs-reveal-delay, 0ms);
}

.wow.cs-revealed.fadeIn { animation-name: csFadeIn; }
.wow.cs-revealed.fadeInUp { animation-name: csFadeInUp; }
.wow.cs-revealed.fadeInDown { animation-name: csFadeInDown; }
.wow.cs-revealed.fadeInLeft { animation-name: csFadeInLeft; }
.wow.cs-revealed.fadeInRight { animation-name: csFadeInRight; }
.wow.cs-revealed.zoomIn { animation-name: csZoomIn; }
.wow.cs-revealed.flipInX { animation-name: csFlipInX; }

.wow.cs-revealed.pulse {
  animation-name: csPulse;
  animation-duration: 1.6s;
  animation-iteration-count: infinite;
  animation-fill-mode: none;
  opacity: 1;
}

/* =========================================================================
 * 2. Hover and focus affordances
 *
 * Kept deliberately small: lift, shadow and a short image zoom. No layout
 * properties (margin/padding/width) are animated anywhere below, so nothing
 * reflows and no neighbouring content jumps on hover.
 * ====================================================================== */

/* -------------------------------------------------------------------------
 * Card image zoom
 *
 * The single most valuable missing affordance on the site: service cards,
 * blog cards and the about image all had no hover feedback whatsoever.
 * overflow:hidden clips the zoom; without it the image grows past the card.
 * ---------------------------------------------------------------------- */
.cs_card_thumbnail,
.cs_post_thumbnail,
.cs_about_thumbnail {
  overflow: hidden;
}

.cs_card_thumbnail img,
.cs_post_thumbnail img,
.cs_about_thumbnail img {
  transition: transform 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: transform;
}

.cs_card_thumbnail:hover img,
.cs_post_thumbnail:hover img,
.cs_about_thumbnail:hover img {
  transform: scale(1.07);
}

/* The whole card is the link on the service and fleet grids, so the zoom has
   to hang off the card, not just the image. */
a.cs_card:hover .cs_card_thumbnail img,
a.cs_card:hover .cs_post_thumbnail img {
  transform: scale(1.07);
}

/* -------------------------------------------------------------------------
 * Fleet cards (a.cs_card.cs_style_3) — no hover rule existed for this variant
 * ---------------------------------------------------------------------- */
a.cs_card.cs_style_3 {
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

a.cs_card.cs_style_3 .cs_card_content {
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

a.cs_card.cs_style_3:hover,
a.cs_card.cs_style_3:focus-visible {
  transform: translateY(-6px);
}

a.cs_card.cs_style_3:hover .cs_card_content,
a.cs_card.cs_style_3:focus-visible .cs_card_content {
  box-shadow: 0 18px 40px rgba(0, 43, 137, 0.14);
}

/* The generic car glyph in each fleet card picks up a touch of the brand
   colour so the card feels alive without moving the text. */
a.cs_card.cs_style_3 .cs_card_icon img {
  transition: transform 0.35s ease, filter 0.35s ease;
}

a.cs_card.cs_style_3:hover .cs_card_icon img,
a.cs_card.cs_style_3:focus-visible .cs_card_icon img {
  transform: translateY(-4px);
  filter: hue-rotate(-12deg) saturate(1.15);
}

/* -------------------------------------------------------------------------
 * "READ MORE"-style text buttons: nudge the arrow, it signals direction
 * ---------------------------------------------------------------------- */
.cs_text_btn {
  transition: color 0.25s ease;
}

.cs_text_btn i,
.cs_text_btn svg {
  transition: transform 0.25s ease;
}

.cs_text_btn:hover i,
.cs_text_btn:hover svg,
.cs_text_btn:focus-visible i,
.cs_text_btn:focus-visible svg {
  transform: translateX(5px);
}

/* -------------------------------------------------------------------------
 * Testimonial / logo strips and generic card lifts
 * ---------------------------------------------------------------------- */
.cs_card.cs_style_1 {
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.cs_card.cs_style_1:hover,
.cs_card.cs_style_1:focus-visible {
  transform: translateY(-5px);
  box-shadow: 0 16px 38px rgba(0, 43, 137, 0.12);
}

/* -------------------------------------------------------------------------
 * Keyboard focus
 *
 * The template styles :hover but almost never :focus-visible, so a keyboard
 * user got no indication of where they were on links, cards and form fields.
 * Only applied where the element does not already draw its own focus ring.
 * ---------------------------------------------------------------------- */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
.cs_btn:focus-visible,
.cs_card:focus-visible,
.cs_post:focus-visible,

.cs_form_field:focus-visible,
.cs_video_open:focus-visible {
  outline: 2px solid #006ff5;
  outline-offset: 2px;
}

/* The form fields and buttons already show a border change on focus, so they
   get the ring only when focused by keyboard, never on mouse click. */
.cs_form_field:focus-visible,
.cs_btn:focus-visible {
  outline-offset: 3px;
}

/* -------------------------------------------------------------------------
 * Contrast fix: the footer copyright link
 *
 * The template renders the brand name in the footer as #006ff5 on the #002b89
 * navy footer -- 2.69:1, which fails WCAG AA (4.5:1 needed at 16px). White on
 * that navy is ~12:1, and #9ec5ff -- used for hover/focus -- is ~7.8:1, so
 * every state clears the bar. The accent blue is kept for the hover so the
 * brand interaction is unchanged, just readable.
 *
 * The selectors below deliberately repeat the template's own
 * ".cs_footer.cs_style_1 .cs_footer_copyright a" (specificity 0,3,1) rather
 * than using a shorter ".cs_footer_copyright a" (0,1,1). Loading later is not
 * enough to win a specificity contest, and the template's rule sets the colour
 * directly on the anchor rather than letting it inherit, so the override has to
 * be at least as specific.
 * ---------------------------------------------------------------------- */
.cs_footer.cs_style_1 .cs_footer_copyright a {
  color: #fff;
  transition: color 0.25s ease;
}

.cs_footer.cs_style_1 .cs_footer_copyright a:hover,
.cs_footer.cs_style_1 .cs_footer_copyright a:focus-visible {
  color: #9ec5ff;
}

/* =========================================================================
 * 3. Accessibility
 *
 * prefers-reduced-motion is honoured in CSS as well as in main.js, so content
 * is visible even if the observer never runs. Large, distant and infinite
 * motion are what trigger vestibular symptoms, so the reveal collapses to a
 * short plain fade instead of being removed.
 *
 * Hover zooms/lifts are also disabled under reduced motion (2026-09-30 pass).
 * ====================================================================== */
@media (prefers-reduced-motion: reduce) {
  .cs-reveal-ready .wow:not(.cs-revealed),
  .cs-reveal-ready .wow.fadeInUp:not(.cs-revealed),
  .cs-reveal-ready .wow.fadeInDown:not(.cs-revealed),
  .cs-reveal-ready .wow.fadeInLeft:not(.cs-revealed),
  .cs-reveal-ready .wow.fadeInRight:not(.cs-revealed),
  .cs-reveal-ready .wow.zoomIn:not(.cs-revealed) {
    opacity: 1;
    transform: none;
  }

  .cs_card_thumbnail img,
  .cs_post_thumbnail img,
  .cs_about_thumbnail img,
  a.cs_card.cs_style_3 .cs_card_icon img { transition: none; }

  .wow.cs-revealed {
    animation-name: csFadeIn !important;
    animation-duration: 0.2s !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
  }

  .cs_card_thumbnail:hover img,
  .cs_post_thumbnail:hover img,
  .cs_about_thumbnail:hover img,
  a.cs_card:hover .cs_card_thumbnail img,
  a.cs_card:hover .cs_post_thumbnail img,
  a.cs_card.cs_style_3:hover,
  a.cs_card.cs_style_3:focus-visible,
  a.cs_card.cs_style_1:hover,
  a.cs_card.cs_style_1:focus-visible,
  .cs_text_btn:hover i,
  .cs_text_btn:hover svg,
  a.cs_card.cs_style_3:hover .cs_card_icon img,
  a.cs_card.cs_style_3:focus-visible .cs_card_icon img {
    transform: none;
  }
}

/* =========================================================================
 * 4. Cursor fixes
 *
 * Slick stamps `draggable` onto the slider's .slick-list whenever dragging is
 * enabled, and the template ships this rule:
 *
 *     .draggable { cursor: ew-resize !important; }
 *
 * `ew-resize` is the double-headed horizontal arrow — the "I can drag this
 * sideways" cursor. Over a full-bleed autoplay hero it covered the whole
 * slide, so simply moving the mouse across the hero swapped the pointer for
 * that arrow. It also over-promised: the hero is not a drag-to-pan surface,
 * and the arrow suggested a resize/drag interaction that is not the primary
 * way to move through the slides.
 *
 * Only the cursor is overridden, not Slick's `draggable` option, so touch
 * swipe on the hero keeps working. Matching `.draggable` on specificity and
 * using !important is the minimum needed to beat the template's own !important.
 * `default` is the normal arrow cursor; interactive children (the slide's
 * "Read more" link, the pagination dots) still show pointer on their own.
 * ====================================================================== */
.draggable {
  cursor: default !important;
}
