// Hyper · страница «Услуги» (services.html)
// Двухуровневая навигация: направления (gateway / sticky-бар) → тарифы направления.
// Использует React.* напрямую (без деструктуризации), чтобы не конфликтовать
// с cursor.jsx, где useEffect/useRef/useState уже объявлены в global-scope.

const CONTACT_HREF = 'index.html#contact';

// ──────────────────────────────────────────────
// ДАННЫЕ УСЛУГ — 6 направлений, у каждого тарифы и состав работ.
// ──────────────────────────────────────────────
const SERVICES_DATA = [
  {
    id: 'marketing',
    idx: '01',
    name: 'Маркетинг',
    kicker: 'полный цикл',
    lede: 'Системный маркетинг под ключ. Start — фокус на одной метрике и быстрых лидах в 1–2 каналах. Boost — все каналы под единой стратегией с брендингом и масштабированием.',
    stat: [{ k: 'тарифа', v: '2' }, { k: 'формат', v: 'ежемесячно' }, { k: 'от', v: '80 000 ₽' }],
    tariffs: [
      {
        name: 'Start',
        pitch: 'Вход в системный маркетинг. Выбираем один ключевой показатель — лиды или трафик — и работаем на него до победного. Без распыления.',
        result: 'К концу месяца — чёткая цифра по главной метрике и порядок вместо хаоса в рекламе. Перестаёте сливать бюджет на каналы, которые не дают результата здесь и сейчас.',
        includes: [
          'Аудит «точки А» и план действий на 1 месяц',
          '1–2 канала продаж + проверка маркетинговых гипотез',
          'Influence Light: 3–4 точечные интеграции в месяц с ТЗ',
          'Контроль контент-плана SMM + отчёт по ключевой метрике',
        ],
        scope: 'На нас — маркетолог с гипотезами, project-менеджер с контролем подрядчиков и дедлайнов, настройка и ведение рекламных кампаний.',
        note: 'Бюджет на рекламу — от 70 000 ₽/мес, оплачивается отдельно. Не входит: производство контента, ведение соцсетей и техническая разработка (берём подрядчиков под ТЗ).',
        price: '80 000 ₽', per: 'мес', from: true,
      },
      {
        name: 'Boost',
        tag: 'популярный',
        accent: true,
        pitch: 'Забираем управление всем маркетингом на себя и превращаем его в конвейер лидов. Все каналы под единой стратегией на 3 месяца.',
        result: 'Системный маркетинг под ключ: прозрачность по каждой рекламной итерации, рост узнаваемости и масштабирование. Деньги идут только туда, где есть отдача — канал не работает, закрываем без эго.',
        includes: [
          'Аудит точки А, разведка конкурентов, стратегия на 3 мес',
          'Управление всеми каналами: Гео, Яндекс, Авито, influence',
          'Контроль SMM, чтобы посты продавали',
          'Масштабирование: наружка, кросс-маркетинг, коллаборации',
        ],
        scope: 'На нас — маркетолог-стратег, креативный директор, дизайнер (в рамках лимитов), ТЗ и контроль всех подрядчиков, ежемесячная аналитика и стратегия.',
        note: 'Бюджет на рекламу — от 150 000 ₽/мес, оплачивается отдельно. Не входит: производство контента, ведение соцсетей и техническая разработка.',
        price: '150 000 ₽', per: 'мес', from: true,
      },
    ],
  },
  {
    id: 'smm',
    idx: '02',
    name: 'SMM',
    kicker: 'контент, который продаёт',
    lede: 'Ведение и рост в Instagram. База — стабильное ведение и регулярный контент, чтобы не терять позиции. Pro — комплексный рост со стратегией, рубрикатором и активным продвижением.',
    stat: [{ k: 'тарифа', v: '2' }, { k: 'формат', v: 'ежемесячно' }, { k: 'от', v: '70 000 ₽' }],
    tariffs: [
      {
        name: 'База',
        pitch: 'Базовое ведение Instagram — для бизнеса, которому важно не терять позиции в соцсети и держать живой профиль без своего участия.',
        result: 'Стабильное профессиональное присутствие: регулярный контент, оформленный профиль и живая лента. Аккаунт не простаивает, а планомерно работает на образ бренда.',
        includes: [
          '8 постов + 6 Reels + 2 фото-карусели в месяц',
          '60 Stories (≈2 в день, с выходными)',
          '1 интеграция блогер / паблик в месяц',
          'Аудит, контент-план, фирменное оформление и «Актуальное»',
        ],
        scope: 'Команда проекта: контент-мейкер, руководитель отдела SMM и менеджер отдела заботы — отвечают за регулярность, качество и соблюдение договорённостей.',
        note: 'Не входит: обработка директа и комментариев. Бюджет на рекламу у блогеров/пабликов оплачивается отдельно.',
        price: '70 000 ₽', per: 'мес', from: true,
      },
      {
        name: 'Pro',
        tag: 'продвинутый',
        accent: true,
        pitch: 'Комплексный рост в Instagram: стратегия, рубрикатор, профессиональный контент и активное продвижение через блогеров и паблики.',
        result: 'Заметный рост и укрепление позиций в соцсети. Контент работает на охваты и продажи по стратегии, растёт поток обращений в директ — профиль становится каналом привлечения, а не витриной.',
        includes: [
          '15 постов + 10 Reels + 5 фото / дизайн в месяц',
          '150 Stories (≈5 в день, прогревы и удержание)',
          'До 4 интеграций: блогеры + паблики',
          'Стратегия, анализ ЦА и конкурентов, рубрикатор, фирменный визуал',
        ],
        scope: 'Команда: менеджер проекта, графический дизайнер, креативный руководитель, руководитель SMM и отдел заботы. Контролируем скорость и качество ответов ваших менеджеров и даём обучающие материалы.',
        note: 'Не входит: обработка директа и комментариев (это зона ваших менеджеров). Рекламный бюджет оплачивается отдельно.',
        price: '120 000 ₽', per: 'мес', from: true,
      },
    ],
  },
  {
    id: 'maximum',
    idx: '03',
    name: 'Максимум',
    kicker: 'флагман агентства',
    lede: 'Гибрид маркетинга и SMM под одной командой. Performance, контент-производство и аналитика с единым KPI — для брендов, которым нужен один подрядчик с ответственностью за результат, а не пять.',
    stat: [{ k: 'тариф', v: '1' }, { k: 'команда', v: 'выделенная' }, { k: 'от', v: '240 000 ₽' }],
    tariffs: [
      {
        name: 'Тариф «Максимум»',
        tag: 'флагман',
        accent: true,
        pitch: 'Объединяет маркетинг Boost и SMM Pro: стратегия захвата рынка, производство контента, продвижение и аналитика — в одной связке под единым KPI.',
        result: 'Весь маркетинг — от стратегии до последнего Reels — в одних руках. Стратег, креатив и контент работают синхронно, а вы получаете один центр ответственности за результат вместо пяти подрядчиков, которые кивают друг на друга.',
        includes: [
          'Полный маркетинг-блок Boost: стратегия на 3 мес, все каналы, масштабирование',
          'Полный SMM-блок Pro: 15 постов + 10 Reels + 150 Stories',
          'Организация съёмок и дизайнерские макеты',
          'Синхронизация контента, рекламы и стратегии',
          'Сквозная аналитика и квартальные отчёты',
        ],
        scope: 'Выделенная команда: маркетолог-стратег, креативный руководитель, продюсер, контент-мейкер, дизайнер, руководитель SMM и отдел заботы. На нас — ТЗ и контроль всех сторонних подрядчиков.',
        note: 'Бюджет на рекламу — от 150 000 ₽/мес, оплачивается отдельно. Не входит: техническая разработка (сайты, CRM) — привлекаем специалистов под ТЗ.',
        price: '240 000 ₽', per: 'мес', from: true,
      },
    ],
  },
  {
    id: 'branding',
    idx: '04',
    name: 'Брендинг',
    kicker: 'айдентика и упаковка',
    lede: 'Идентика, упаковка и фирменный стиль — визуальный код, который раскрывает смыслы бренда. Подход не «нарисовать красиво», а маркетинговый: позиционирование, смыслы и целевая аудитория.',
    stat: [{ k: 'формат', v: 'проект' }, { k: 'результат', v: 'гайдлайн' }, { k: 'от', v: '50 000 ₽' }],
    tariffs: [
      {
        name: 'Брендинг под ключ',
        pitch: 'Логотип, айдентика, фирменный стиль и дизайн упаковки. Сначала позиционирование, смыслы и ЦА — и уже под это визуальный код.',
        result: 'Цельный визуальный язык, который раскрывает смыслы бренда и работает на узнаваемость и продажи. Не «красивый логотип», а система, в которой бизнес выглядит дороже конкурентов.',
        includes: [
          'Логотип и фирменный знак',
          'Айдентика и гайдлайн использования',
          'Дизайн упаковки и носителей',
          'Стратегия позиционирования и смыслов',
        ],
        scope: 'На нас — маркетинговая логика бренда и весь визуал. На выходе вы получаете готовый гайдлайн, по которому работает любой подрядчик.',
        price: '50 000 ₽', per: 'проект', from: true,
      },
    ],
  },
  {
    id: 'production',
    idx: '05',
    name: 'Продакшн',
    kicker: 'съёмка роликов',
    lede: 'Отдельное направление — съёмка рекламных роликов любой сложности. От телефонного reels-сценария до павильона с режиссёром, светом, актёрами и пост-продакшном.',
    stat: [{ k: 'формат', v: 'за ролик' }, { k: 'площадки', v: 'все' }, { k: 'от', v: '5 000 ₽' }],
    tariffs: [
      {
        name: 'Съёмка рекламных роликов',
        pitch: 'Заходим в продукт, придумываем идею, снимаем и монтируем — под любой бюджет и площадку. От reels на телефон до павильона с режиссёром.',
        result: 'Готовый рекламный материал, который цепляет с первых секунд и работает на задачу — охваты, заявки или имидж. Один исходник адаптируем под все площадки, где он будет жить.',
        includes: [
          'Сценарий и раскадровка под задачу',
          'Подбор локации, актёров и команды',
          'Съёмочный день и монтаж',
          'Адаптация под все площадки и форматы',
        ],
        scope: 'На нас — весь путь от идеи до финального монтажа. Работаем под любой бюджет: от мобильного reels до полноценного продакшна со светом и звуком.',
        price: '5 000 — 100 000 ₽', per: 'ролик', from: true,
      },
    ],
  },
  {
    id: 'extra',
    idx: '06',
    name: 'Доп. услуги',
    kicker: 'разовые работы',
    lede: 'Разовые работы для тех, кому пока не нужен подрядчик на ведение. Глубокий разбор бизнеса и каналов с готовой дорожной картой роста — без общих советов.',
    stat: [{ k: 'формата', v: '2' }, { k: 'результат', v: 'план действий' }, { k: 'от', v: '25 000 ₽' }],
    tariffs: [
      {
        name: 'Разработка стратегии',
        pitch: 'Глубокий аудит бизнеса и каналов, поиск узких мест, расчёт потенциала и план действий. На итоговой консультации презентуем решение с цифрами.',
        result: 'Дорожная карта роста с цифрами: что делать, в каком порядке и какой потенциал у каждого канала. Готовое решение, по которому можно двигаться самим или с любым подрядчиком.',
        includes: [
          'Глубинное интервью по бизнесу',
          'Аудит каналов и текущих цифр',
          'Разработка решения и расчёт потенциала',
          'Презентация на консультации',
        ],
        scope: 'Разбираем по существу, без общих советов из интернета — только то, что применимо к вашему бизнесу.',
        price: '45 000 ₽', per: 'работа',
      },
      {
        name: 'Аудит',
        pitch: 'Разбираем маркетинг и SMM по слоям: ищем точки потери денег и на стратегической сессии выдаём готовую дорожную карту роста.',
        result: 'Понимаете, где именно теряете деньги, и получаете пошаговый план на 30 / 60 / 90 дней. Ясность вместо ощущения, что «маркетинг как-то идёт».',
        includes: [
          'Бриф и сбор данных по бизнесу',
          'Аудит SMM, рекламы и воронки',
          'Стратегическая сессия от 2 часов',
          'PDF с планом действий 30 / 60 / 90 дней',
        ],
        scope: 'На нас — честный разбор по слоям и конкретный план. Без воды и обтекаемых формулировок.',
        price: '25 000 ₽', per: 'работа',
      },
    ],
  },
];

