// Hyper · страница «Кейсы» (work.html)
// Трёхуровневая навигация: разделы → сетка кейсов раздела → отдельный кейс.
// Кейс открывается как самодостаточный «экран»: чёткое начало и конец,
// CTA и кнопка возврата. Листание не перетекает в соседний кейс.
// Использует React.* напрямую (без деструктуризации), чтобы не конфликтовать
// с cursor.jsx, где useEffect/useRef/useState уже объявлены в global-scope.

// ──────────────────────────────────────────────
// ДАННЫЕ КЕЙСОВ
// real — реальные кейсы (SMM). demo — фейковые заглушки для шаблона.
// Чтобы подключить реальное видео: добавьте в кейс video.src = 'assets/xxx.mp4'.
// Кейс может иметь расширенные поля (lead, approach, results, resultNote,
// gallery с подписями) — они рендерятся, если заданы; иначе берутся базовые.
// ──────────────────────────────────────────────
const WORK_DATA = [
  {
    id: 'smm',
    idx: '01',
    name: 'SMM и маркетинг',
    tagline: 'Контент, который продаёт',
    desc: 'Системный контент с экспертным заходом, сетки блогеров и воронки в Direct. Превращаем аккаунт-витрину в канал продаж — и считаем каждый рубль.',
    stat: [{ k: 'кейса', v: '4' }, { k: 'суммарный охват', v: '30М+' }],
    cases: [
      {
        id: 'diox',
        brand: 'DIOX',
        sub: 'витамины и БАДы · собственное производство',
        kicker: 'Производство витаминов и БАДов',
        niche: 'фарма · БАДы · маркетплейсы',
        role: 'SMM полного цикла',
        duration: '12 месяцев',
        platform: 'Instagram Reels',
        cover: 'assets/case-diox-reels-2.jpg',
        railImg: 'assets/case-diox-reels-1.jpg',
        railMetric: '×30 охват',
        featured: true,
        tags: ['Витамины / БАДы', '12 месяцев', 'Instagram', 'Блогеры & паблики', 'Чат-бот воронка', 'Эксперты / врачи'],
        headline: (<><span className="muted">Витамины без доверия — это витрина без покупателей. Как DIOX вырос с </span><span className="accent">1 500</span><span className="muted"> до </span><span className="accent">50 000</span><span className="muted"> просмотров.</span></>),
        // 1 · вступление — коротко про кейс
        lead: 'Российский производитель витаминов и БАДов. За 12 месяцев превратили Instagram-витрину в медиа, которому доверяют, и в канал переходов на маркетплейсы.',

        // ═══ НОВЫЙ LAYOUT (premium) — компактная подача DIOX ═══
        redesign: true,
        heroShot: 'assets/case-diox-reels-2.jpg',
        heroBadge: { v: '×30', l: 'рост охвата' },
        // лента метрик первого экрана (одометр)
        metrics: [
          { v: '×30', l: 'рост охвата Reels' },
          { v: '215 000', l: 'просмотров · лучший Reels' },
          { v: '1 000 000+', l: 'суммарный охват' },
          { v: '2 000+', l: 'переходов на маркетплейс' },
        ],
        // суть на первом экране: задача → решение → результат
        story: {
          task: 'Превратить Instagram-витрину в канал, который ведёт тёплых клиентов на Ozon и Wildberries — без вирусных трендов и развлекалова.',
          idea: 'Доверие в нише здоровья не покупается рекламой — его зарабатывают экспертностью. Путь: сначала польза, потом продукт.',
          result: 'Охваты выросли в 30 раз, Direct ожил. Люди пишут не «сколько стоит», а «подойдёт ли мне» — и заказывают сами.',
        },
        // «как это работало» — 4 интерактивные вкладки со скринами
        pillars: [
          { k: '01', t: 'Эксперты в кадре', d: 'Собрали пул нутрициологов и врачей под каждый продукт — D3 и K2, магний, куркума. Экспертный заход вместо «красивых банок».', shot: 'assets/case-diox-reels-2.jpg', cap: 'Reels с врачами: 30–100 тыс. просмотров на органике.' },
          { k: '02', t: 'Воронка в Direct', d: '«+» под полезным Reels → чат-бот выдаёт гайд с промокодом и ссылкой на маркетплейс. Контент греет, бот доводит до покупки 24/7.', shot: 'assets/case-diox-dm-story.jpg', cap: 'Сторис «как выбрать магний» → вопрос → ссылка на заказ.' },
          { k: '03', t: 'Сетка блогеров', d: 'Блогеры по сегментам ЦА, у каждого свой промокод (PRIZOTDIOX и др.) — точный трекинг канала продаж.', shot: 'assets/case-diox-dm-blogger.jpg', cap: '«По истории Эмины» → промокод → заказ на Ozon.' },
          { k: '04', t: 'Форматы и аналитика', d: 'ПП-рецепты, разборы мифов о витаминах, лайфхаки по питанию. Каждый месяц масштабировали рабочее и отключали слабое.', shot: 'assets/case-diox-reels-1.jpg', cap: 'Нестандартные форматы — органический охват без рекламы.' },
        ],
        // доказательства — компактная сетка скринов (клик → лайтбокс)
        proof: [
          { src: 'assets/case-diox-stat-215k.jpg', cap: '215 114 просмотров, 659 комментариев — лучший Reels.' },
          { src: 'assets/case-diox-stats.png', cap: '975 757 просмотров за 30 дней, 97% — неподписчики.' },
          { src: 'assets/case-diox-dm-request.jpg', cap: 'Пишут сами: «масло тмина, цинк, магний B6».' },
          { src: 'assets/case-diox-dm-thanks.jpg', cap: '«Спасибо большое ❤️» — клиенты возвращаются.' },
        ],

        // 2 · ЗАДАЧА — главный акцент
        taskLead: 'Превратить Instagram из витрины в систему, которая приводит тёплую аудиторию на маркетплейсы — без вирусных трендов и развлекательного контента.',
        taskGoals: [
          'Поднять охваты Reels с 500–1 500 до десятков тысяч на органике.',
          'Заработать доверие к малоизвестному производителю в нише сомнений.',
          'Сделать соцсети источником заказов на Ozon и Wildberries.',
        ],

        // 3 · контекст «с чего начинали»
        context: {
          situation: 'Средний охват Reels — 500–1 500 просмотров. Переходы на маркетплейс — единицы. Обращения в Direct — почти ноль.',
          before: 'Стандартный SMM: красивые фото банок, копирование крупных брендов. Без стратегии и воронки — аудитория смотрела, но не покупала.',
        },

        // 4 · главный инсайт
        insight: 'В нише здоровья доверие не покупается рекламой — его зарабатывают экспертностью и честностью. Поэтому выбрали путь «сначала польза — потом продукт».',

        // 5 · что сделали — система из 6 шагов
        approach: [
          { k: '01', t: 'Комбинированная контент-стратегия', d: 'Экспертный, полезный и продающий контент в одной воронке: каждый формат — на своём этапе пути покупателя.' },
          { k: '02', t: 'База настоящих врачей', d: 'Собрали пул нутрициологов, дерматологов, эндокринологов, косметологов и сняли с ними контент под каждый продукт: D3 и K2, магний, куркума.' },
          { k: '03', t: 'Чат-бот воронка в Direct', d: '«+» под полезным Reels → гайд с промокодом и ссылкой на маркетплейс. Контент греет, бот доводит до покупки 24/7.' },
          { k: '04', t: 'Сетка блогеров с промокодами', d: 'Подключили блогеров по сегментам ЦА, каждому — свой промокод (PRIZOTDIOX и др.) для точного трекинга канала.' },
          { k: '05', t: 'Нестандартные форматы', d: 'ПП-рецепты, лайфхаки по питанию, разборы мифов о витаминах — органический охват без прямой рекламы.' },
          { k: '06', t: 'Ежемесячная аналитика', d: 'Каждый месяц масштабировали то, что работало, и отключали форматы без результата.' },
        ],
        // пруфы рядом с решением
        approachProof: {
          k: 'Как это выглядело',
          shots: [
            { src: 'assets/case-diox-reels-2.jpg', cap: 'Экспертный контент: нутрициолог и врачи в кадре разбирают конкретные витамины.' },
            { src: 'assets/case-diox-dm-story.jpg', cap: 'Воронка: сторис «как выбрать магний» → вопрос «как заказать?» → ссылка на маркетплейс.' },
            { src: 'assets/case-diox-dm-blogger.jpg', cap: 'Сетка блогеров: «по истории Эмины» → промокод PRIZOTDIOX → заказ на Ozon.' },
          ],
        },

        // 6 · результаты за 12 месяцев (6 карточек)
        results: [
          { v: '×30', l: 'рост среднего охвата Reels (1 500 → 40–50 тыс.)' },
          { v: '215 000', l: 'просмотров — лучший Reels' },
          { v: '1 000 000+', l: 'суммарный охват за период' },
          { v: '2 000+', l: 'переходов на маркетплейс' },
          { v: '+489%', l: 'рост кликов на внешнюю ссылку' },
          { v: '0 → ∞', l: 'Direct из мёртвого канала в точку продаж' },
        ],
        // пруфы результатов — по месту
        resultProof: [
          {
            k: 'Видеостатистика отдельных Reels',
            shots: [
              { src: 'assets/case-diox-stat-215k.jpg', cap: '215 114 просмотров, 659 комментариев — лучший Reels.' },
              { src: 'assets/case-diox-stat-166k.jpg', cap: '166 266 просмотров на одном ролике.' },
              { src: 'assets/case-diox-stat-161k.jpg', cap: '161 623 просмотра, 193 пересылки.' },
            ],
          },
          {
            k: 'Охваты и живые заявки',
            shots: [
              { src: 'assets/case-diox-stats.png', cap: '975 757 просмотров за 30 дней, 97% — неподписчики, охват +1 747%.' },
              { src: 'assets/case-diox-dm-request.jpg', cap: 'Люди пишут сами и спрашивают конкретику: «масло тмина, цинк, магний B6».' },
              { src: 'assets/case-diox-dm-thanks.jpg', cap: '«Спасибо большое ❤️» — клиенты благодарят и возвращаются.' },
            ],
          },
        ],

        // 7 · финал
        closing: 'В Direct начали писать не «сколько стоит», а «подойдёт ли мне этот витамин при моей проблеме?» — и переходить к заказу без возражений. Контент убрал главный барьер перед покупкой.',
      },
      {
        id: 'coffee29',
        brand: 'Кофейня 29',
        sub: '@29na26 · Махачкала',
        kicker: 'Кофейня · HoReCa',
        niche: 'HoReCa · кофейня',
        role: 'SMM + influence-маркетинг',
        duration: '12 месяцев',
        platform: 'Instagram Reels',
        cover: 'assets/case-29-feed.jpg',
        railImg: 'assets/case-29-stat-reel.jpg',
        railMetric: '1,38М просмотров',
        featured: true,
        tags: ['Кофейня · HoReCa', '12 месяцев', 'Instagram', 'Юмор-контент', 'Блогер-амбассадор', 'Офлайн-интерактивы'],
        headline: (<><span className="muted">Кофейня без медийности — это просто фасад у дороги. Как мы вывели «29» на </span><span className="accent">1,38 млн</span><span className="muted"> просмотров и сделали узнаваемой.</span></>),
        lead: 'Кофейня «29» в Махачкале с ярким фасадом, но почти нулевой медийностью. За год собрали контент-машину на юморе и вывели её на миллионы органических просмотров — без рекламного бюджета.',

        // ═══ premium-layout ═══
        redesign: true,
        heroShot: 'assets/case-29-feed.jpg',
        heroBadge: { v: '1,38М', l: 'просмотров' },
        metrics: [
          { v: '1 382 186', l: 'просмотров за период' },
          { v: '599 158', l: 'просмотров за месяц (пик)' },
          { v: '98%', l: 'неподписчики на топ-Reels' },
          { v: '220 874', l: 'просмотров · вирусный Reels' },
        ],
        story: {
          task: 'Поднять узнаваемость кофейни в перегретой нише Дагестана — взять широким органическим охватом, а не точечным локальным SMM.',
          idea: 'Кофеен много, все рвутся за вниманием. Мы пошли в медийность: авторский юмор + известное лицо + продукт всегда в кадре — так контент сам становится трендом.',
          result: 'Миллионы органических просмотров, 85–98% — неподписчики. Кофейню начали узнавать офлайн, а её тренды повторяли другие заведения.',
        },
        pillars: [
          { k: '01', t: 'Блогер и авторский юмор', d: 'Привлекли контент-мейкера с узнаваемым лицом из мира юмора. Придумывали свои тренды под кофейню — за ними потом повторяли другие.', shot: 'assets/case-29-blogger.jpg', cap: '«Под какой кофе» — авторский юмор-формат от лица блогера.' },
          { k: '02', t: 'Виральные форматы', d: 'Юмор + новостная подача давали высокий охват без бюджета. Форматы расходились далеко за пределы аккаунта.', shot: 'assets/case-29-humor.jpg', cap: '«В кофейню 29 на полном ходу влетела машина 😱» — виральный заход.' },
          { k: '03', t: 'Продукт всегда в кадре', d: 'Кофе, новинки, дегустации, еда собственного производства. Трафик с виральных роликов сразу видел продукт — и хотел дойти офлайн.', shot: 'assets/case-29-coffee.jpg', cap: 'Продукт в каждом ролике — связка медийности с продажами.' },
          { k: '04', t: 'Офлайн-интерактивы', d: 'Поставили спортивный таймер: останови ровно на 5 секундах — кофе и десерт в подарок. Снимали попытки гостей в Reels — за ними следили тысячи.', shot: 'assets/case-29-people.jpg', cap: 'Офлайн-механики превращались в медийные ролики.' },
        ],
        proof: [
          { src: 'assets/case-29-stat-138m.jpg', cap: '1 382 186 просмотров за период, 79,7% — неподписчики.' },
          { src: 'assets/case-29-stat-600k.jpg', cap: '599 158 просмотров за месяц, 85% — неподписчики.' },
          { src: 'assets/case-29-stat-reel.jpg', cap: 'Вирусный Reels: 220 874 просмотра, 98% — неподписчики, 2,2 тыс. комментариев.' },
          { src: 'assets/case-29-stat-reach.jpg', cap: '132 189 охваченных аккаунтов, 98% — неподписчики.' },
        ],
        closing: 'Кофейня «29» из «просто яркого фасада у дороги» стала медийно узнаваемой: её тренды повторяют конкуренты, а гости приходят, потому что «видели в Instagram». И всё это — на органике, без рекламного бюджета.',
      },
      {
        id: 'pavlonia',
        brand: 'Павлония',
        sub: 'сеть семейных кафе · 8+ точек',
        kicker: 'Сеть семейных кафе · HoReCa',
        niche: 'HoReCa · общепит',
        role: 'SMM + influence-маркетинг',
        duration: '6 месяцев',
        platform: 'Instagram Reels',
        cover: 'assets/pav-grid-family.jpg',
        railImg: 'assets/pav-grid-millions.jpg',
        railMetric: '13,1М просмотров',
        featured: true,
        tags: ['HoReCa · общепит', '6 месяцев', 'Instagram', 'Скетчи + продающий', 'Блогеры & паблики', '8+ точек'],
        headline: (<><span className="muted">Сеть кафе без системы — в контент-машину на </span><span className="accent">миллионы</span><span className="muted"> охватов. </span><span className="accent">97,7%</span><span className="muted"> органики, без рекламного бюджета.</span></>),
        lead: 'Павлония — сеть семейных кафе с акцентом на блюда на углях. Собрали контентную машину из двух форматов и вывели её на миллионы органических просмотров в месяц.',

        // ═══ premium-layout ═══
        redesign: true,
        heroShot: 'assets/pav-grid-family.jpg',
        heroBadge: { v: '13,1М', l: 'просмотров' },
        metrics: [
          { v: '13,1 млн', l: 'просмотров · лучший Reels' },
          { v: '17,4 млн', l: 'просмотров за месяц (пик)' },
          { v: '97,7%', l: 'органический охват, 0% рекламы' },
          { v: '275 000', l: 'пересылок одного ролика' },
        ],
        story: {
          task: 'Закрыть весь цикл одним агентством — от поиска героев и съёмок до продвижения — и приводить через Instagram переходы на сайт и в приложение.',
          idea: 'Продаёт не один формат, а связка: скетчи «муж и жена» дают охваты, продающие ролики с офферами — заказы. Большинство делают упор во что-то одно.',
          result: 'Скетчи стали узнаваемыми и расходились далеко за пределы аккаунта, а продающие ролики вели на сайт и в приложение. Бренд закрепился как семейный — без слива бюджета в рекламу.',
        },
        pillars: [
          { k: '01', t: 'Два формата в связке', d: 'Семейные скетчи «муж и жена» на охваты + продающий контент с офферами на заказы. Промокоды и акции иногда зашивали прямо в скетчи.', shot: 'assets/pav-grid-millions.jpg', cap: 'Продающий контент с блюдами на углях — ролики на 12,4 и 8,9 млн.' },
          { k: '02', t: 'Скетчи, которые уходят в вирус', d: 'Постановочные семейные сюжеты с отдельными героями под юмор. Один скетч репостнул крупный паблик — 189 тыс. лайков на репосте.', shot: 'assets/pav-sketch-repost.jpg', cap: 'Скетч «муж и жена» ушёл в вирус через крупный паблик.' },
          { k: '03', t: 'Блогеры-амбассадоры', d: 'Пул микроблогеров на обзоры курицы на углях, пиццы и роллов плюс реклама под запуск акций. Коллаборации и уличные опросы за еду.', shot: 'assets/pav-grid-family.jpg', cap: 'Лента: семейные сюжеты и продукт в каждом ролике.' },
          { k: '04', t: 'Замеры и масштаб', d: 'Замеряли просмотры и переходы, добавляли рабочие форматы, отключали слабые — стратегия усиливалась каждый месяц.', shot: 'assets/pav-reel-chicken.jpg', cap: 'Курица на углях: 13,1 млн просмотров, 275 тыс. пересылок.' },
        ],
        proof: [
          { src: 'assets/pav-reel-chicken.jpg', cap: 'Курица на углях: 13,1 млн просмотров, 402 тыс. лайков.' },
          { src: 'assets/pav-reel-rolls.jpg', cap: 'Роллы «Павлония»: 9,18 млн просмотров, 74 тыс. пересылок.' },
          { src: 'assets/pav-stat-dec.jpg', cap: '17,4 млн просмотров за месяц, охват +1921%.' },
          { src: 'assets/pav-stat-interactions.jpg', cap: '234 396 взаимодействий за месяц, 97% — неподписчики.' },
        ],

        taskLead: 'Закрыть весь цикл одним агентством — от поиска героев и съёмок до продвижения — и приводить через Instagram переходы на сайт и в приложение.',
        taskGoals: [
          'Приводить из Instagram переходы на сайт и в приложение.',
          'Растить органические охваты семейной аудитории.',
          'Закрепить позиционирование семейного заведения.',
        ],

        context: {
          situation: 'Сеть из 8+ точек в Махачкале и Каспийске: курица на углях, пицца, роллы. Охваты нестабильные, заказы из соцсетей непрогнозируемы.',
          before: 'Пробовали блогеров, юмор, разные форматы и «главное лицо» — но без системы, результат был случайным.',
        },

        insight: 'Продаёт не один формат, а связка: скетчи «муж и жена» дают охваты, продающие ролики с офферами — заказы. Большинство делают упор во что-то одно.',

        approach: [
          { k: '01', t: 'Два формата в связке', d: 'Соединили семейные скетчи «муж и жена» с продающим контентом и офферами. Промокоды и акции иногда зашивали прямо в скетчи.' },
          { k: '02', t: 'Стратегия и отдельные герои', d: 'Прописали форматы под цели: одни лица — для продающих роликов, другие — для юмористических скетчей.' },
          { k: '03', t: 'Продакшн разной сложности', d: 'От постановочных скетчей на съёмной квартире до коротких роликов в заведении — масштабировали то, что заходило.' },
          { k: '04', t: 'База блогеров-амбассадоров', d: 'Собрали пул микроблогеров на обзоры курицы на углях, пиццы и роллов плюс реклама под запуск акций.' },
          { k: '05', t: 'Коллаборации и репортажи', d: 'Обмен аудиторией с партнёрами в совместных постах и уличные опросы с триггерными вопросами — за участие угощали едой.' },
          { k: '06', t: 'Замеры и корректировка', d: 'Замеряли просмотры и переходы, добавляли рабочие форматы, отключали слабые — стратегия усиливалась каждый месяц.' },
        ],
        approachProof: {
          k: 'Что выходило в ленте',
          shots: [
            { src: 'assets/pav-grid-family.jpg', cap: 'Лента: семейные сюжеты и продукт «Павлонии» в каждом ролике.' },
            { src: 'assets/pav-sketch-repost.jpg', cap: 'Скетч «муж и жена» ушёл в вирус — его репостнул крупный паблик (189 тыс. лайков на репосте).' },
            { src: 'assets/pav-grid-millions.jpg', cap: 'Продающий контент с блюдами на углях — ролики на 12,4 и 8,9 млн просмотров.' },
          ],
        },

        results: [
          { v: '13,1 млн', l: 'просмотров — лучший Reels «курица на углях»' },
          { v: '17,4 млн', l: 'просмотров за месяц (пик)' },
          { v: '+1921%', l: 'рост охваченных аккаунтов' },
          { v: '97,7%', l: 'органический охват, 0% рекламы' },
          { v: '275 000', l: 'пересылок одного ролика' },
          { v: '6,99 млн', l: 'охваченных аккаунтов за месяц' },
        ],
        resultProof: [
          {
            k: 'Флагманские Reels',
            shots: [
              { src: 'assets/pav-reel-chicken.jpg', cap: 'Курица на углях: 13,1 млн просмотров, 402 тыс. лайков, 275 тыс. пересылок.' },
              { src: 'assets/pav-reel-rolls.jpg', cap: 'Роллы «Павлония»: 9,18 млн просмотров, 74 тыс. пересылок.' },
            ],
          },
          {
            k: 'Охваты за месяц',
            shots: [
              { src: 'assets/pav-stat-dec.jpg', cap: '17,4 млн просмотров за месяц, охват +1921%, 0% от рекламы.' },
              { src: 'assets/pav-stat-jan.jpg', cap: '5,5 млн просмотров за следующий месяц — стабильно высокая база.' },
              { src: 'assets/pav-stat-interactions.jpg', cap: '234 396 взаимодействий за месяц, 97% — на неподписчиках.' },
            ],
          },
        ],

        closing: 'Скетчи стали узнаваемыми и расходились далеко за пределы аккаунта, а продающие ролики вели на сайт и в приложение. Бренд закрепился как семейный и растёт без слива бюджета в рекламу.',
      },
      {
        id: 'shrm',
        brand: 'ШРМ',
        sub: 'ЖК «Пражская» · застройщик',
        kicker: 'ЖК «Пражская» · застройщик',
        niche: 'недвижимость · застройщик',
        role: 'SMM + личный бренд',
        duration: '7 месяцев',
        platform: 'Instagram Reels',
        cover: 'assets/shrm-content-grid.jpg',
        railImg: 'assets/shrm-reel-car.jpg',
        railMetric: '0 → 300 лидов',
        featured: true,
        tags: ['Недвижимость', '7 месяцев', 'Instagram', 'Личный бренд', 'Блогеры & паблики', 'Бюджет до 50 000 ₽'],
        headline: (<><span className="muted">С </span><span className="accent">нуля</span><span className="muted"> до </span><span className="accent">300</span><span className="muted"> целевых лидов в месяц. Как застройщик без узнаваемости включил поток заявок на бюджете до 50 000 ₽.</span></>),
        lead: 'ШРМ — молодой застройщик из Махачкалы с нулевой узнаваемостью и нулём лидов из Instagram. За 7 месяцев мы построили продвижение вокруг личности собственника Рустама и вывели аккаунт на 300 целевых обращений в месяц.',

        // ═══ premium-layout ═══
        redesign: true,
        heroShot: 'assets/shrm-content-grid.jpg',
        heroBadge: { v: '0 → 300', l: 'лидов в месяц' },
        metrics: [
          { v: '0 → 300', l: 'целевых лидов в месяц (было 20–30)' },
          { v: '100 000', l: 'охватов в месяц' },
          { v: '7 141', l: 'комментарий на одном ролике' },
          { v: 'до 50 000 ₽', l: 'рекламный бюджет в месяц' },
        ],
        story: {
          task: 'Запустить поток целевых заявок на квартиры клубного дома при бюджете до 50 000 ₽ и сделать застройщика заметным в перегретой нише.',
          idea: 'Люди покупают квартиры не у компаний, а у людей. Молодому застройщику нужен не брендинг, а лицо — мы сделали из собственника Рустама медиаперсону.',
          result: 'Теперь в Direct спрашивают не «что за компания?», а «когда созвон с Рустамом?». Личный бренд собственника стал главным активом продаж.',
        },
        pillars: [
          { k: '01', t: 'Личный бренд вместо корпоратива', d: 'Перевели весь контент с обезличенной компании на личность собственника — личный бренд с элементами коммерции.', shot: 'assets/shrm-content-grid.jpg', cap: 'Лента: личный бренд Рустама + офферы и стройка.' },
          { k: '02', t: 'Лайфстайл со стройки', d: 'Обходы объекта, аудиты, переговоры с подрядчиками, мнения «из машины» от первого лица. Прозрачная стройка строит доверие.', shot: 'assets/shrm-build.jpg', cap: 'Прозрачный процесс заливки этажа = доверие покупателей.' },
          { k: '03', t: 'Триггерные хуки от первого лица', d: 'Ролики с вопросами-хуками голосом собственника («оформлять квартиру на мужа?») — один собрал больше 7 000 комментариев.', shot: 'assets/shrm-reel-car.jpg', cap: 'Вопрос «из машины»: 5 717 лайков и 7 141 комментарий.' },
          { k: '04', t: 'Офферы как личные жесты', d: 'Не «скидка от компании», а «я лично дарю сертификат до 1 000 000 ₽», техника, рассрочка, сертификаты к праздникам. Позиционирование «не для всех».', shot: 'assets/shrm-offers.jpg', cap: 'Офферы-дефицит: «инвестируйте» — 281 тыс. просмотров.' },
        ],
        proof: [
          { src: 'assets/shrm-offers.jpg', cap: 'Офферы-дефицит: 281 тыс. просмотров, скидка до 500 000 ₽.' },
          { src: 'assets/shrm-reels-grid.jpg', cap: 'Ролики стабильно набирают десятки тысяч: 50,4 и 31,3 тыс.' },
          { src: 'assets/shrm-reel-car.jpg', cap: 'Вопрос «из машины»: 7 141 комментарий на одном ролике.' },
          { src: 'assets/shrm-profile.jpg', cap: 'Профиль ШРМ: позиционирование «Дом не для всех».' },
        ],

        taskLead: 'Запустить поток целевых заявок на квартиры клубного дома при бюджете до 50 000 ₽ и сделать застройщика заметным в перегретой нише.',
        taskGoals: [
          'Выйти с нуля на стабильный поток целевых лидов из Instagram.',
          'Дать узнаваемость застройщику без бренда и истории.',
          'Удержать стоимость в рамках до 50 000 ₽/мес.',
        ],

        context: {
          situation: 'Клубный дом ЖК «Пражская»: 12 этажей, один подъезд, 66 квартир. Лидов из Instagram — 0, в первые месяцы — 20–30 обращений.',
          before: 'Аккаунт вели как корпоративную страницу: контент про «надёжность и качество» от лица компании. Покупателей он не приводил.',
        },

        insight: 'Люди покупают квартиры не у компаний, а у людей. Молодому застройщику нужен не брендинг, а лицо — мы сделали из собственника Рустама медиаперсону.',

        approach: [
          { k: '01', t: 'Личный бренд вместо корпоратива', d: 'Перевели весь контент с обезличенной компании на личность собственника — личный бренд с элементами коммерции.' },
          { k: '02', t: 'Лайфстайл со стройки', d: 'Обходы объекта, аудиты, переговоры с подрядчиками, мнения «из машины» от первого лица. Прозрачная стройка строит доверие.' },
          { k: '03', t: 'Офферы как личные жесты', d: 'Не «скидка от компании», а «я лично дарю сертификат до 1 000 000 ₽», техника на 100 000 ₽, рассрочка, сертификаты к Курбан- и Ураза-Байрам.' },
          { k: '04', t: 'Позиционирование «не для всех»', d: 'Упаковали особенности дома в эксклюзивность: «клубный дом — не для всех», «посуточных не будет», «не продаём перекупщикам».' },
          { k: '05', t: 'Триггерные хуки от первого лица', d: 'Ролики с вопросами-хуками голосом собственника («оформлять квартиру на мужа?») — один собрал больше 7 000 комментариев.' },
          { k: '06', t: 'Конкурсы и посевы', d: 'Путёвки на Умру, iPhone, MacBook для роста аудитории. Паблики и блогеры как площадки для репостов, без «фейк-покупок».' },
        ],
        approachProof: {
          k: 'Как это выглядело',
          shots: [
            { src: 'assets/shrm-content-grid.jpg', cap: 'Лента: личный бренд Рустама + офферы — мат. капитал, «только 3 квартиры», стройка.' },
            { src: 'assets/shrm-reel-car.jpg', cap: 'Вопрос «из машины» от первого лица: 5 717 лайков и 7 141 комментарий на одном ролике.' },
            { src: 'assets/shrm-build.jpg', cap: 'Лайфстайл со стройки: прозрачный процесс заливки этажа = доверие покупателей.' },
          ],
        },

        results: [
          { v: '0 → 300', l: 'целевых лидов в месяц (было 20–30)' },
          { v: '100 000', l: 'охватов в месяц' },
          { v: 'до 50 000 ₽', l: 'рекламный бюджет в месяц' },
          { v: '7 141', l: 'комментарий на одном ролике' },
          { v: '+356%', l: 'переходов по внешней ссылке за месяц' },
          { v: '281 000', l: 'просмотров на лучшем оффере' },
        ],
        resultProof: [
          {
            k: 'Охваты и вовлечение',
            shots: [
              { src: 'assets/shrm-offers.jpg', cap: 'Офферы-дефицит: «инвестируйте» — 281 тыс. просмотров, скидка до 500 000 ₽.' },
              { src: 'assets/shrm-reels-grid.jpg', cap: 'Ролики стабильно набирают десятки тысяч: 50,4 тыс., 31,3 тыс. просмотров.' },
              { src: 'assets/shrm-profile.jpg', cap: 'Профиль ШРМ: 5 106 подписчиков, позиционирование «Дом не для всех».' },
            ],
          },
        ],

        closing: 'Теперь в Direct спрашивают не «что за компания?», а «когда созвон с Рустамом?». Личный бренд собственника стал главным активом продаж: люди приходят «к Рустаму», а не «в компанию».',
      },
    ],
  },
  {
    id: 'production',
    idx: '02',
    name: 'Продакшн',
    wip: true, // ← раздел «на ремонте»: убери эту строку, чтобы вернуть кейсы
    tagline: 'Видео, которое смотрят до конца',
    desc: 'Рекламные ролики, бренд-фильмы и Reels-продакшн. От сценария и раскадровки до монтажа и звука. Снимаем так, чтобы досматривали и пересылали.',
    stat: [{ k: 'кейса', v: '3' }, { k: 'формат', v: 'видео' }],
    cases: [
      {
        id: 'prod-fuel',
        brand: 'FUEL 1',
        sub: 'сеть автомоек',
        niche: 'локальный бизнес · промо',
        role: 'рекламный продакшн',
        duration: '8 дней',
        demo: true,
        cover: 'assets/case-shrm-reel.jpg',
        railImg: 'assets/case-shrm-reel.jpg',
        railMetric: '2,3М просмотров',
        video: { poster: 'assets/case-shrm-reel.jpg', title: 'FUEL 1 · рекламный ролик' },
        headline: (<><span className="muted">Рекламный ролик, который набрал </span><span className="accent">2,3 млн</span><span className="muted"> просмотров за две недели.</span></>),
        stats: [
          { v: <>2,3<em>М</em></>, l: 'просмотров за 14 дней' },
          { v: <>4</>, l: 'ролика в серии' },
          { v: <>8</>, l: 'дней на продакшн' },
        ],
        problem: 'Сеть автомоек снимала ролики «как у всех»: машина, пена, логотип. Видео не выделялись и быстро забывались, реклама не отбивалась.',
        task: 'Сделать серию роликов с характером, которые запоминаются и работают и в рекламе, и в органике.',
        solution: [
          'Сценарий с юмором и узнаваемым героем',
          'Динамичный монтаж под вертикальный формат',
          'Хук в первые 2 секунды — против пролистывания',
          'Серийность для накопления узнаваемости',
        ],
        outcome: 'Ролики разошлись по органике и стали лицом бренда в городе. Стоимость показа упала, а узнаваемость выросла.',
      },
      {
        id: 'prod-versus',
        brand: 'VERSUS',
        sub: 'одежда · ритейл',
        niche: 'fashion · бренд-фильм',
        role: 'бренд-фильм',
        duration: '3 недели',
        demo: true,
        cover: 'assets/case-pavlonia-sketch.jpg',
        railImg: 'assets/case-pavlonia-sketch.jpg',
        railMetric: 'бренд-фильм',
        video: { poster: 'assets/case-pavlonia-sketch.jpg', title: 'VERSUS · бренд-фильм' },
        headline: (<><span className="muted">Бренд-фильм, который задал </span><span className="accent">визуальный код</span><span className="muted"> марки на год вперёд.</span></>),
        stats: [
          { v: <>1</>, l: 'съёмочный день' },
          { v: <>×4</>, l: 'рост вовлечённости' },
          { v: <>12</>, l: 'нарезок для соцсетей' },
        ],
        problem: 'У марки одежды был товар, но не было образа: контент выглядел как фотографии с маркетплейса, бренд не считывался.',
        task: 'Снять бренд-фильм, который задаёт визуальный язык и работает на образ, а нарезки — на охваты.',
        solution: [
          'Мудборд и визуальная концепция под характер марки',
          'Один съёмочный день — 12 единиц контента',
          'Цветокор и звук под настроение бренда',
          'Раскадровка под вертикаль и горизонталь сразу',
        ],
        outcome: 'Бренд-фильм стал точкой отсчёта стиля: по нему собирается весь дальнейший контент. Вовлечённость выросла кратно.',
      },
      {
        id: 'prod-elektro',
        brand: 'Электробыт',
        sub: 'бытовая техника',
        niche: 'ритейл · продуктовое видео',
        role: 'продуктовый продакшн',
        duration: '10 дней',
        demo: true,
        cover: 'assets/case-diox-reels-2.jpg',
        railImg: 'assets/case-diox-reels-2.jpg',
        railMetric: 'CPV −38%',
        video: { poster: 'assets/case-diox-reels-2.jpg', title: 'Электробыт · продуктовая серия' },
        headline: (<><span className="muted">Продуктовая серия, которая снизила стоимость просмотра на </span><span className="accent">38%</span><span className="muted">.</span></>),
        stats: [
          { v: <>−38<em>%</em></>, l: 'стоимость просмотра' },
          { v: <>9</>, l: 'роликов в серии' },
          { v: <>+62<em>%</em></>, l: 'досматриваемость' },
        ],
        problem: 'Карточки техники сопровождались статичными фото — конверсия в клик и заказ буксовала, ролики конкурентов выигрывали внимание.',
        task: 'Собрать продуктовые ролики, которые объясняют пользу за 15 секунд и держат внимание до конца.',
        solution: [
          'Сценарии «проблема → решение» под каждый товар',
          'Чистый предметный свет и акцент на деталях',
          'Динамичный монтаж с подписями-выгодами',
          'Версии под рекламу и под органику',
        ],
        outcome: 'Серия снизила стоимость просмотра и подняла досматриваемость. Видео встали в карточки и в рекламные кампании.',
      },
    ],
  },
  {
    id: 'design',
    idx: '03',
    name: 'Дизайн',
    wip: true, // ← раздел «на ремонте»: убери эту строку, чтобы вернуть кейсы
    tagline: 'Айдентика, которую запоминают',
    desc: 'Фирстиль, упаковка, визуальные системы для соцсетей и маркетплейсов. Дизайн, который не просто красивый, а продаёт и отличает от конкурентов.',
    stat: [{ k: 'кейса', v: '3' }, { k: 'фокус', v: 'айдентика' }],
    cases: [
      {
        id: 'des-homeplaza',
        brand: 'Home Plaza',
        sub: 'мебель · интерьер',
        niche: 'ребрендинг',
        role: 'фирменный стиль',
        duration: '4 недели',
        demo: true,
        cover: 'assets/clients/homeplaza.png',
        railImg: 'assets/clients/homeplaza.png',
        railMetric: 'ребрендинг',
        headline: (<><span className="muted">Ребрендинг, после которого узнаваемость в ленте выросла в </span><span className="accent">3 раза</span><span className="muted">.</span></>),
        stats: [
          { v: <>×3</>, l: 'узнаваемость в ленте' },
          { v: <>40<em>+</em></>, l: 'шаблонов в системе' },
          { v: <>1</>, l: 'визуальный язык' },
        ],
        problem: 'Бренд выглядел разнородно: каждый пост в своём стиле, логотип терялся, аудитория не узнавала компанию.',
        task: 'Собрать единую визуальную систему, которая работает в соцсетях, на сайте и в офлайне.',
        solution: [
          'Логотип и фирменная палитра',
          'Сетка и шаблоны под соцсети',
          'Гайдлайн для команды контента',
          'Система иконок и типографики',
        ],
        outcome: 'Бренд стал узнаваемым с первого касания. Контент собирается быстрее — по готовой системе.',
      },
      {
        id: 'des-glaz',
        brand: 'Глаз Алмаз',
        sub: 'салон оптики',
        niche: 'визуальная концепция',
        role: 'дизайн соцсетей',
        duration: '3 недели',
        demo: true,
        cover: 'assets/clients/glaz.png',
        railImg: 'assets/clients/glaz.png',
        railMetric: 'визуал-концепт',
        headline: (<><span className="muted">Визуальная концепция, которая подняла </span><span className="accent">сохранения</span><span className="muted"> постов в 2,4 раза.</span></>),
        stats: [
          { v: <>×2,4</>, l: 'рост сохранений' },
          { v: <>30</>, l: 'шаблонов карточек' },
          { v: <>+18<em>%</em></>, l: 'вовлечённость' },
        ],
        problem: 'Оптика конкурировала ценой, а контент выглядел как у всех. Визуал не передавал уровень салона.',
        task: 'Создать визуальный код, который выделяет салон и поднимает вовлечённость.',
        solution: [
          'Концепт и палитра под премиальное позиционирование',
          'Шаблоны под акции и новинки',
          'Единый стиль фото и обработки',
          'Карточки-инструкции по подбору',
        ],
        outcome: 'Контент стал узнаваемым и «сохраняемым». Салон отстроился от ценовых конкурентов.',
      },
      {
        id: 'des-manymo',
        brand: 'ManyMo',
        sub: 'товары для дома',
        niche: 'маркетплейсы · упаковка',
        role: 'дизайн карточек',
        duration: '2 недели',
        demo: true,
        cover: 'assets/clients/manymo.png',
        railImg: 'assets/clients/manymo.png',
        railMetric: 'CTR +27%',
        headline: (<><span className="muted">Переупаковали карточки — </span><span className="accent">+27%</span><span className="muted"> к кликабельности на маркетплейсе.</span></>),
        stats: [
          { v: <>+27<em>%</em></>, l: 'CTR карточек' },
          { v: <>+14<em>%</em></>, l: 'конверсия в заказ' },
          { v: <>50<em>+</em></>, l: 'SKU переоформлено' },
        ],
        problem: 'Карточки терялись в выдаче: слабое главное фото, нет считываемых выгод, низкий CTR.',
        task: 'Переупаковать карточки так, чтобы они выигрывали клик в выдаче и вели к заказу.',
        solution: [
          'Сильное главное фото с выгодой',
          'Инфографика по свойствам товара',
          'Единый стиль линейки',
          'A/B-проверка вариантов обложки',
        ],
        outcome: 'CTR и конверсия выросли без изменения цены — за счёт упаковки. Линейка стала выглядеть как бренд.',
      },
    ],
  },
  {
    id: 'personal',
    idx: '04',
    name: 'Личный бренд',
    tagline: 'Эксперт, которому доверяют',
    desc: 'Упаковка экспертов и собственников: позиционирование, контент-стратегия, съёмка. Делаем так, чтобы за человеком шли клиенты, а не только подписчики.',
    stat: [{ k: 'кейс', v: '1' }, { k: 'фокус', v: 'эксперты' }],
    cases: [
      {
        id: 'allergo',
        brand: 'Абдулкарим',
        sub: '@allergo.doc · аллерголог-гомеопат',
        kicker: 'Личный бренд врача · спорная ниша',
        niche: 'медицина · аллергология · гомеопатия',
        role: 'личный бренд эксперта',
        duration: '6 месяцев',
        platform: 'Instagram Reels',
        cover: 'assets/case-ak-grid.jpg',
        railImg: 'assets/case-ak-homeo.jpg',
        railMetric: '300 → 17,4K',
        featured: true,
        tags: ['Медицина', '6 месяцев', 'Instagram', 'Личный бренд', 'Спорная ниша', 'Reels-стратегия'],
        headline: (<><span className="muted">Спорная ниша и недоверие аудитории — и из </span><span className="accent">300</span><span className="muted"> подписчиков до </span><span className="accent">1 000 000</span><span className="muted"> просмотров. На том самом недоверии, что мешало.</span></>),
        lead: 'Абдулкарим — аллерголог-гомеопат из Дагестана со своей клиникой «Центр доктора К. Ная». Личный аккаунт «про жизнь» (300 подписчиков, картинка вместо лица) за 6 месяцев превратили в экспертный блог, который дотягивает до 1 000 000 просмотров и приводит пациентов в клинику.',

        // ═══ premium-layout ═══
        redesign: true,
        heroShot: 'assets/case-ak-grid.jpg',
        heroBadge: { v: '×58', l: 'рост аудитории' },
        metrics: [
          { v: '300 → 17 400', l: 'подписчиков за 6 месяцев' },
          { v: '254 000', l: 'просмотров · топовый Reels' },
          { v: '1 000 000+', l: 'суммарный охват на Reels' },
          { v: '0 → поток', l: 'записей в клинику из блога' },
        ],
        story: {
          task: 'Сделать Абдулкарима самым узнаваемым аллергологом-гомеопатом Дагестана и через личный блог привести пациентов в клинику «Центр доктора К. Ная».',
          idea: 'Спорность направления — не баг, а топливо. Недоверие к гомеопатии мы не обходили, а превращали в повод смотреть: «врач, который говорит прямо то, о чём другие молчат».',
          result: 'Из аккаунта «про жизнь» — экспертный блог на 17,4 тыс. подписчиков. Direct ожил, пациенты идут «на врача», а узнавать стали даже офлайн.',
        },
        pillars: [
          { k: '01', t: 'Reels как главный инструмент', d: 'Системный экспертный контент, встроенный в рабочий день врача: офис, клиника, студия. Никаких сложных продакшнов — съёмка не выжигает время эксперта.', shot: 'assets/case-ak-allergy.jpg', cap: 'Экспертные разборы аллергии: десятки тысяч просмотров на органике.' },
          { k: '02', t: 'Спорность как топливо', d: 'Острые профессиональные позиции (гомеопатия, Манту, энергетики) вызывают реакцию — а реакция кормит охваты. Триггер → охват → авторитет → запись.', shot: 'assets/case-ak-energy.jpg', cap: '«Призываю всех» — триггерная позиция по энергетикам: 68 438 просмотров.' },
          { k: '03', t: 'Три типа контента', d: 'Полезные экспертные темы, кейсы лечения (как вылечили ребёнка) и триггерные профессиональные позиции. Эксперт даёт смысл — мы упаковку: хук → польза → вывод.', shot: 'assets/case-ak-likbez.jpg', cap: '«3 аллергии, которых не существует» — ликбез-формат на охват.' },
          { k: '04', t: 'Система и дисциплина', d: 'Главное операционное решение — график. Съёмки, регулярная выкладка, дисциплина выпуска. Без системы личный бренд эксперта не живёт — мы её выстроили и держали.', shot: 'assets/case-ak-grid2.jpg', cap: 'Регулярная выкладка: лента из брендированного экспертного контента.' },
        ],
        proof: [
          { src: 'assets/case-ak-profile.jpg', cap: 'Профиль @allergo.doc: 17,4 тыс. подписчиков и 88 публикаций (старт — 300).' },
          { src: 'assets/case-ak-grid.jpg', cap: 'Виральные ролики: 254, 142, 117 тыс. просмотров на спорных темах.' },
          { src: 'assets/case-ak-energy.jpg', cap: 'Триггерная позиция по энергетикам: 68 438 просмотров, 1 456 взаимодействий.' },
          { src: 'assets/case-ak-homeo.jpg', cap: '«Гомеопатия работает! И точка!» — 57 564 просмотра в нише, которой не доверяют.' },
        ],

        taskLead: 'Стать самым узнаваемым аллергологом-гомеопатом Дагестана и через личный блог популяризировать и направление, и клинику «Центр доктора К. Ная».',
        taskGoals: [
          'Снять недоверие к спорному направлению и превратить его в охваты.',
          'Вырастить аудиторию с базы 300 подписчиков в экспертный блог.',
          'Довести подписчика до записи в клинику, а не только до лайка.',
        ],

        context: {
          situation: 'Личный аккаунт «про жизнь»: 300 подписчиков, вместо лица — картинка на аватарке, пара публикаций. Системы — ноль.',
          before: 'Главная проблема глубже цифр: ниша спорная. Аудитория не понимает гомеопатию, боится слухов и относится к направлению с недоверием. Любой контент стартовал не с нуля, а с минуса.',
        },

        insight: 'Очевидный путь — смягчать и «продавать гомеопатию мягко». Мы сделали наоборот: спорность направления — это не баг, а топливо. Недоверие мы превращали в повод смотреть и слушать.',

        approach: [
          { k: '01', t: 'Reels + экспертный Instagram', d: 'Сделали Reels главным инструментом, а контент выстроили так, чтобы не выжигать время врача: съёмка встроена в рабочий день.' },
          { k: '02', t: 'Производство в доступных локациях', d: 'Офис, клиника, студия. Никаких сложных продакшнов — простая, но регулярная съёмка вместо разовых дорогих съёмочных дней.' },
          { k: '03', t: 'Темы — от эксперта', d: 'Собирали темы из аллергологии и гомеопатии, приносили врачу — он выбирал, добавлял своё и писал тезисы по своей теме, которую знает лучше.' },
          { k: '04', t: 'Структура под охват', d: 'Дорабатывали ролики по схеме хук → польза → вывод. Эксперт даёт смысл, мы — упаковку, которая удерживает и расходится.' },
          { k: '05', t: 'Три линии контента', d: 'Полезные экспертные темы, кейсы лечения и триггерные профессиональные позиции — баланс пользы, доверия и охвата.' },
          { k: '06', t: 'Система и график', d: 'Принуждали эксперта к графику: съёмки, регулярная выкладка, дисциплина выпуска. Это и есть то, без чего личный бренд врача не живёт.' },
        ],
        approachProof: {
          k: 'Как это выглядело',
          shots: [
            { src: 'assets/case-ak-grid.jpg', cap: 'Лента виральных роликов: эксперт в кадре на спорных и полезных темах.' },
            { src: 'assets/case-ak-likbez.jpg', cap: 'Хук → польза → вывод: «3 аллергии, которых не существует» — 39 376 просмотров.' },
            { src: 'assets/case-ak-bulling.jpg', cap: 'Кейс-линия про детей: «важно быть в диалоге с ребёнком» — 40 109 просмотров.' },
          ],
        },

        results: [
          { v: '300 → 17 400', l: 'подписчиков за 6 месяцев' },
          { v: '254 000', l: 'просмотров — топовый Reels' },
          { v: '1 000 000+', l: 'суммарный охват на Reels' },
          { v: '68 438', l: 'просмотров — триггерный ролик' },
          { v: '88', l: 'экспертных публикаций за период' },
          { v: '0 → поток', l: 'обращений в Direct и записей' },
        ],
        resultProof: [
          {
            k: 'Профиль и охваты',
            shots: [
              { src: 'assets/case-ak-profile.jpg', cap: 'Было 300 — стало 17,4 тыс. подписчиков и 88 публикаций. Узнавать начали и офлайн.' },
              { src: 'assets/case-ak-grid.jpg', cap: 'Топовые ролики: 254 тыс., 142 тыс., 117 тыс. просмотров.' },
              { src: 'assets/case-ak-homeo.jpg', cap: '«Гомеопатия работает» — 57 564 просмотра на том самом недоверии.' },
            ],
          },
          {
            k: 'Статистика отдельных Reels',
            shots: [
              { src: 'assets/case-ak-energy.jpg', cap: '68 438 просмотров, 1 456 взаимодействий — триггерная позиция.' },
              { src: 'assets/case-ak-allergy.jpg', cap: '43 417 просмотров — экспертный разбор лечения аллергии.' },
              { src: 'assets/case-ak-likbez.jpg', cap: '39 376 просмотров, 908 взаимодействий — ликбез-формат.' },
            ],
          },
        ],

        closing: 'Если ты эксперт, личный блог — не альбом «про жизнь», а система, которая приводит пациентов и снимает недоверие к тому, что ты делаешь. Даже спорную нишу можно упаковать так, чтобы спорность работала на тебя. Вопрос не в харизме врача — вопрос в системе вокруг него.',
      },
    ],
  },
  {
    id: 'ai',
    idx: '05',
    name: 'Кейсы по ИИ',
    wip: true, // ← раздел «на ремонте»: убери эту строку, чтобы вернуть кейсы
    tagline: 'Нейросети в работе агентства',
    desc: 'ИИ-аватары, чат-боты на GPT и генерация креативов. Используем нейросети там, где они реально снижают стоимость и ускоряют — без хайпа ради хайпа.',
    stat: [{ k: 'кейса', v: '3' }, { k: 'фокус', v: 'AI' }],
    cases: [
      {
        id: 'ai-avatar',
        brand: 'ИИ-аватары',
        sub: 'Reels без съёмок',
        niche: 'AI · видео',
        role: 'ИИ-продакшн',
        duration: 'пилот',
        demo: true,
        cover: 'assets/case-diox-reels-2.jpg',
        railImg: 'assets/case-diox-reels-2.jpg',
        railMetric: 'продакшн −70%',
        video: { poster: 'assets/case-diox-reels-2.jpg', title: 'ИИ-аватары · демо' },
        headline: (<><span className="muted">ИИ-аватары снизили стоимость продакшна Reels на </span><span className="accent">70%</span><span className="muted">.</span></>),
        stats: [
          { v: <>−70<em>%</em></>, l: 'стоимость продакшна' },
          { v: <>×4</>, l: 'скорость выпуска' },
          { v: <>0</>, l: 'съёмочных смен' },
        ],
        problem: 'Регулярный видеоконтент упирался в стоимость и сроки съёмок. Эксперту некогда сниматься, а контент нужен постоянно.',
        task: 'Поставить выпуск видео на поток без живых съёмок — и сохранить качество.',
        solution: [
          'ИИ-аватар по образу спикера',
          'Генерация озвучки из текста сценария',
          'Шаблон монтажа под серию',
          'Контроль качества и фактуры',
        ],
        outcome: 'Видео выходят регулярно и дёшево. Эксперт освобождён от съёмок, контент-план не простаивает.',
      },
      {
        id: 'ai-bot',
        brand: 'GPT-бот в Direct',
        sub: 'автоворонка',
        niche: 'AI · продажи',
        role: 'чат-бот',
        duration: 'пилот',
        demo: true,
        cover: 'assets/case-diox-direct.jpg',
        railImg: 'assets/case-diox-direct.jpg',
        railMetric: '24/7 ответы',
        headline: (<><span className="muted">Бот на GPT обработал </span><span className="accent">100%</span><span className="muted"> входящих в Direct — без участия менеджера.</span></>),
        stats: [
          { v: <>100<em>%</em></>, l: 'входящих обработано' },
          { v: <>24/7</>, l: 'без выходных' },
          { v: <>−4<em>ч</em></>, l: 'время ответа → секунды' },
        ],
        problem: 'Заявки в Direct терялись: менеджер не успевал отвечать, ночные сообщения остывали, часть лидов уходила к конкурентам.',
        task: 'Закрыть первый контакт мгновенно и довести тёплого клиента до заявки в любое время суток.',
        solution: [
          'Бот на GPT с базой по продукту',
          'Сценарии ответов на частые вопросы',
          'Передача горячих лидов менеджеру',
          'Сбор контактов в воронку',
        ],
        outcome: 'Ни одно сообщение не остаётся без ответа. Менеджер подключается только к горячим лидам.',
      },
      {
        id: 'ai-creative',
        brand: 'ИИ-креативы',
        sub: 'масштаб A/B',
        niche: 'AI · перформанс',
        role: 'генерация креативов',
        duration: 'пилот',
        demo: true,
        cover: 'assets/case-diox-stats.png',
        railImg: 'assets/case-diox-stats.png',
        railMetric: '×10 гипотез',
        headline: (<><span className="muted">ИИ-генерация креативов дала </span><span className="accent">×10</span><span className="muted"> гипотез для теста при том же бюджете.</span></>),
        stats: [
          { v: <>×10</>, l: 'вариантов на тест' },
          { v: <>−45<em>%</em></>, l: 'стоимость креатива' },
          { v: <>+33<em>%</em></>, l: 'лучший CTR связки' },
        ],
        problem: 'Перформанс упирался в скорость производства креативов: мало гипотез — медленный поиск рабочей связки.',
        task: 'Резко расширить число тестируемых креативов без роста бюджета на дизайн.',
        solution: [
          'Генерация вариаций креативов нейросетью',
          'Быстрый A/B-перебор гипотез',
          'Отбор связок по метрикам',
          'Масштаб победивших вариантов',
        ],
        outcome: 'Рабочая связка находится быстрее и дешевле. Бюджет идёт в то, что уже доказало результат.',
      },
    ],
  },
];

