(() => {
  const section = document.querySelector('#platform');
  const rail = document.querySelector('#system-parts');
  if (!section || !rail) return;

  const cards = [...rail.querySelectorAll('.platform-v2-card')];
  const title = document.querySelector('#platform-title');
  const description = document.querySelector('#platform-description');
  const leadCount = document.querySelector('#platform-lead-count');
  const progress = document.querySelector('#platform-progress');
  const fill = document.querySelector('#platform-progress-fill');
  const previous = document.querySelector('#platform-prev');
  const next = document.querySelector('#platform-next');
  const pagination = document.querySelector('#platform-pagination');
  const dots = cards.map((card, index) => {
    const dot = document.createElement('button');
    dot.type = 'button';
    dot.className = 'platform-v2-dot';
    dot.setAttribute('aria-label', `Показать возможность ${index + 1}: ${card.dataset.title}`);
    dot.addEventListener('click', () => goTo(index));
    pagination.append(dot);
    return dot;
  });
  const compact = matchMedia('(max-width: 800px), (prefers-reduced-motion: reduce)');
  const reduce = matchMedia('(prefers-reduced-motion: reduce)');
  const introTitle = title.innerHTML;
  const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
  const lead = section.querySelector('.platform-v2-lead');
  function sizeCompactLead() {
    if (!compact.matches) {
      lead.style.removeProperty('--platform-lead-height');
      return;
    }
    const width = lead.getBoundingClientRect().width;
    if (!width) return;
    const measure = lead.cloneNode(true);
    measure.style.cssText = `position:absolute;visibility:hidden;pointer-events:none;left:-10000px;top:0;width:${width}px;max-width:none;height:auto;min-height:0;margin:0`;
    section.append(measure);
    const measureTitle = measure.querySelector('h2');
    const measureDescription = measure.querySelector('p');
    const variants = [{ title: introTitle, description: '', intro: true }, ...cards.map(card => ({ title: card.dataset.title, description: card.dataset.description }))];
    let tallest = 0;
    variants.forEach(variant => {
      if (variant.intro) measureTitle.innerHTML = variant.title;
      else measureTitle.textContent = variant.title;
      measureDescription.textContent = variant.description;
      tallest = Math.max(tallest, measure.scrollHeight);
    });
    measure.remove();
    lead.style.setProperty('--platform-lead-height', `${Math.ceil(tallest + 4)}px`);
  }
  const morphEnd = .16;
  const portalStart = .04;
  const imageEnd = .18;
  const stackEnd = .90;
  let active = -2;
  let frame = 0;
  let wheelLockedUntil = 0;

  function setActive(index, intro = false) {
    const nextActive = intro ? -1 : index;
    if (active === nextActive) return;
    active = nextActive;
    if (intro) title.innerHTML = introTitle;
    else title.textContent = cards[index].dataset.title;
    description.textContent = intro ? '' : cards[index].dataset.description;
    leadCount.textContent = intro ? 'КЛУБ / ПЛАТФОРМА' : `${String(index + 1).padStart(2, '0')} / 07`;
    progress.textContent = `${String(index + 1).padStart(2, '0')} / 07`;
    previous.disabled = intro || index === 0;
    next.disabled = !intro && index === cards.length - 1;
    dots.forEach((dot, i) => {
      const selected = !intro && i === index;
      dot.classList.toggle('is-active', selected);
      dot.setAttribute('aria-current', String(selected));
    });
    if (!reduce.matches && title.animate) {
      title.animate([{ opacity: .62, transform: 'translateY(8px)' }, { opacity: 1, transform: 'translateY(0)' }], { duration: 260, easing: 'ease-out' });
      if (!intro) description.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 300, easing: 'ease-out' });
    }
    cards.forEach((card, i) => {
      card.classList.toggle('is-active', !intro && i === index);
      card.classList.toggle('has-history', !intro && index > 0 && i === index);
      if (compact.matches) {
        card.removeAttribute('aria-hidden');
      } else {
        card.setAttribute('aria-hidden', String(intro || i !== index));
      }
    });
  }

  function syncOpenAvailability() {
    const imageVisible = section.classList.contains('is-image-visible');
    cards.forEach((card, i) => {
      const open = card.querySelector('.platform-v2-open');
      if (!open) return;
      const available = imageVisible && (compact.matches || i === active);
      open.disabled = !available;
      open.tabIndex = available ? 0 : -1;
    });
  }

  function update() {
    frame = 0;
    if (compact.matches) {
      section.classList.add('is-image-visible');
      section.dataset.stackEnergy = '0';
      const span = Math.max(1, rail.scrollWidth - rail.clientWidth);
      const value = clamp(rail.scrollLeft / span, 0, 1);
      const center = rail.scrollLeft + rail.clientWidth / 2;
      let closest = 0, distance = Infinity;
      cards.forEach((card, i) => {
        const delta = Math.abs(card.offsetLeft + card.offsetWidth / 2 - center);
        if (delta < distance) { distance = delta; closest = i; }
        card.style.removeProperty('transform');
        card.style.removeProperty('opacity');
        card.style.removeProperty('z-index');
        card.style.removeProperty('clip-path');
        card.style.removeProperty('filter');
        card.classList.remove('is-stacked');
      });
      section.dataset.morph = '1';
      section.classList.remove('is-morphed');
      fill.style.transform = `scaleX(${Math.max((closest + 1) / cards.length, value)})`;
      setActive(closest);
      syncOpenAvailability();
      document.dispatchEvent(new Event('club:part'));
      return;
    }

    const rect = section.getBoundingClientRect();
    const travel = Math.max(1, section.offsetHeight - innerHeight);
    const raw = clamp(-rect.top / travel, 0, 1);
    const morph = clamp(raw / morphEnd, 0, 1);
    const portal = clamp((raw - portalStart) / (imageEnd - portalStart), 0, 1);
    section.classList.toggle('is-image-visible', portal > .92);
    const position = clamp((raw - imageEnd) / (stackEnd - imageEnd), 0, 1) * (cards.length - 1);
    const index = clamp(Math.floor(position + .3), 0, cards.length - 1);
    section.dataset.morph = morph.toFixed(3);
    section.dataset.stackEnergy = (portal * Math.min(1, .52 + position * .085)).toFixed(3);
    section.classList.toggle('is-morphed', morph > .98);
    section.style.setProperty('--platform-portal', portal.toFixed(3));
    setActive(index, raw < portalStart);
    syncOpenAvailability();

    const rise = Math.min(innerHeight * .68, 520);
    cards.forEach((card, i) => {
      const depth = Math.max(0, position - i);
      const arriving = i > 0 && i - 1 <= position && position < i;
      const arrival = arriving ? clamp(position - (i - 1), 0, 1) : position >= i ? 1 : 0;
      const eased = arrival * arrival * (3 - 2 * arrival);
      const stacked = depth > .04 && depth < 3;
      const visible = i === 0 || depth < 2.8;
      const x = depth > 0 ? -Math.min(depth, 2.5) * 22 : 0;
      const y = i === 0 ? Math.min(depth, 2.5) * 13 : arriving ? (1 - eased) * rise : position >= i ? Math.min(depth, 2.5) * 13 : rise;
      const scale = arriving ? .965 + eased * .035 : 1 - Math.min(depth, 2.5) * .028;
      const tilt = arriving ? (1 - eased) * 2.5 : -Math.min(depth, 2.5) * .8;
      const opacity = i === 0
        ? clamp(portal * 4, 0, 1) * (visible ? 1 - Math.min(depth, 2.5) * .12 : 0)
        : arriving ? clamp((arrival - .02) / .2, 0, 1)
          : position >= i && visible ? 1 - Math.min(depth, 2.5) * .12 : 0;
      card.style.transform = `translate3d(${x.toFixed(1)}px, ${y.toFixed(1)}px, ${(-Math.min(depth, 2.5) * 32).toFixed(1)}px) rotateZ(${tilt.toFixed(2)}deg) scale(${scale.toFixed(3)})`;
      card.style.opacity = opacity.toFixed(3);
      card.style.filter = depth > 0 ? `brightness(${(1 - Math.min(depth, 2.5) * .09).toFixed(3)})` : '';
      card.classList.toggle('is-stacked', stacked);
      card.style.zIndex = String(i + 2);
      card.style.removeProperty('clip-path');
    });
    fill.style.transform = `scaleX(${(index + 1) / cards.length})`;
    document.dispatchEvent(new Event('club:part'));
  }

  function requestUpdate() { if (!frame) frame = requestAnimationFrame(update); }
  function goTo(index) {
    const target = clamp(index, 0, cards.length - 1);
    if (compact.matches) {
      const card = cards[target];
      rail.scrollTo({ left: card.offsetLeft + card.offsetWidth / 2 - rail.clientWidth / 2, behavior: reduce.matches ? 'instant' : 'smooth' });
    } else {
      const total = section.offsetHeight - innerHeight;
      const position = imageEnd + (target / (cards.length - 1)) * (stackEnd - imageEnd);
      scrollTo({ top: scrollY + section.getBoundingClientRect().top + total * position, behavior: 'smooth' });
    }
  }
  // Each desktop wheel gesture advances one complete card while the card stage is pinned.
  // The intro morph and the section exits keep their natural page scrolling.
  function snapWheel(event) {
    if (compact.matches || event.ctrlKey || Math.abs(event.deltaY) < 4 || document.querySelector('dialog[open]')) return;
    const rect = section.getBoundingClientRect();
    const travel = Math.max(1, section.offsetHeight - innerHeight);
    const raw = clamp(-rect.top / travel, 0, 1);
    if (rect.top > 1 || rect.bottom < innerHeight - 1 || raw < imageEnd - .012 || raw > stackEnd + .012) return;
    const direction = Math.sign(event.deltaY);
    const now = performance.now();
    if (now < wheelLockedUntil) { event.preventDefault(); return; }
    const current = clamp(active, 0, cards.length - 1);
    if ((current === 0 && direction < 0) || (current === cards.length - 1 && direction > 0)) return;
    event.preventDefault();
    wheelLockedUntil = now + 680;
    goTo(current + direction);
  }
  previous.addEventListener('click', () => goTo(active - 1));
  next.addEventListener('click', () => goTo(active + 1));
  addEventListener('wheel', snapWheel, { passive: false });
  addEventListener('scroll', requestUpdate, { passive: true });
  addEventListener('resize', () => { sizeCompactLead(); requestUpdate(); }, { passive: true });
  rail.addEventListener('scroll', requestUpdate, { passive: true });
  compact.addEventListener('change', () => { sizeCompactLead(); requestUpdate(); });

  section.classList.add('is-ready');
  sizeCompactLead();
  document.fonts?.ready.then(sizeCompactLead);
  update();
})();