// ──────────────────────────────────────────────
// ЛОКАЛЬНЫЕ ЭФФЕКТЫ СЦЕНЫ (scoped к текущему направлению)
// reveal · magnetic · 3D-tilt · parallax · follow-glow
// ──────────────────────────────────────────────
function useSceneFx(rootRef, dep) {
  React.useEffect(() => {
    const root = rootRef.current;
    if (!root) return;
    const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    // reveal
    const fades = [...root.querySelectorAll('.fade-up')];
    fades.forEach((el, i) => {
      if (!el.style.transitionDelay) el.style.transitionDelay = (Math.min(i, 6) * 0.06) + 's';
    });
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); }
      });
    }, { threshold: 0.12 });
    fades.forEach((el) => {
      const r = el.getBoundingClientRect();
      if (r.top < window.innerHeight) el.classList.add('in');
      else io.observe(el);
    });

    // magnetic
    const mags = [...root.querySelectorAll('.magnetic')];
    const magH = [];
    mags.forEach((el) => {
      const move = (e) => {
        const r = el.getBoundingClientRect();
        const dx = (e.clientX - (r.left + r.width / 2)) * 0.2;
        const dy = (e.clientY - (r.top + r.height / 2)) * 0.3;
        el.style.transform = `translate(${dx}px, ${dy}px)`;
      };
      const leave = () => { el.style.transform = ''; };
      el.addEventListener('mousemove', move);
      el.addEventListener('mouseleave', leave);
      magH.push([el, move, leave]);
    });

    // 3D tilt (.tilt)
    const tilts = [...root.querySelectorAll('.tilt')];
    const tiltH = [];
    if (!reduce) tilts.forEach((el) => {
      const move = (e) => {
        const r = el.getBoundingClientRect();
        const px = (e.clientX - r.left) / r.width - 0.5;
        const py = (e.clientY - r.top) / r.height - 0.5;
        el.style.transform = `perspective(900px) rotateX(${(-py * 4).toFixed(2)}deg) rotateY(${(px * 5).toFixed(2)}deg) translateY(-4px)`;
      };
      const leave = () => { el.style.transform = ''; };
      el.addEventListener('mousemove', move);
      el.addEventListener('mouseleave', leave);
      tiltH.push([el, move, leave]);
    });

    // follow-glow ([data-glow] → .glow)
    const glows = [...root.querySelectorAll('[data-glow]')];
    const glowH = [];
    glows.forEach((el) => {
      const g = el.querySelector('.glow');
      if (!g) return;
      const move = (e) => {
        const r = el.getBoundingClientRect();
        g.style.left = (e.clientX - r.left - 210) + 'px';
        g.style.top = (e.clientY - r.top - 210) + 'px';
      };
      el.addEventListener('mousemove', move);
      glowH.push([el, move]);
    });

    // parallax ([data-speed])
    const pxEls = [...root.querySelectorAll('[data-speed]')];
    let raf;
    const tick = () => {
      const vh = window.innerHeight;
      pxEls.forEach((el) => {
        const r = el.getBoundingClientRect();
        const delta = (r.top + r.height / 2 - vh / 2) / vh;
        const sp = parseFloat(el.dataset.speed) || 0;
        el.style.transform = `translateY(${(delta * sp * 100).toFixed(1)}px)`;
      });
      raf = requestAnimationFrame(tick);
    };
    if (!reduce) raf = requestAnimationFrame(tick);

    return () => {
      io.disconnect();
      if (raf) cancelAnimationFrame(raf);
      magH.forEach(([el, m, l]) => { el.removeEventListener('mousemove', m); el.removeEventListener('mouseleave', l); });
      tiltH.forEach(([el, m, l]) => { el.removeEventListener('mousemove', m); el.removeEventListener('mouseleave', l); });
      glowH.forEach(([el, m]) => { el.removeEventListener('mousemove', m); });
    };
  }, [dep]);
}