// Галереи материалов (скрины) по кейсам, у которых нет своей gallery.
// В шаблоне переиспользуем имеющиеся ассеты; позже меняются на реальные скрины.
const GALLERIES = {
  pavlonia: ['assets/case-pavlonia-hero.jpg', 'assets/case-pavlonia-grid.jpg', 'assets/case-pavlonia-sketch.jpg'],
  shrm: ['assets/case-shrm-reel.jpg', 'assets/case-shrm-grid.jpg'],
  'prod-fuel': ['assets/case-shrm-reel.jpg', 'assets/case-shrm-grid.jpg', 'assets/case-diox-reels-1.jpg'],
  'prod-versus': ['assets/case-pavlonia-sketch.jpg', 'assets/case-pavlonia-hero.jpg', 'assets/case-pavlonia-grid.jpg'],
  'prod-elektro': ['assets/case-diox-reels-2.jpg', 'assets/case-diox-reels-1.jpg', 'assets/case-diox-stats.png'],
  'des-homeplaza': ['assets/clients/homeplaza.png', 'assets/case-pavlonia-grid.jpg', 'assets/case-diox-stats.png'],
  'des-glaz': ['assets/clients/glaz.png', 'assets/case-shrm-grid.jpg', 'assets/case-diox-direct.jpg'],
  'des-manymo': ['assets/clients/manymo.png', 'assets/case-diox-stats.png', 'assets/case-diox-direct.jpg'],
  allergo: ['assets/case-ak-profile.jpg', 'assets/case-ak-grid.jpg', 'assets/case-ak-homeo.jpg'],
  'ai-avatar': ['assets/case-diox-reels-2.jpg', 'assets/case-diox-reels-1.jpg', 'assets/case-diox-stats.png'],
  'ai-bot': ['assets/case-diox-direct.jpg', 'assets/case-diox-stats.png', 'assets/case-diox-reels-1.jpg'],
  'ai-creative': ['assets/case-diox-stats.png', 'assets/case-diox-reels-1.jpg', 'assets/case-diox-reels-2.jpg'],
};
WORK_DATA.forEach((c) => c.cases.forEach((cs) => { if (!cs.gallery) cs.gallery = GALLERIES[cs.id] || []; }));

