Skip to main content

Logo Carousel

Copy and paste the code below into an HTML block via amplify homepage. Be sure to replace the "view members" button with the correct link you would like. You will also find the section where you can input the Streamline link of the images.


<!-- ================== Member Agencies Logo Carousel (Faster Auto-Rotate) ================== -->
<section
  class="logo-carousel"
  role="region"
  aria-roledescription="carousel"
  aria-label="Member agencies logo carousel"
  aria-live="off"
>
  <div class="lc-header">
    <h2 class="lc-title">Our Member Agencies</h2>
  </div>

  <div class="lc-viewport" tabindex="0" aria-label="Logo carousel viewport">
    <ul class="lc-track" role="list" aria-label="Agency logos"></ul>
  </div>

  <div class="lc-controls" aria-hidden="false">
    <button class="lc-prev" type="button" aria-label="Previous logos" title="Previous">◀</button>
    <button class="lc-next" type="button" aria-label="Next logos" title="Next">▶</button>
  </div>

  <div class="lc-cta-wrap">
    <a class="lc-cta" href="https://smwsa.specialdistrict.org/our-members">View all Members</a>
  </div>

  <div class="sr-only" aria-live="polite" aria-atomic="true"></div>
</section>

<style>
  .logo-carousel {
    --gap: 1.1rem;
    --slide-radius: 14px;
    --shadow: 0 4px 18px rgba(0,0,0,.08);
    --shadow-hover: 0 10px 28px rgba(0,0,0,.12);
    --transition-ms: 320; /* faster animation (was 480) */
    --visible: 5;
    --track-padding: .25rem;
    --bg: #ffffff;
    --ink: #0f172a;
    --accent: #197AA4; /* your blue */
  }

  .lc-header { text-align: center; margin-bottom: 0.75rem; }
  .lc-title {
    margin: 0 auto; color: var(--accent);
    font-size: clamp(1.25rem, 0.9rem + 1vw, 1.75rem);
    font-weight: 700; letter-spacing: 0.3px;
  }

  .lc-viewport {
    position: relative; overflow: hidden; border-radius: 18px;
    background: linear-gradient(180deg, #fff, #fafafa); padding: var(--track-padding);
  }

  .lc-track {
    display: flex; gap: var(--gap);
    will-change: transform; transition: transform calc(var(--transition-ms) * 1ms) ease;
    padding: 0; margin: 0; list-style: none;
  }

  .lc-slide {
    flex: 0 0 calc((100% - (var(--gap) * (var(--visible) - 1))) / var(--visible));
  }

  .lc-card {
    display: grid; place-items: center; aspect-ratio: 16/9;
    background: #fff; border-radius: var(--slide-radius);
    box-shadow: var(--shadow); border: 1px solid #e5e7eb;
    transition: box-shadow .25s ease, transform .25s ease, border-color .25s ease;
  }
  .lc-card:hover, .lc-card:focus-within {
    box-shadow: var(--shadow-hover); transform: translateY(-2px); border-color: #d0d7de;
  }

  .lc-logo {
    display: block; width: min(90%, 320px); height: auto;
    object-fit: contain; image-rendering: -webkit-optimize-contrast;
    transition: transform .25s ease;
  }
  .lc-card:hover .lc-logo { transform: scale(1.04); }

  .lc-controls {
    display: flex; gap: .5rem; justify-content: center; margin-top: .6rem;
  }
  .lc-prev, .lc-next {
    border: 1px solid #d1d5db; background: var(--bg); color: var(--ink);
    padding: .5rem .85rem; border-radius: 999px; min-width: 44px; min-height: 44px;
    cursor: pointer; box-shadow: var(--shadow);
    transition: box-shadow .2s ease, transform .12s ease;
  }
  .lc-prev:hover, .lc-next:hover { box-shadow: var(--shadow-hover); transform: translateY(-1px); }

  .lc-cta-wrap { display: flex; justify-content: center; margin-top: .8rem; }
  .lc-cta {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 44px; padding: .6rem 1.1rem; border-radius: 999px;
    font-weight: 600; text-decoration: none;
    background: var(--accent); color: #fff;
    box-shadow: var(--shadow); border: 1px solid rgba(0,0,0,0.06);
    transition: transform .12s ease, box-shadow .2s ease, filter .2s ease;
  }
  .lc-cta:hover { box-shadow: var(--shadow-hover); transform: translateY(-1px); filter: brightness(1.05); }
  .lc-cta:focus-visible { outline: 3px solid #0a84ff; outline-offset: 3px; }

  .sr-only {
    position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
  }

  @media (max-width: 1280px) { .logo-carousel { --visible: 4; } }
  @media (max-width: 992px)  { .logo-carousel { --visible: 3; } }
  @media (max-width: 640px)  { .logo-carousel { --visible: 2; } }
  @media (max-width: 420px)  { .logo-carousel { --visible: 1; } }

  @media (prefers-reduced-motion: reduce) {
    .logo-carousel { --transition-ms: 0; }
    .lc-card, .lc-logo { transition: none; }
  }
</style>

<script>
  (function () {
    const agencies = [
      /* Replace with your 14 real agencies (name + logo URL) */
      { name: "Agency 1", logo: "https://via.placeholder.com/560x280?text=Agency+1" },
      { name: "Agency 2", logo: "https://via.placeholder.com/560x280?text=Agency+2" },
      { name: "Agency 3", logo: "https://via.placeholder.com/560x280?text=Agency+3" },
      { name: "Agency 4", logo: "https://via.placeholder.com/560x280?text=Agency+4" },
      { name: "Agency 5", logo: "https://via.placeholder.com/560x280?text=Agency+5" },
      { name: "Agency 6", logo: "https://via.placeholder.com/560x280?text=Agency+6" },
      { name: "Agency 7", logo: "https://via.placeholder.com/560x280?text=Agency+7" },
      { name: "Agency 8", logo: "https://via.placeholder.com/560x280?text=Agency+8" },
      { name: "Agency 9", logo: "https://via.placeholder.com/560x280?text=Agency+9" },
      { name: "Agency 10", logo: "https://via.placeholder.com/560x280?text=Agency+10" },
      { name: "Agency 11", logo: "https://via.placeholder.com/560x280?text=Agency+11" },
      { name: "Agency 12", logo: "https://via.placeholder.com/560x280?text=Agency+12" },
      { name: "Agency 13", logo: "https://via.placeholder.com/560x280?text=Agency+13" },
      { name: "Agency 14", logo: "https://via.placeholder.com/560x280?text=Agency+14" },
    ];

    const root = document.currentScript.previousElementSibling.previousElementSibling;
    const track = root.querySelector('.lc-track');
    const prevBtn = root.querySelector('.lc-prev');
    const nextBtn = root.querySelector('.lc-next');
    const srLive = root.querySelector('.sr-only');

    let idx = 0, autoTimer = null;

    function buildSlides() {
      track.innerHTML = "";
      agencies.forEach(({ name, logo }) => {
        const li = document.createElement('li');
        li.className = 'lc-slide';
        const card = document.createElement('div'); card.className = 'lc-card';
        const img = document.createElement('img');
        img.className = 'lc-logo'; img.src = logo; img.alt = name; img.loading = 'lazy'; img.decoding = 'async';
        card.appendChild(img); li.appendChild(card); track.appendChild(li);
      });
      addClones();
    }

    function addClones() {
      const realSlides = slides().filter(li => !li.dataset.clone);
      const need = Math.min(getVisibleCount(), realSlides.length);
      for (let i = 0; i < need; i++) {
        const clone = realSlides[i].cloneNode(true);
        clone.dataset.clone = "true";
        clone.setAttribute('aria-hidden', 'true');
        track.appendChild(clone);
      }
    }

    function slides() { return Array.from(track.querySelectorAll('.lc-slide')); }
    function gapPx() { const g = getComputedStyle(track).gap; return g ? parseFloat(g) : 0; }
    function slideW() { const s = slides()[0]; return s ? s.getBoundingClientRect().width + gapPx() : 0; }
    function maxIndex() { return slides().filter(li => !li.dataset.clone).length; }
    function tMs() { const v = parseInt(getComputedStyle(root).getPropertyValue('--transition-ms'), 10); return isNaN(v) ? 320 : v; }
    function getVisibleCount() { return parseInt(getComputedStyle(root).getPropertyValue('--visible'), 10) || 5; }

    function setTransform(i, ms = tMs()) {
      const realCount = maxIndex();
      const w = slideW();
      track.style.transitionDuration = ms + 'ms';
      if (i > realCount) {
        idx = 1;
        track.style.transitionDuration = '0ms';
        track.style.transform = 'translateX(' + (-w * idx) + 'px)';
        track.getBoundingClientRect();
        track.style.transitionDuration = ms + 'ms';
      } else idx = i;
      track.style.transform = 'translateX(' + (-w * idx) + 'px)';
    }

    function next(step = 1) { setTransform(idx + step); }
    function prev(step = 1) {
      const realCount = maxIndex();
      if (idx <= 0) {
        const w = slideW();
        idx = realCount;
        track.style.transitionDuration = '0ms';
        track.style.transform = 'translateX(' + (-w * idx) + 'px)';
        track.getBoundingClientRect();
        track.style.transitionDuration = tMs() + 'ms';
      }
      setTransform(idx - step);
    }

    function startAuto() {
      stopAuto();
      autoTimer = setInterval(() => next(1), 1600); // faster advance (was 3000)
    }
    function stopAuto() { if (autoTimer) clearInterval(autoTimer); autoTimer = null; }

    prevBtn.addEventListener('click', () => { stopAuto(); prev(); });
    nextBtn.addEventListener('click', () => { stopAuto(); next(); });

    root.addEventListener('mouseenter', stopAuto);
    root.addEventListener('mouseleave', startAuto);

    window.addEventListener('resize', () => setTransform(idx, 0));
    document.addEventListener('visibilitychange', () => { if (document.hidden) stopAuto(); else startAuto(); });

    buildSlides();
    setTransform(0, 0);
    startAuto();
  })();
</script>
<!-- ================== /Member Agencies Logo Carousel (Faster Auto-Rotate) ================== -->