// ──────────────────────────────────────────────
// NAV
// ──────────────────────────────────────────────
function ServicesNav({ active, onPick }) {
  return (
    <nav className="nav work-nav">
      <a href="index.html" className="nav-logo" data-cursor data-cursor-label="на главную">
        <img className="nav-eyes" src="assets/brand-mark-tight.png" alt="ХАЙПЕР" />
        <span className="nav-wordmark">ХАЙПЕР</span>
      </a>
      <div className="nav-links">
        {SERVICES_DATA.map((c) => (
          <a
            key={c.id}
            href={'#' + c.id}
            className={active === c.id ? 'is-active' : ''}
            onClick={(e) => { e.preventDefault(); onPick(c.id, true); }}>
            {c.name}
          </a>
        ))}
        <a href="work.html">Кейсы</a>
      </div>
      <a href="https://wa.me/79886554717" target="_blank" rel="noopener" className="nav-cta magnetic" data-cursor data-cursor-label="WhatsApp">
        WhatsApp&nbsp;→
      </a>
    </nav>
  );
}

// ──────────────────────────────────────────────
// HERO / GATEWAY (6 направлений)
// ──────────────────────────────────────────────
function ServicesHero({ active, onPick }) {
  const rootRef = React.useRef(null);
  useSceneFx(rootRef, 'hero');
  return (
    <header className="sv-hero" ref={rootRef}>
      <div className="sv-hero-glow" data-speed="0.18" aria-hidden="true"></div>
      <div className="shell">
        <div className="sv-hero-eyebrow fade-up"><span className="pulse"></span>Хайпер · услуги · 2026</div>
        <h1 className="fade-up d-1">
          Что мы <span className="accent">делаем</span><br />
          <span className="muted">и сколько это стоит.</span>
        </h1>
        <p className="sv-hero-sub fade-up d-2">
          Не «полный спектр услуг», а <strong>шесть конкретных направлений</strong> с понятными
          тарифами и составом работ. Можно взять одно — например, только SMM или продакшн, —
          а можно сразу «Максимум» и закрыть весь маркетинг одним подрядчиком.
        </p>

        <div className="sv-gate fade-up d-3">
          {SERVICES_DATA.map((c) => {
            const fromPrice = (c.stat.find((s) => s.k === 'от') || {}).v;
            return (
              <button
                key={c.id}
                className={'sv-gate-card magnetic' + (active === c.id ? ' is-active' : '') + (c.id === 'maximum' ? ' is-flag' : '')}
                data-cursor data-cursor-label="открыть"
                onClick={() => onPick(c.id, true)}>
                <span className="glow"></span>
                <span className="sv-gate-top">
                  <span className="sv-gate-idx">{c.idx}</span>
                  <span className="sv-gate-arrow">↗</span>
                </span>
                <span className="sv-gate-name">{c.name}</span>
                <span className="sv-gate-kicker">{c.kicker}</span>
                {fromPrice && (
                  <span className="sv-gate-price"><span className="from">от</span> {fromPrice}</span>
                )}
              </button>
            );
          })}
        </div>

        <button className="sv-hero-scroll" data-cursor data-cursor-label="вниз" onClick={() => onPick(active, true)}>
          <span className="sv-hero-scroll-label">
            подробно о направлении «{(SERVICES_DATA.find((c) => c.id === active) || SERVICES_DATA[0]).name}»
          </span>
          <span className="sv-hero-scroll-arrow">↓</span>
        </button>
      </div>
    </header>
  );
}

