{# Carousel Module - Multi-purpose card carousel #}

{# Shorthand variables for cleaner code #}
{% set c = module.content %}
{% set b = module.behavior %}
{% set s = module.style %}
{% set a = module.advanced %}

{# Preconnect to CDN for faster image loading #}
{% if c.cards %}
  <link rel="preconnect" href="https://cdn2.hubspot.net" crossorigin>
  <link rel="dns-prefetch" href="https://cdn2.hubspot.net">
{% endif %}

{# Critical inline CSS for immediate render #}
<style>
  .carousel-module{position:relative;width:100%}
  .carousel-track-wrapper{overflow:hidden}
  .carousel-track{display:flex;transition:transform {{ s.transition_speed|default(600) }}ms cubic-bezier(0.25, 0.1, 0.25, 1)}
  .carousel-slide{flex-shrink:0;width:100%;padding:0.5rem 0}
  .carousel-module:not(.js-enhanced) .carousel-track-wrapper{overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch}
  .carousel-module:not(.js-enhanced) .carousel-slide{scroll-snap-align:start}
  .carousel-module:not(.js-enhanced) .carousel-nav,.carousel-module:not(.js-enhanced) .carousel-dots{display:none}
  .card-media-wrapper{overflow:hidden;background:var(--color-bg-secondary,#f5f5f5)}
  @media(max-width:992px){.carousel-slide{width:100%}}
</style>

{% set carousel_id = "carousel-" ~ name %}
{% set desktop_cards = s.cards_per_view_desktop|default(3) %}
{% set mobile_cards = s.cards_per_view_mobile|default(1) %}
{% set card_gap = s.card_gap|default(20) %}
{% set total_cards = c.cards|length %}
{% set show_navigation = total_cards > desktop_cards %}
{% set show_navigation_mobile = total_cards > mobile_cards %}

<div class="carousel-module {{ carousel_id }}{% if a.custom_class %} {{ a.custom_class }}{% endif %}"
     {% if a.custom_id %}id="{{ a.custom_id }}"{% endif %}
     role="region"
     aria-label="{{ c.carousel_title|default('Image carousel') }}"
     aria-roledescription="carousel"
     data-carousel-id="{{ carousel_id }}"
     data-desktop-cards="{{ desktop_cards }}"
     data-mobile-cards="{{ mobile_cards }}"
     data-autoplay="{{ b.autoplay_enabled|default(false) }}"
     data-autoplay-speed="{{ b.autoplay_speed|default(3000) }}"
     data-pause-on-hover="{{ b.pause_on_hover|default(true) }}"
     data-infinite-loop="{{ b.infinite_loop|default(true) }}"
     data-equal-height="{{ s.equal_height|default(true) }}"
     data-lazy="{{ a.lazy_load_carousel|default(true) }}">

  {# Module Title #}
  {% if c.show_title and c.carousel_title %}
    <h2 class="carousel-title" style="text-align: {{ s.title_alignment|default('center') }};">
      {{ c.carousel_title }}
    </h2>
  {% endif %}

  {# Navigation Buttons - positioned outside carousel-container to avoid overflow:hidden clipping #}
  {% if show_navigation %}
    <button class="carousel-nav carousel-nav-prev"
            aria-label="Go to previous slide"
            data-direction="prev"
            tabindex="0">
      <span class="carousel-arrow" aria-hidden="true">&#8249;</span>
    </button>
    <button class="carousel-nav carousel-nav-next"
            aria-label="Go to next slide"
            data-direction="next"
            tabindex="0">
      <span class="carousel-arrow" aria-hidden="true">&#8250;</span>
    </button>
  {% endif %}

  {# Carousel Container #}
  <div class="carousel-container">

    {# Cards Track #}
    <div class="carousel-track-wrapper" aria-live="polite" aria-atomic="false">
      <div class="carousel-track" role="list">
        {% for card in c.cards %}
          {% set has_image = card.background_image.src %}
          {% set has_height = s.image_height_type != 'none' %}
          {% set card_link = card.make_card_clickable ? card.card_link.url.href : null %}

          <div class="carousel-slide"
               role="listitem"
               aria-label="Slide {{ loop.index }} of {{ total_cards }}"
               data-slide-index="{{ loop.index0 }}">
            {% if card_link and card.make_card_clickable %}
              <a href="{{ card_link }}" class="card carousel-card clickable-card"
                 {{ card.card_link.open_in_new_tab ? 'target="_blank" rel="noopener"' : '' }}>
            {% else %}
              <div class="card carousel-card">
            {% endif %}

              {# Label Flag. (label_icon branch removed — no such field exists in
                 fields.json, so the icon could never render.) #}
              {% if card.show_label and card.label_text %}
                <div class="card-flag" style="--label-bg: {% if s.label_color.color %}rgba({{ s.label_color.color|convert_rgb }}, {{ s.label_color.opacity / 100 }}){% else %}{{ theme.core.colors.primary.color or '#007bff' }}{% endif %};">
                  <span class="card-flag-text">{{ card.label_text }}</span>
                </div>
              {% endif %}

              {# Background Image. (Video branch removed — use_video /
                 background_video_url / video_poster_image fields don't exist. #}
              {% if has_image %}
                <div class="card-media-wrapper"
                     style="{% if has_height %}
                              height: {{ s.image_height_type == 'custom' ? s.custom_image_height ~ 'px' : 'auto' }};
                              {% if s.image_height_type == 'full' %}height: 100%;{% endif %}
                            {% endif %}">
                    {% set image_url = card.background_image.src %}
                    {# Handle relative paths - apply get_asset_url for theme images #}
                    {% if '../../images/' in image_url %}
                      {% set image_url = get_asset_url(image_url) %}
                    {% endif %}
                    <picture>
                      {# Modern formats for better compression #}
                      {% if not ".svg" in image_url %}
                        <source srcset="{{ image_url }}?format=avif&width=800" type="image/avif">
                        <source srcset="{{ image_url }}?format=webp&width=800" type="image/webp">
                      {% endif %}
                      <img src="{{ image_url }}"
                           alt="{{ card.background_image.alt }}"
                           loading="lazy"
                           width="{{ card.background_image.width|default(800) }}"
                           height="{{ card.background_image.height|default(450) }}"
                           class="card-image">
                    </picture>
                </div>
              {% endif %}

              {# Card Content #}
              <div class="card-content {% if not has_height and has_image %}card-overlay{% endif %}"
                   style="{% if s.equal_height and not has_height %}
                            align-items: {{ s.content_vertical_alignment|default('flex-start') }};
                          {% endif %}">

                {% if card.title %}
                  <h3 class="card-title" style="text-align: {{ s.title_text_alignment|default('left') }};">
                    {{ card.title }}
                  </h3>
                {% endif %}

                {% if card.content %}
                  <div class="card-richtext">
                    {{ card.content }}
                  </div>
                {% endif %}

                {% if card.show_button and card.button_text and not card.make_card_clickable %}
                  <div class="card-button-wrapper" style="text-align: {{ s.button_text_alignment|default('left') }};">
                    <a href="{{ card.button_link.url.href }}"
                       class="btn btn-primary carousel-btn"
                       {% if s.button_color.color %}style="background: {{ s.button_color.color }}; border-color: {{ s.button_color.color }};"{% endif %}
                       {{ card.button_link.open_in_new_tab ? 'target="_blank" rel="noopener"' : '' }}>
                      {{ card.button_text }}
                    </a>
                  </div>
                {% endif %}
              </div>

            {% if card_link and card.make_card_clickable %}
              </a>
            {% else %}
              </div>
            {% endif %}
          </div>
        {% endfor %}
      </div>
    </div>

    {# Dots Navigation #}
    {% if b.show_dots and show_navigation %}
      <div class="carousel-dots">
        {% for i in range(0, total_cards) %}
          <button class="carousel-dot {% if loop.first %}active{% endif %}"
                  data-slide="{{ loop.index0 }}"
                  aria-label="Go to slide {{ loop.index }}"></button>
        {% endfor %}
      </div>
    {% endif %}
  </div>
</div>

{# Module-specific styles #}
<style>
  .{{ carousel_id }} {
    position: relative;
    margin: {{ s.margin_top|default(40) }}px 0 {{ s.margin_bottom|default(40) }}px;
  }

  .{{ carousel_id }} .carousel-container {
    position: relative;
    overflow: hidden;
  }

  .{{ carousel_id }} .carousel-track-wrapper {
    overflow: hidden;
    margin: 0 -{{ card_gap / 2 }}px;
  }

  .{{ carousel_id }} .carousel-track {
    display: flex;
    transition: transform {{ s.transition_speed|default(600) }}ms {{ s.transition_easing|default('cubic-bezier(0.25, 0.1, 0.25, 1)') }};
    padding: 0 {{ card_gap / 2 }}px;
    will-change: transform;
  }

  .{{ carousel_id }} .carousel-track.no-transition {
    transition: none !important;
  }

  .{{ carousel_id }} .carousel-slide {
    flex: 0 0 calc(100% / {{ desktop_cards }} - {{ card_gap }}px);
    margin: 0 {{ card_gap / 2 }}px;
  }

  .{{ carousel_id }} .carousel-card {
    height: 100%;
    position: relative;
  }

  {% include "../../includes/card-flag.css.html" %}

  {# Card Image Styles. Selector must be .card-media-wrapper (the actual markup) —
     .card-image-wrapper matched nothing, so "Image Aspect Ratio" did nothing. #}
  .{{ carousel_id }} .card-media-wrapper {
    position: relative;
    overflow: hidden;
    background: var(--color-bg-secondary, #f5f5f5);
    {% if s.image_aspect != 'auto' %}
    aspect-ratio: {{ s.image_aspect }};
    {% endif %}
  }

  .{{ carousel_id }} .card-image {
    width: 100%;
    height: 100%;
    object-fit: {{ s.image_fit|default('contain') }};
    display: block;
  }

  {# Content Overlay (when no height set) #}
  .{{ carousel_id }} .card-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: linear-gradient(to bottom, transparent 0%, rgba(0,0,0,0.7) 100%);
    color: white;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    padding: 1.5rem;
  }

  .{{ carousel_id }} .card-overlay .card-title {
    color: white;
  }

  {# Equal Height Layout #}
  {% if s.equal_height %}
    .{{ carousel_id }} .carousel-card {
      display: flex;
      flex-direction: column;
    }

    .{{ carousel_id }} .card-content:not(.card-overlay) {
      flex: 1;
      display: flex;
      flex-direction: column;
      justify-content: {{ s.content_vertical_alignment|default('flex-start') }};
    }
  {% endif %}

  {# Navigation Arrows - positioned relative to carousel-module (not carousel-container) #}
  .{{ carousel_id }} .carousel-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background: var(--color-bg, #ffffff);
    border: 2px solid var(--color-border, #e0e0e0);
    border-radius: 50%;
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 20;
    transition: all 0.3s ease;
    color: var(--color-text, #333333);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
    padding: 0;
    margin: 0;
  }

  .{{ carousel_id }} .carousel-arrow {
    font-size: 28px;
    font-weight: 300;
    line-height: 1;
    display: block;
    margin-top: -2px;
  }

  .{{ carousel_id }} .carousel-nav:hover:not([disabled]),
  .{{ carousel_id }} .carousel-nav:focus:not([disabled]) {
    background: var(--color-primary, #007bff);
    color: #ffffff;
    border-color: var(--color-primary, #007bff);
    transform: translateY(-50%) scale(1.1);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
  }

  .{{ carousel_id }} .carousel-nav-prev {
    left: 12px;
  }

  .{{ carousel_id }} .carousel-nav-next {
    right: 12px;
  }

  .{{ carousel_id }} .carousel-nav[disabled] {
    opacity: 0.35;
    cursor: not-allowed;
    background: var(--color-bg-secondary, #f5f5f5);
    box-shadow: none;
  }

  {# Dots Navigation #}
  .{{ carousel_id }} .carousel-dots {
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-top: 20px;
  }

  .{{ carousel_id }} .carousel-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    border: none;
    background: #e0e0e0;
    cursor: pointer;
    transition: all 0.3s ease;
  }

  .{{ carousel_id }} .carousel-dot.active {
    background: {{ s.label_color.color|default('var(--color-primary, #007bff)') }};
    width: 24px;
    border-radius: 4px;
  }

  {# Mobile Responsive #}
  @media (max-width: 992px) {
    .{{ carousel_id }} .carousel-slide {
      flex: 0 0 calc(100% / {{ mobile_cards }} - {{ card_gap }}px);
    }

    .{{ carousel_id }} .carousel-nav {
      {% if not show_navigation_mobile %}
        display: none;
      {% endif %}
    }

    .{{ carousel_id }} .card-flag {
      font-size: 0.625rem;
      padding: 3px 8px;
    }
  }

  {# Touch indicators for mobile #}
  @media (hover: none) and (pointer: coarse) {
    .{{ carousel_id }} .carousel-track-wrapper {
      cursor: grab;
    }

    .{{ carousel_id }} .carousel-track-wrapper:active {
      cursor: grabbing;
    }
  }
</style>

{# Carousel JavaScript — init deferred to idle time (was a ~10KB render-blocking
   synchronous IIFE). module.js was the dead duplicate implementation; deleted. #}
<script>
(function() {
  function initCarousel() {
  const carousel = document.querySelector('.{{ carousel_id }}');
  if (!carousel) return;

  // Mark as JavaScript enhanced for progressive enhancement
  carousel.classList.add('js-enhanced');

  const track = carousel.querySelector('.carousel-track');
  const slides = carousel.querySelectorAll('.carousel-slide');
  const prevBtn = carousel.querySelector('.carousel-nav-prev');
  const nextBtn = carousel.querySelector('.carousel-nav-next');
  const dots = carousel.querySelectorAll('.carousel-dot');

  const desktopCards = parseInt(carousel.dataset.desktopCards);
  const mobileCards = parseInt(carousel.dataset.mobileCards);
  {# Respect reduced-motion: no auto-advancing carousel (WCAG 2.2.2). #}
  const prefersReducedMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  const autoplay = carousel.dataset.autoplay === 'true' && !prefersReducedMotion;
  const autoplaySpeed = parseInt(carousel.dataset.autoplaySpeed);
  const pauseOnHover = carousel.dataset.pauseOnHover === 'true';
  const infiniteLoop = carousel.dataset.infiniteLoop === 'true';

  let currentIndex = 0;
  let autoplayInterval;
  let isTransitioning = false;
  let touchStartX = 0;
  let touchEndX = 0;

  // Responsive cards per view
  function getCardsPerView() {
    return window.innerWidth <= 768 ? mobileCards : desktopCards;
  }

  // Clone slides for infinite loop
  if (infiniteLoop && slides.length > getCardsPerView()) {
    // Clone first and last sets
    const firstClones = [];
    const lastClones = [];
    const cloneCount = getCardsPerView();

    for (let i = 0; i < cloneCount; i++) {
      firstClones.push(slides[i].cloneNode(true));
      lastClones.push(slides[slides.length - 1 - i].cloneNode(true));
    }

    // Add clones to track
    firstClones.forEach(clone => {
      clone.classList.add('clone');
      track.appendChild(clone);
    });

    {# insertBefore(firstChild) already reverses iteration order; an explicit
       .reverse() double-reversed the leading clones (slides out of order). #}
    lastClones.forEach(clone => {
      clone.classList.add('clone');
      track.insertBefore(clone, track.firstChild);
    });

    // Offset for clones
    currentIndex = cloneCount;
    updateCarousel(false);
  }

  function updateCarousel(animate = true) {
    const cardsPerView = getCardsPerView();
    const slideWidth = 100 / cardsPerView;
    const offset = -currentIndex * slideWidth;

    // Use class-based transition control for reliability
    if (animate) {
      track.classList.remove('no-transition');
    } else {
      track.classList.add('no-transition');
    }

    // Small delay to ensure transition class is applied before transform
    requestAnimationFrame(() => {
      track.style.transform = `translateX(${offset}%)`;
    });

    // Update ARIA attributes for screen readers
    slides.forEach((slide, index) => {
      const isVisible = index >= currentIndex && index < currentIndex + cardsPerView;
      slide.setAttribute('aria-hidden', !isVisible);
    });

    // Preload adjacent slide images for instant navigation
    preloadAdjacentSlides();

    // Update dots
    if (dots.length > 0) {
      dots.forEach(dot => dot.classList.remove('active'));
      const actualIndex = infiniteLoop ?
        (currentIndex - getCardsPerView() + slides.length) % slides.length :
        currentIndex;
      if (dots[actualIndex]) {
        dots[actualIndex].classList.add('active');
        dots[actualIndex].setAttribute('aria-current', 'true');
      }
      dots.forEach((dot, idx) => {
        if (idx !== actualIndex) {
          dot.removeAttribute('aria-current');
        }
      });
    }

    // Update navigation buttons
    if (!infiniteLoop) {
      if (prevBtn) prevBtn.disabled = currentIndex === 0;
      if (nextBtn) nextBtn.disabled = currentIndex >= slides.length - cardsPerView;
    }
  }

  function nextSlide() {
    if (isTransitioning) return;
    isTransitioning = true;

    const cardsPerView = getCardsPerView();
    const maxIndex = infiniteLoop ?
      slides.length + cardsPerView - 1 :
      Math.max(0, slides.length - cardsPerView);

    currentIndex++;

    if (infiniteLoop && currentIndex > maxIndex) {
      updateCarousel(true);
      setTimeout(() => {
        currentIndex = cardsPerView;
        updateCarousel(false);
        isTransitioning = false;
      }, {{ s.transition_speed|default(600) }});
    } else if (!infiniteLoop && currentIndex > maxIndex) {
      currentIndex = maxIndex;
      isTransitioning = false;
    } else {
      updateCarousel(true);
      setTimeout(() => {
        isTransitioning = false;
      }, {{ s.transition_speed|default(600) }});
    }
  }

  function prevSlide() {
    if (isTransitioning) return;
    isTransitioning = true;

    const cardsPerView = getCardsPerView();
    currentIndex--;

    if (infiniteLoop && currentIndex < 0) {
      updateCarousel(true);
      setTimeout(() => {
        currentIndex = slides.length - 1;
        updateCarousel(false);
        isTransitioning = false;
      }, {{ s.transition_speed|default(600) }});
    } else if (!infiniteLoop && currentIndex < 0) {
      currentIndex = 0;
      isTransitioning = false;
    } else {
      updateCarousel(true);
      setTimeout(() => {
        isTransitioning = false;
      }, {{ s.transition_speed|default(600) }});
    }
  }

  function goToSlide(index) {
    currentIndex = infiniteLoop ? index + getCardsPerView() : index;
    updateCarousel(true);
  }

  // Preload images in adjacent slides for instant navigation
  function preloadAdjacentSlides() {
    const cardsPerView = getCardsPerView();
    const preloadIndices = [
      currentIndex - 1,
      currentIndex + cardsPerView,
      currentIndex + cardsPerView + 1
    ];

    preloadIndices.forEach(index => {
      if (index >= 0 && index < slides.length) {
        const slide = slides[index];
        const img = slide.querySelector('img[loading="lazy"]');
        if (img && !img.complete) {
          // Force load by setting loading to eager
          img.loading = 'eager';
          // Preload modern formats too
          const picture = img.closest('picture');
          if (picture) {
            const sources = picture.querySelectorAll('source');
            sources.forEach(source => {
              if (!document.querySelector(`link[href="${source.srcset}"]`)) {
                const link = document.createElement('link');
                link.rel = 'preload';
                link.as = 'image';
                link.href = source.srcset;
                link.type = source.type;
                document.head.appendChild(link);
              }
            });
          }
        }
      }
    });
  }

  // Auto-play
  function startAutoplay() {
    if (!autoplay || slides.length <= getCardsPerView()) return;

    autoplayInterval = setInterval(() => {
      if (infiniteLoop) {
        nextSlide();
      } else {
        if (currentIndex >= slides.length - getCardsPerView()) {
          currentIndex = -1;
        }
        nextSlide();
      }
    }, autoplaySpeed);
  }

  function stopAutoplay() {
    if (autoplayInterval) {
      clearInterval(autoplayInterval);
    }
  }

  // Touch/Swipe support
  function handleTouchStart(e) {
    touchStartX = e.touches[0].clientX;
  }

  function handleTouchMove(e) {
    touchEndX = e.touches[0].clientX;
  }

  function handleTouchEnd() {
    if (!touchStartX || !touchEndX) return;

    const diff = touchStartX - touchEndX;
    const threshold = 50;

    if (Math.abs(diff) > threshold) {
      if (diff > 0) {
        nextSlide();
      } else {
        prevSlide();
      }
    }

    touchStartX = 0;
    touchEndX = 0;
  }

  // Event listeners
  if (prevBtn) prevBtn.addEventListener('click', prevSlide);
  if (nextBtn) nextBtn.addEventListener('click', nextSlide);

  dots.forEach((dot, index) => {
    dot.addEventListener('click', () => goToSlide(index));
  });

  // Keyboard navigation
  carousel.addEventListener('keydown', (e) => {
    if (e.key === 'ArrowLeft') {
      e.preventDefault();
      prevSlide();
    } else if (e.key === 'ArrowRight') {
      e.preventDefault();
      nextSlide();
    }
  });

  // Make carousel focusable for keyboard navigation
  carousel.setAttribute('tabindex', '0');

  // Touch events
  track.addEventListener('touchstart', handleTouchStart, { passive: true });
  track.addEventListener('touchmove', handleTouchMove, { passive: true });
  track.addEventListener('touchend', handleTouchEnd);

  // Pause on hover
  if (pauseOnHover && autoplay) {
    carousel.addEventListener('mouseenter', stopAutoplay);
    carousel.addEventListener('mouseleave', startAutoplay);
  }

  // Handle resize
  let resizeTimeout;
  window.addEventListener('resize', () => {
    clearTimeout(resizeTimeout);
    resizeTimeout = setTimeout(() => {
      updateCarousel(false);
    }, 150);
  });

  // Intersection Observer for better performance - pauses autoplay when off-screen
  if ('IntersectionObserver' in window && autoplay) {
    const visibilityObserver = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          if (!autoplayInterval && autoplay) {
            startAutoplay();
          }
        } else {
          stopAutoplay();
        }
      });
    }, { threshold: 0.1 });

    visibilityObserver.observe(carousel);
  }

  // Initialize
  updateCarousel(false);

  // Only start autoplay if carousel is visible or IntersectionObserver isn't supported
  if (autoplay) {
    if (!('IntersectionObserver' in window)) {
      startAutoplay();
    } else {
      // Check if carousel is initially visible
      const rect = carousel.getBoundingClientRect();
      if (rect.top < window.innerHeight && rect.bottom > 0) {
        startAutoplay();
      }
    }
  }
  }

  if ('requestIdleCallback' in window) {
    requestIdleCallback(initCarousel, { timeout: 500 });
  } else {
    window.addEventListener('load', initCarousel);
  }
})();
</script>