// карта: id кейса → раздел
const CASE_INDEX = {};
WORK_DATA.forEach((c) => c.cases.forEach((cs, i) => { CASE_INDEX[cs.id] = { cat: c, pos: i }; }));

function plural(n, one, few, many) {
  const m10 = n % 10, m100 = n % 100;
  if (m10 === 1 && m100 !== 11) return one;
  if (m10 >= 2 && m10 <= 4 && (m100 < 10 || m100 >= 20)) return few;
  return many;
}

// нормализуем галерею: строка → {src, cap:''}
function normShots(gallery) {
  return (gallery || []).map((g) => (typeof g === 'string' ? { src: g, cap: '' } : g));
}

// ──────────────────────────────────────────────
// Одометр: «прокрутка» числа из 0 в целевое значение.
// Сохраняет префиксы/суффиксы (×, +, %, ₽, «млн»), разрядку
// пробелами и десятичную запятую. Строки с «→» не трогаем —
// это смысловые переходы (0 → ∞), а не счётчики.
// ──────────────────────────────────────────────
const NUM_RE = /[+\-−]?\d[\d   ]*(?:,\d+)?/;
function fmtNumber(value, decimals, grouped) {
  const fixed = value.toFixed(decimals);
  let [intPart, frac] = fixed.split('.');
  const sign = intPart.startsWith('-') ? '-' : '';
  intPart = intPart.replace('-', '');
  if (grouped) intPart = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
  return sign + intPart + (decimals ? ',' + frac : '');
}
function animateOdometer(el) {
  if (el.dataset.odoDone) return;
  const text = el.textContent;
  if (text.indexOf('→') !== -1) { el.dataset.odoDone = '1'; return; }
  const m = text.match(NUM_RE);
  if (!m) { el.dataset.odoDone = '1'; return; }
  el.dataset.odoDone = '1';
  const token = m[0];
  const trail = (token.match(/\s+$/) || [''])[0]; // хвостовой пробел-разделитель (перед «₽»)
  const sign = token.charAt(0) === '+' ? '+' : '';
  const clean = token.replace(/[   ]/g, '').replace(',', '.');
  const target = parseFloat(clean);
  if (!isFinite(target)) return;
  const decimals = token.indexOf(',') !== -1 ? (token.split(',')[1] || '').length : 0;
  const grouped = /[   ]/.test(token);
  const before = text.slice(0, m.index);
  const after = trail + text.slice(m.index + token.length);
  const dur = 1100;
  let start = null;
  const ease = (t) => 1 - Math.pow(1 - t, 3);
  const step = (ts) => {
    if (start === null) start = ts;
    const p = Math.min((ts - start) / dur, 1);
    const cur = target * ease(p);
    el.textContent = before + sign + fmtNumber(cur, decimals, grouped) + after;
    if (p < 1) requestAnimationFrame(step);
    else el.textContent = before + token + after;
  };
  requestAnimationFrame(step);
}