// ──────────────────────────────────────────────
// STICKY CATEGORY BAR
// ──────────────────────────────────────────────
function ServicesCatBar({ active, onPick }) {
  return (
    <div className="sv-catbar">
      <div className="shell">
        <div className="sv-catbar-inner">
          {SERVICES_DATA.map((c) => (
            <button
              key={c.id}
              className={'sv-catbar-tab' + (active === c.id ? ' is-active' : '')}
              data-cursor
              onClick={() => onPick(c.id, true)}>
              <span className="t-idx">{c.idx}</span>{c.name}
            </button>
          ))}
        </div>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────
// TARIFF CARD
// ──────────────────────────────────────────────
function TariffCard({ tariff, service }) {
  // навигация внутри карточки — показывается только на мобильном,
  // где sticky-бар направлений скрыт (см. styles-mobile.css)
  const scrollTo = (sel, block) => {
    const el = document.querySelector(sel);
    if (el) el.scrollIntoView({ behavior: 'smooth', block: block });
  };
  return (
    <div className={'tariff tilt fade-up' + (tariff.accent ? ' is-accent' : '')} data-glow>
      <span className="glow"></span>
      <div className="tariff-head">
        <span className="tariff-name">{tariff.name}</span>
        {tariff.tag && <span className="tariff-tag">{tariff.tag}</span>}
      </div>
      <p className="tariff-pitch">{tariff.pitch}</p>

      {tariff.result && (
        <div className="tariff-result">
          <span className="tariff-seg-label">что вы получаете</span>
          <p>{tariff.result}</p>
        </div>
      )}

      <div className="tariff-seg">
        <span className="tariff-seg-label">что входит в работу</span>
        <ul className="tariff-list">
          {tariff.includes.map((it, i) => (
            <li key={i}>
              <span className="tariff-bullet">/</span>
              <span>{it}</span>
            </li>
          ))}
        </ul>
      </div>

      {tariff.scope && (
        <div className="tariff-seg">
          <span className="tariff-seg-label">наша зона ответственности</span>
          <p className="tariff-scope">{tariff.scope}</p>
        </div>
      )}

      {tariff.note && <p className="tariff-note">{tariff.note}</p>}

      <div className="tariff-foot">
        <div className="tariff-price">
          {tariff.from && <span className="from">от</span>}
          <span className="v">{tariff.price}</span>
          <span className="per">/&nbsp;{tariff.per}</span>
        </div>
        <button
          type="button"
          onClick={() => window.openLead({ service: service, source: 'Услуги · тариф «' + tariff.name + '»' })}
          className="tariff-cta magnetic" data-cursor data-cursor-label="обсудить">
          <span>Обсудить</span>
          <span className="arrow">→</span>
        </button>
      </div>

      <div className="tariff-nav" aria-label="Навигация по услугам">
        <button
          type="button"
          className="tariff-nav-btn"
          data-cursor
          onClick={() => scrollTo('#sv-content', 'start')}>
          <span className="tariff-nav-ic">↑</span>
          <span>К тарифам</span>
        </button>
        <button
          type="button"
          className="tariff-nav-btn"
          data-cursor
          onClick={() => scrollTo('.sv-gate', 'center')}>
          <span className="tariff-nav-ic">⟲</span>
          <span>Направления</span>
        </button>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────
// CATEGORY VIEW — направление + тарифы
// ──────────────────────────────────────────────
function CategoryView({ cat }) {
  const rootRef = React.useRef(null);
  useSceneFx(rootRef, cat.id);
  // id раздела услуг → услуга в форме заявки ('extra' = разовые → консультация)
  const svc = cat.id === 'extra' ? 'consult' : cat.id;

  return (
    <div className="sv-cat" id="sv-content" ref={rootRef}>
      <div className="sv-cat-ghost" data-speed="-0.12" aria-hidden="true">{cat.idx}</div>
      <div className="shell">
        <div className="sv-cat-masthead fade-up">
          <div>
            <div className="sv-cat-mast-idx">{cat.idx} · направление</div>
            <h2 className="sv-cat-mast-name">{cat.name}</h2>
            <span className="sv-cat-mast-kicker">{cat.kicker}</span>
          </div>
          <div className="sv-cat-mast-side">
            <p className="sv-cat-mast-desc">{cat.lede}</p>
            <div className="sv-cat-mast-stat">
              {cat.stat.map((s, i) => <span key={i}><b>{s.v}</b> {s.k}</span>)}
            </div>
          </div>
        </div>

        <div className={'svc-cat-grid n-' + cat.tariffs.length}>
          {cat.tariffs.map((t, i) => <TariffCard key={i} tariff={t} service={svc} />)}
        </div>

        <div className="sv-cat-cta fade-up">
          <div>
            <h3>Не уверены, что подойдёт?<br /><span className="accent">Посчитаем под вашу задачу.</span></h3>
            <p>Расскажите про бизнес — предложим направление и формат под цель и бюджет. Отвечаем в течение часа в рабочее время.</p>
          </div>
          <div className="sv-cat-cta-actions">
            <button
              type="button"
              onClick={() => window.openLead({ service: svc, source: 'Услуги · раздел «' + cat.name + '»' })}
              className="btn primary magnetic" data-cursor data-cursor-label="бесплатно">
              <span>Получить расчёт</span>
              <span className="arrow">→</span>
            </button>
            <a href="https://wa.me/79886554717" target="_blank" rel="noopener" className="btn magnetic" data-cursor data-cursor-label="написать">
              <span>Написать в WhatsApp</span>
              <span className="arrow">→</span>
            </a>
          </div>
        </div>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────
// FOOTER (лёгкая локальная версия)
// ──────────────────────────────────────────────
function Footer() {
  return (
    <footer className="foot">
      <div className="shell">
        <div className="row">
          <span><strong>HYPER</strong> · агентство маркетинга · 2026</span>
          <span>Создано на цифрах и нервах</span>
          <span>© 2018—2026</span>
        </div>
      </div>
    </footer>
  );
}

// ──────────────────────────────────────────────
// APP
// ──────────────────────────────────────────────
function ServicesApp() {
  const ids = SERVICES_DATA.map((c) => c.id);
  const initial = (() => {
    const h = (window.location.hash || '').replace('#', '');
    return ids.includes(h) ? h : ids[0];
  })();

  const [active, setActive] = React.useState(initial);

  window.useNavScroll && window.useNavScroll();

  const setHash = (h) => {
    if (window.history && window.history.replaceState) window.history.replaceState(null, '', '#' + h);
  };
  const scrollToContent = () => requestAnimationFrame(() => {
    const el = document.getElementById('sv-content');
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
  });

  const pick = (id, scroll) => {
    setActive(id);
    setHash(id);
    if (scroll) scrollToContent();
  };

  // deep-link при загрузке с #направлением → подвести к контенту
  React.useEffect(() => {
    const h = (window.location.hash || '').replace('#', '');
    if (ids.includes(h)) {
      const t = setTimeout(scrollToContent, 360);
      return () => clearTimeout(t);
    }
  }, []);

  const activeCat = SERVICES_DATA.find((c) => c.id === active) || SERVICES_DATA[0];

  return (
    <>
      <window.ProgressBar />
      <window.CustomCursor />
      <window.Ambient />
      <ServicesNav active={active} onPick={pick} />
      <main className="work-page sv-page">
        <ServicesHero active={active} onPick={pick} />
        <ServicesCatBar active={active} onPick={pick} />
        <CategoryView key={active} cat={activeCat} />
      </main>
      <Footer />
      <window.NavDock home="index.html" />
    </>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<ServicesApp />);