// ──────────────────────────────────────────────
// Сцена-эффекты (reveal / magnetic / parallax / odometer) — общие для видов
// ──────────────────────────────────────────────
function useSceneFx(rootRef) {
  React.useEffect(() => {
    const root = rootRef.current;
    if (!root) return;
    const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    // reveal (scoped)
    const fades = [...root.querySelectorAll('.fade-up')];
    fades.forEach((el, i) => {
      if (el.style.transitionDelay) return;
      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);
    });

    // odometer (числа результатов) — запуск при появлении
    const odo = [...root.querySelectorAll('[data-odometer]')];
    const odoIo = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          if (!reduce) animateOdometer(e.target);
          odoIo.unobserve(e.target);
        }
      });
    }, { threshold: 0.6 });
    odo.forEach((el) => odoIo.observe(el));

    // magnetic (scoped)
    const mags = [...root.querySelectorAll('.magnetic')];
    const magHandlers = [];
    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);
      magHandlers.push([el, move, leave]);
    });

    // 3D-наклон по курсору (карточки с .tilt)
    const tilts = [...root.querySelectorAll('.tilt')];
    const tiltHandlers = [];
    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 * 5).toFixed(2)}deg) rotateY(${(px * 6).toFixed(2)}deg) translateY(-4px)`;
      };
      const leave = () => { el.style.transform = ''; };
      el.addEventListener('mousemove', move);
      el.addEventListener('mouseleave', leave);
      tiltHandlers.push([el, move, leave]);
    });

    // parallax: медиа + универсальные .wpx (data-speed) + ghost-цифры
    const media = [...root.querySelectorAll('.wcase-media-img')];
    const pxEls = [...root.querySelectorAll('[data-speed]')];
    let raf;
    const tick = () => {
      const vh = window.innerHeight;
      media.forEach((img) => {
        const r = img.parentElement.getBoundingClientRect();
        const delta = (r.top + r.height / 2 - vh / 2) / vh;
        img.style.transform = `translateY(${(delta * 26).toFixed(1)}px)`;
      });
      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();
      odoIo.disconnect();
      if (raf) cancelAnimationFrame(raf);
      magHandlers.forEach(([el, m, l]) => {
        el.removeEventListener('mousemove', m);
        el.removeEventListener('mouseleave', l);
      });
      tiltHandlers.forEach(([el, m, l]) => {
        el.removeEventListener('mousemove', m);
        el.removeEventListener('mouseleave', l);
      });
    };
  }, []);
}

// ──────────────────────────────────────────────
// NAV
// ──────────────────────────────────────────────
function WorkNav({ 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">
        {WORK_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>
        ))}
      </div>
      <a href="index.html" className="nav-cta magnetic" data-cursor data-cursor-label="на главную">
        На&nbsp;главную&nbsp;→
      </a>
    </nav>
  );
}

// ──────────────────────────────────────────────
// HERO / GATEWAY (5 блоков-разделов)
// ──────────────────────────────────────────────
function WorkHero({ active, onPick }) {
  return (
    <header className="whero">
      <div className="shell">
        <div className="whero-eyebrow"><span className="pulse"></span>Хайпер · портфолио · 2026</div>
        <h1>
          Сделано<br />
          и <span className="accent">посчитано</span><span className="muted">.</span>
        </h1>
        <p className="whero-sub">
          Не «мы делаем SMM», а конкретные <strong>цифры до и после</strong>.
          Выберите направление — ниже откроется сетка кейсов раздела.
        </p>

        <div className="wgate">
          {WORK_DATA.map((c) => {
            const count = c.cases.length;
            return (
              <button
                key={c.id}
                className={'wgate-card magnetic' + (active === c.id ? ' is-active' : '') + (c.wip ? ' is-wip' : '')}
                data-cursor data-cursor-label={c.wip ? 'на ремонте' : 'открыть'}
                onClick={() => onPick(c.id, true)}
              >
                <span className="wgate-idx">{c.idx}</span>
                <span className="wgate-arrow">{c.wip ? '⛏' : '↗'}</span>
                <span className="wgate-name">{c.name}</span>
                {c.wip
                  ? <span className="wgate-count wgate-count--wip"><span className="dot">●</span>на ремонте</span>
                  : <span className="wgate-count"><span className="dot">●</span>{count} {plural(count, 'кейс', 'кейса', 'кейсов')}</span>}
              </button>
            );
          })}
        </div>

        <button className="whero-scroll" data-cursor data-cursor-label="вниз" onClick={() => onPick(active, true)}>
          <span className="whero-scroll-label">смотреть кейсы раздела «{(WORK_DATA.find((c) => c.id === active) || WORK_DATA[0]).name}»</span>
          <span className="whero-scroll-arrow">↓</span>
        </button>
      </div>
    </header>
  );
}

// ──────────────────────────────────────────────
// STICKY CATEGORY BAR
// ──────────────────────────────────────────────
function WorkCatBar({ active, onPick }) {
  return (
    <div className="wcatbar">
      <div className="shell">
        <div className="wcatbar-inner">
          {WORK_DATA.map((c) => (
            <button
              key={c.id}
              className={'wcatbar-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>
  );
}

// ──────────────────────────────────────────────
// CASE CARD (в сетке раздела)
// ──────────────────────────────────────────────
function CaseCard({ cs, num, onOpen }) {
  return (
    <button
      className="wcard fade-up"
      data-cursor data-cursor-label={cs.video ? 'смотреть кейс' : 'открыть кейс'}
      onClick={onOpen}
    >
      <div className="wcard-media">
        <img src={cs.cover} alt={cs.brand} loading="lazy" />
        <span className="wcard-tag">{String(num).padStart(2, '0')}</span>
        <span className="wcard-role"><span className="dot"></span>{cs.role}</span>
        {cs.video && <span className="wcard-play"><span>▶</span></span>}
        {cs.demo && <span className="wcard-demo">демо</span>}
      </div>
      <div className="wcard-body">
        <div className="wcard-brand">{cs.brand}<span className="sub">{cs.sub}</span></div>
        <div className="wcard-metric">{cs.railMetric}</div>
        <div className="wcard-foot">
          <span className="niche">{cs.niche}</span>
          <span className="go">Открыть кейс →</span>
        </div>
      </div>
    </button>
  );
}

// ──────────────────────────────────────────────
// CATEGORY WIP — временная заглушка «раздел на ремонте»
// (убери wip: true в WORK_DATA — и вернётся обычная сетка кейсов)
// ──────────────────────────────────────────────
function CategoryWip({ cat }) {
  const rootRef = React.useRef(null);
  useSceneFx(rootRef);

  return (
    <div className="wcat" id="work-content" ref={rootRef}>
      <div className="shell">
        <div className="wwip fade-up">
          <div className="wwip-idx">{cat.idx} · раздел</div>
          <div className="wwip-badge"><span className="pulse"></span>в работе</div>
          <h2 className="wwip-name">{cat.name} —<br /><span className="accent">скоро здесь</span><span className="muted">.</span></h2>
          <p className="wwip-lead">
            Собираем кейсы этого направления — с реальными <strong>цифрами «до и после»</strong>.
            Страница на ремонте: совсем скоро тут появятся работы и результаты.
          </p>
          <div className="wwip-actions">
            <button
              type="button"
              onClick={() => window.openLead({ service: window.serviceFromCategory(cat.name), source: 'Кейсы · раздел «' + cat.name + '» (в работе)' })}
              className="btn primary magnetic" data-cursor data-cursor-label="обсудить">
              <span>Обсудить проект</span><span className="arrow">→</span>
            </button>
            <span className="wwip-note">А пока загляните в раздел «SMM и маркетинг» — там кейсы с цифрами.</span>
          </div>
        </div>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────
// CATEGORY VIEW — масштаб раздела + сетка кейсов
// ──────────────────────────────────────────────
function CategoryView({ cat, onOpenCase }) {
  const rootRef = React.useRef(null);
  useSceneFx(rootRef);

  return (
    <div className="wcat" id="work-content" ref={rootRef}>
      <div className="shell">
        <div className="wcat-masthead fade-up">
          <div>
            <div className="wcat-mast-idx">{cat.idx} · раздел</div>
            <h2 className="wcat-mast-name">{cat.name}</h2>
          </div>
          <div className="wcat-mast-side">
            <p className="wcat-mast-desc">{cat.desc}</p>
            <div className="wcat-mast-stat">
              {cat.stat.map((s, i) => <span key={i}><b>{s.v}</b> {s.k}</span>)}
            </div>
          </div>
        </div>

        <div className="wgrid">
          {cat.cases.map((cs, i) => (
            <CaseCard key={cs.id} cs={cs} num={i + 1} onOpen={() => onOpenCase(cs.id)} />
          ))}
        </div>

        <div className="wcat-cta fade-up">
          <div>
            <h3>Хотите <span className="accent">такой же результат</span>?</h3>
            <p>Расскажите о задаче — посчитаем, как это сработает у вас.</p>
          </div>
          <button
            type="button"
            onClick={() => window.openLead({ service: window.serviceFromCategory(cat.name), source: 'Кейсы · раздел «' + cat.name + '»' })}
            className="btn primary magnetic" data-cursor data-cursor-label="обсудить">
            <span>Хочу такой же кейс</span><span className="arrow">→</span>
          </button>
        </div>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────
// PROOF ROW — скрины-доказательства «по месту»
// ──────────────────────────────────────────────
function ProofRow({ k, shots, brand, onImage }) {
  if (!shots || !shots.length) return null;
  return (
    <div className="wproof fade-up">
      {k && <div className="wproof-k">{k}</div>}
      <div className="wproof-row">
        {shots.map((s, i) => (
          <figure className="wproof-fig" key={i}>
            <button
              className="wproof-shot"
              data-cursor data-cursor-label="увеличить"
              onClick={() => onImage(brand, s.src)}
            >
              <img src={s.src} alt={brand + ' — доказательство ' + (i + 1)} loading="lazy" />
              <span className="wshot-zoom">⤢</span>
            </button>
            {s.cap && <figcaption>{s.cap}</figcaption>}
          </figure>
        ))}
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────
// PREMIUM · «Как это работало» — интерактивные вкладки
// Слева список из 4 пунктов, справа — скрин в рамке телефона + текст.
// ──────────────────────────────────────────────
function PremiumPillars({ pillars, brand, onImage }) {
  const [active, setActive] = React.useState(0);
  const cur = pillars[active];
  return (
    <div className="wdx-how fade-up">
      <div className="wdx-tabs" role="tablist">
        {pillars.map((p, i) => (
          <button
            key={i}
            className={'wdx-tab' + (i === active ? ' is-active' : '')}
            data-cursor
            onClick={() => setActive(i)}
          >
            <span className="wdx-tab-k">{p.k}</span>
            <span className="wdx-tab-t">{p.t}</span>
            <span className="wdx-tab-arrow">→</span>
          </button>
        ))}
      </div>
      <div className="wdx-stage" key={active}>
        <button
          className="wdx-phone wdx-phone-sm"
          data-cursor data-cursor-label="увеличить"
          onClick={() => onImage(brand, cur.shot)}
        >
          <img src={cur.shot} alt={brand + ' — ' + cur.t} loading="lazy" />
          <span className="wshot-zoom">⤢</span>
        </button>
        <div className="wdx-stage-text">
          <span className="wdx-stage-k">{cur.k} · шаг</span>
          <h4>{cur.t}</h4>
          {cur.d && <p>{cur.d}</p>}
          {cur.cap && <span className="wdx-stage-cap">{cur.cap}</span>}
        </div>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────
// PREMIUM · тело кейса DIOX — суть на первом экране
// hero (текст + телефон) → лента метрик → задача/решение/результат
// → интерактив «как это работало» → доказательства → итог
// ──────────────────────────────────────────────
function PremiumCaseBody({ cs, onImage }) {
  // Нормализация: реальные кейсы задают metrics/story/pillars/proof напрямую,
  // демо-кейсы (личный бренд) — собираем из базовых полей.
  const gal = normShots(cs.gallery);
  const metrics = cs.metrics || (cs.stats || []).map((s) => ({ v: s.v, l: s.l }));
  const story = cs.story || {
    task: cs.taskLead || cs.task,
    idea: cs.insight || cs.problem,
    result: cs.closing || cs.outcome,
  };
  const pillars = cs.pillars || (cs.solution || []).map((t, i) => ({
    k: String(i + 1).padStart(2, '0'),
    t,
    d: '',
    shot: (gal[i % (gal.length || 1)] || {}).src || cs.heroShot || cs.cover,
    cap: '',
  }));
  const proof = cs.proof || gal.map((s) => ({ src: s.src, cap: s.cap || '' }));
  const heroShot = cs.heroShot || cs.cover;
  const heroBadge = cs.heroBadge || (metrics[0] ? { v: metrics[0].v, l: metrics[0].l } : null);
  const chips = cs.tags || [cs.niche, cs.duration, cs.role, cs.platform].filter(Boolean);

  return (
    <>
      {/* 1 · HERO — суть + визуальный хук */}
      <div className="wdx-hero fade-up">
        <div className="wdx-hero-text">
          <div className="wdx-eyebrow">ХАЙПЕР · кейс{cs.kicker ? ' · ' + cs.kicker : ''}</div>
          <div className="wdx-brand">{cs.brand}<span className="sub">{cs.sub}</span></div>
          <h1 className="wdx-headline">{cs.headline}</h1>
          {cs.lead && <p className="wdx-lead">{cs.lead}</p>}
          <div className="wdx-chips">
            {chips.map((t, i) => <span className="chip" key={i}>{t}</span>)}
            {cs.demo && <span className="chip demo">демо-кейс</span>}
          </div>
        </div>
        <div className="wdx-hero-media">
          <button
            className="wdx-phone"
            data-cursor data-cursor-label="увеличить"
            onClick={() => onImage(cs.brand, heroShot)}
          >
            <img src={heroShot} alt={cs.brand} />
            <span className="wshot-zoom">⤢</span>
          </button>
          {heroBadge && (
            <div className="wdx-badge">
              <span className="wdx-badge-v" data-odometer>{heroBadge.v}</span>
              <span className="wdx-badge-l">{heroBadge.l}</span>
            </div>
          )}
        </div>
      </div>

      {/* 2 · лента метрик — результат сразу */}
      {metrics.length > 0 && (
        <div className="wdx-ribbon fade-up">
          {metrics.map((m, i) => (
            <div className="wdx-metric" key={i}>
              <div className="wdx-metric-v" data-odometer>{m.v}</div>
              <div className="wdx-metric-l">{m.l}</div>
            </div>
          ))}
        </div>
      )}

      {/* 3 · задача → решение → результат */}
      {(story.task || story.idea || story.result) && (
        <div className="wdx-flow fade-up">
          <div className="wdx-flow-step" data-step="task">
            <span className="wdx-flow-k">Задача</span>
            <p>{story.task}</p>
          </div>
          <span className="wdx-flow-arrow">→</span>
          <div className="wdx-flow-step" data-step="idea">
            <span className="wdx-flow-k">Решение</span>
            <p>{story.idea}</p>
          </div>
          <span className="wdx-flow-arrow">→</span>
          <div className="wdx-flow-step is-result" data-step="result">
            <span className="wdx-flow-k">Результат</span>
            <p>{story.result}</p>
          </div>
        </div>
      )}

      {/* 4 · как это работало — интерактив */}
      {pillars.length > 0 && (
        <div className="wdx-section">
          <div className="wdx-section-head fade-up">
            <span className="wdx-section-k">Как это работало</span>
            <span className="wdx-section-hint">кликните по шагу</span>
          </div>
          <PremiumPillars pillars={pillars} brand={cs.brand} onImage={onImage} />
        </div>
      )}

      {/* 5 · доказательства */}
      {proof.length > 0 && (
        <div className="wdx-section">
          <div className="wdx-section-head fade-up">
            <span className="wdx-section-k">{cs.demo ? 'Материалы кейса' : 'Доказательства'}</span>
            <span className="wdx-section-hint">{cs.demo ? 'примеры контента' : 'скрины статистики и Direct'}</span>
          </div>
          <div className="wdx-proof fade-up">
            {proof.map((p, i) => (
              <figure className="wdx-proof-fig" key={i}>
                <button
                  className="wdx-phone wdx-phone-xs"
                  data-cursor data-cursor-label="увеличить"
                  onClick={() => onImage(cs.brand, p.src)}
                >
                  <img src={p.src} alt={cs.brand + ' — доказательство ' + (i + 1)} loading="lazy" />
                  <span className="wshot-zoom">⤢</span>
                </button>
                {p.cap && <figcaption>{p.cap}</figcaption>}
              </figure>
            ))}
          </div>
        </div>
      )}

      {/* 6 · итог */}
      {cs.closing && (
        <div className="wdx-closing fade-up">
          <span className="wdx-closing-k">Итог</span>
          <p>{cs.closing}</p>
        </div>
      )}
    </>
  );
}

// ──────────────────────────────────────────────
// CASE DETAIL — отдельный самодостаточный кейс
// Чёткое начало и конец: листание не перетекает в соседний кейс.
// ──────────────────────────────────────────────
function CaseDetailView({ cs, cat, onClose, onOpenCase, onVideo, onImage }) {
  const rootRef = React.useRef(null);
  useSceneFx(rootRef);

  const isVideo = !!cs.video;
  const shots = normShots(cs.gallery);
  const others = cat.cases.filter((c) => c.id !== cs.id);
  const pos = cat.cases.findIndex((c) => c.id === cs.id) + 1;
  const toTop = () => {
    const el = document.getElementById('work-content');
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
  };

  return (
    <div className="wcd" id="work-content" ref={rootRef}>
      <div className="shell">
        {/* breadcrumb / возврат к разделу */}
        <button className="wcat-back fade-up" data-cursor data-cursor-label="к разделу" onClick={onClose}>
          <span className="wcat-back-arrow">←</span> Раздел «{cat.name}»
          <span className="wcat-back-pos">кейс {String(pos).padStart(2, '0')} / {String(cat.cases.length).padStart(2, '0')}</span>
        </button>

        {cs.redesign ? (
          /* ─────────── НОВЫЙ premium-layout (DIOX) ─────────── */
          <PremiumCaseBody cs={cs} onImage={onImage} />
        ) : (
        <>
        {/* 1 · шапка кейса (без большой обложки) */}
        <div className="wcd-hero fade-up">
          <div className="wcd-eyebrow">ХАЙПЕР · кейс{cs.kicker ? ' · ' + cs.kicker : ''}</div>
          <div className="wcase-meta">
            {(cs.tags || [cs.niche, cs.duration, cs.platform].filter(Boolean)).map((t, i) => (
              <span className="chip" key={i}>{t}</span>
            ))}
            {cs.demo && <span className="chip demo">демо-кейс</span>}
          </div>
          <div className="wcd-brand">{cs.brand}<span className="sub">{cs.sub}</span></div>
          <h1 className="wcd-headline">{cs.headline}</h1>
          {cs.lead && <p className="wcd-lead">{cs.lead}</p>}
          {isVideo && (
            <button className="wcd-videobtn" data-cursor data-cursor-label="смотреть" onClick={() => onVideo(cs)}>
              <span className="play">▶</span> Смотреть ролик
            </button>
          )}
        </div>

        {cs.approach ? (
          /* ─────────── развёрнутый кейс (DIOX) ─────────── */
          <>
            {/* 2 · ЗАДАЧА — главный акцент */}
            {cs.taskLead && (
              <section className="wstage" data-stage="01">
                <div className="wstage-rail">
                  <span className="wstage-no" data-speed="0.06">01</span>
                  <span className="wstage-cap">Задача</span>
                </div>
                <div className="wtask fade-up">
                  <div className="wtask-k">Что нужно было сделать</div>
                  <p className="wtask-lead">{cs.taskLead}</p>
                  {cs.taskGoals && (
                    <ul className="wtask-goals">
                      {cs.taskGoals.map((g, i) => <li key={i}>{g}</li>)}
                    </ul>
                  )}
                </div>
              </section>
            )}

            {/* 3 · с чего начинали */}
            {cs.context && (
              <section className="wstage" data-stage="02">
                <div className="wstage-rail">
                  <span className="wstage-no" data-speed="0.06">02</span>
                  <span className="wstage-cap">С чего начинали</span>
                </div>
                <div className="wcontext-grid fade-up">
                  <div className="wcase-block">
                    <div className="wcase-block-k">Ситуация клиента</div>
                    <p>{cs.context.situation}</p>
                  </div>
                  <div className="wcase-block">
                    <div className="wcase-block-k">Что делали до нас</div>
                    <p>{cs.context.before}</p>
                  </div>
                </div>
              </section>
            )}

            {/* 4 · главный инсайт */}
            {cs.insight && (
              <section className="wstage" data-stage="03">
                <div className="wstage-rail">
                  <span className="wstage-no" data-speed="0.06">03</span>
                  <span className="wstage-cap">Инсайт</span>
                </div>
                <div className="winsight fade-up">
                  <span className="winsight-quote" data-speed="0.05">“</span>
                  <p>{cs.insight}</p>
                </div>
              </section>
            )}

            {/* 5 · что сделали + пруфы */}
            <section className="wstage" data-stage="04">
              <div className="wstage-rail">
                <span className="wstage-no" data-speed="0.06">04</span>
                <span className="wstage-cap">Что сделали</span>
              </div>
              <div className="wsteps">
                {cs.approach.map((a, i) => (
                  <div className={'wstep tilt fade-up d-' + ((i % 4) + 1)} key={i}>
                    <span className="wstep-k">{a.k}</span>
                    <h4>{a.t}</h4>
                    <p>{a.d}</p>
                  </div>
                ))}
              </div>
              {cs.approachProof && (
                <ProofRow k={cs.approachProof.k} shots={cs.approachProof.shots} brand={cs.brand} onImage={onImage} />
              )}
            </section>

            {/* 6 · результаты + пруфы */}
            <section className="wstage" data-stage="05">
              <div className="wstage-rail">
                <span className="wstage-no" data-speed="0.06">05</span>
                <span className="wstage-cap">Результаты за {cs.duration}</span>
              </div>
              <div className="wresults fade-up">
                <div className="wresults-grid wresults-6">
                  {cs.results.map((r, i) => (
                    <div className={'wresult tilt fade-up d-' + ((i % 4) + 1)} key={i}>
                      <div className="wresult-v" data-odometer>{r.v}</div>
                      <div className="wresult-l">{r.l}</div>
                    </div>
                  ))}
                </div>
              </div>
              {(cs.resultProof || []).map((p, i) => (
                <ProofRow key={i} k={p.k} shots={p.shots} brand={cs.brand} onImage={onImage} />
              ))}
              {cs.closing && (
                <div className="wclosing fade-up">
                  <span className="wclosing-k">Итог</span>
                  <p>{cs.closing}</p>
                </div>
              )}
            </section>
          </>
        ) : (
          /* ─────────── базовый кейс (остальные) ─────────── */
          <>
            {/* метрики */}
            {cs.stats && (
              <div className="wcase-stats wcd-stats fade-up">
                {cs.stats.map((s, i) => (
                  <div className="wcase-stat" key={i}>
                    <div className="wcase-stat-v">{s.v}</div>
                    <span className="wcase-stat-l">{s.l}</span>
                  </div>
                ))}
              </div>
            )}

            {/* контекст + задача */}
            <div className="wcd-pair fade-up">
              <div className="wcase-block">
                <div className="wcase-block-k">Контекст</div>
                <p>{cs.problem}</p>
              </div>
              <div className="wcase-block">
                <div className="wcase-block-k">Задача</div>
                <p>{cs.task}</p>
              </div>
            </div>

            {/* что сделали */}
            <div className="wcase-block span fade-up">
              <div className="wcase-block-k">Что сделали</div>
              <ul className="wcase-steps">
                {(cs.solution || []).map((st, i) => <li key={i}>{st}</li>)}
              </ul>
            </div>

            {/* что это дало */}
            {cs.outcome && (
              <div className="wcase-block span fade-up">
                <div className="wcase-block-k">Что это дало</div>
                <p>{cs.outcome}</p>
              </div>
            )}
          </>
        )}

        {/* галерея материалов */}
        {shots.length > 0 && (
          <div className="wcase-gallery fade-up">
            <div className="wcase-gallery-k">Материалы кейса · {shots.length} {plural(shots.length, 'скрин', 'скрина', 'скринов')}</div>
            <div className={'wcd-shots' + (shots.some((s) => s.cap) ? ' with-cap' : '')}>
              {shots.map((s, i) => (
                <figure className="wshot-fig" key={i}>
                  <button
                    className="wshot"
                    data-cursor data-cursor-label="увеличить"
                    onClick={() => onImage(cs.brand, s.src)}
                  >
                    <img src={s.src} alt={cs.brand + ' — материал ' + (i + 1)} loading="lazy" />
                    <span className="wshot-zoom">⤢</span>
                  </button>
                  {s.cap && <figcaption>{s.cap}</figcaption>}
                </figure>
              ))}
            </div>
          </div>
        )}
        </>
        )}

        {/* CTA — призыв к действию (конец кейса) */}
        <div className="wcat-cta wcd-cta fade-up">
          <div>
            <h3>Хотите <span className="accent">такой же результат</span> в своей нише?</h3>
            <p>Расскажите о задаче — разберём вашу воронку и посчитаем, как это сработает у вас.</p>
          </div>
          <button
            type="button"
            onClick={() => window.openLead({ service: window.serviceFromCategory(cat.name), source: 'Кейс «' + cs.brand + '» · ' + cat.name })}
            className="btn primary magnetic" data-cursor data-cursor-label="обсудить">
            <span>Хочу такой же кейс</span><span className="arrow">→</span>
          </button>
        </div>

        {/* явный конец кейса + переход к другим кейсам раздела */}
        {others.length > 0 && (
          <div className="wother fade-up">
            <div className="wother-head">
              <span className="end">— конец кейса —</span>
              Другие кейсы раздела «{cat.name}»
            </div>
            <div className="wother-grid">
              {others.map((o, i) => (
                <button
                  key={o.id}
                  className="wother-card"
                  data-cursor data-cursor-label="открыть кейс"
                  onClick={() => onOpenCase(o.id)}
                >
                  <div className="wother-media">
                    <img src={o.railImg || o.cover} alt={o.brand} loading="lazy" />
                    {o.video && <span className="wother-play">▶</span>}
                  </div>
                  <div className="wother-body">
                    <div className="wother-brand">{o.brand}</div>
                    <div className="wother-metric">{o.railMetric}</div>
                    <div className="wother-niche">{o.niche}</div>
                  </div>
                </button>
              ))}
            </div>
          </div>
        )}

        {/* возврат */}
        <div className="wcd-foot fade-up">
          <button className="wcd-foot-back" data-cursor data-cursor-label="назад" onClick={onClose}>
            <span className="arrow">←</span> Вернуться к разделу «{cat.name}»
          </button>
          <button className="wcd-foot-up" data-cursor data-cursor-label="наверх" onClick={toTop}>↑ к началу кейса</button>
        </div>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────
// VIDEO / IMAGE LIGHTBOX
// ──────────────────────────────────────────────
function Lightbox({ data, onClose }) {
  React.useEffect(() => {
    if (!data) return;
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', onKey);
    document.body.style.overflow = 'hidden';
    return () => {
      document.removeEventListener('keydown', onKey);
      document.body.style.overflow = '';
    };
  }, [data, onClose]);

  const isImage = data && data.kind === 'image';

  return (
    <div
      className={'vlb' + (data ? ' is-open' : '') + (isImage ? ' is-image' : '')}
      onClick={onClose}
      aria-hidden={!data}
    >
      {data && (
        <div className="vlb-frame" onClick={(e) => e.stopPropagation()}>
          <button className="vlb-close" onClick={onClose} data-cursor data-cursor-label="закрыть" aria-label="Закрыть">✕</button>

          {isImage ? (
            <div className="vlb-img"><img src={data.src} alt={data.brand} /></div>
          ) : data.src ? (
            <video src={data.src} poster={data.poster} controls autoPlay playsInline />
          ) : (
            <div className="vlb-demo">
              <img src={data.poster} alt="" />
              <div className="vlb-demo-inner">
                <span className="vlb-demo-play">▶</span>
                <span className="vlb-demo-note">Видео-ролик · демо</span>
                <span className="vlb-demo-sub">
                  Здесь откроется ролик кейса «{data.brand}». В шаблоне — плейсхолдер;
                  реальное видео подключается одной строкой в данных кейса.
                </span>
              </div>
            </div>
          )}
          <div className="vlb-meta">{data.brand}{data.title ? ' · ' + data.title : ' · материалы кейса'}</div>
        </div>
      )}
    </div>
  );
}

// ──────────────────────────────────────────────
// APP
// ──────────────────────────────────────────────
function WorkApp() {
  const catIds = WORK_DATA.map((c) => c.id);

  const initial = (() => {
    const h = (window.location.hash || '').replace('#', '');
    if (catIds.includes(h)) return { cat: h, cs: null };
    if (CASE_INDEX[h]) return { cat: CASE_INDEX[h].cat.id, cs: h };
    return { cat: catIds[0], cs: null };
  })();

  const [active, setActive] = React.useState(initial.cat);
  const [activeCase, setActiveCase] = React.useState(initial.cs);

  // общие хуки из cursor.jsx
  window.useNavScroll && window.useNavScroll();

  // единый лайтбокс: видео или скриншот
  const [media, setMedia] = React.useState(null);
  const openVideo = (cs) => setMedia({ kind: 'video', brand: cs.brand, title: cs.video.title, poster: cs.video.poster, src: cs.video.src });
  const openImage = (brand, src) => setMedia({ kind: 'image', brand, src });

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

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

  const openCase = (cid) => {
    const rec = CASE_INDEX[cid];
    if (!rec) return;
    if (rec.cat.wip) { pick(rec.cat.id, true); return; } // раздел на ремонте — кейсы не открываем
    setActive(rec.cat.id);
    setActiveCase(cid);
    setHash(cid);
    scrollToContent();
  };

  const closeCase = () => {
    setActiveCase(null);
    setHash(active);
    scrollToContent();
  };

  // deep-link при загрузке: если открыт кейс — подведём к контенту
  React.useEffect(() => {
    if (activeCase) {
      const t = setTimeout(scrollToContent, 360);
      return () => clearTimeout(t);
    }
  }, []);

  const activeCat = WORK_DATA.find((c) => c.id === active) || WORK_DATA[0];
  const curCase = activeCase ? activeCat.cases.find((cs) => cs.id === activeCase) : null;

  return (
    <>
      <window.ProgressBar />
      <window.CustomCursor />
      <window.Ambient />
      <WorkNav active={active} onPick={pick} />
      <main className="work-page">
        <WorkHero active={active} onPick={pick} />
        <WorkCatBar active={active} onPick={pick} />
        {curCase && !activeCat.wip ? (
          <CaseDetailView
            key={curCase.id}
            cs={curCase}
            cat={activeCat}
            onClose={closeCase}
            onOpenCase={openCase}
            onVideo={openVideo}
            onImage={openImage}
          />
        ) : activeCat.wip ? (
          <CategoryWip key={active} cat={activeCat} />
        ) : (
          <CategoryView key={active} cat={activeCat} onOpenCase={openCase} />
        )}
      </main>
      <Footer />
      <Lightbox data={media} onClose={() => setMedia(null)} />
      <window.NavDock
        back={curCase ? { label: 'К кейсам', hint: 'раздел «' + activeCat.name + '»', onClick: closeCase } : null}
        home="index.html"
      />
    </>
  );
}

// Подвал — лёгкая локальная версия (sections-v2.jsx на этой странице не грузим)
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>
  );
}

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