# VSE AI · providers-banners

Standalone drop-in для двух баннеров со страницы Провайдеры (`mockups-providers.html`):
- **Plus full-screen** — модалка-апсейл на весь экран, 3 варианта.
- **Promo home** — узкая полоска на главной (52px), 4 варианта.

Эти файлы — **не показ, а отдельные готовые компоненты**, чтобы фронт мог встроить их в Mini App без выковыривания из общей страницы мокапа.

## Что внутри

```
providers-banners/
├── banners.css            # изолированные стили (только plus-* и promo-* классы + нужные tokens)
├── plus-fullscreen.html   # demo: 3 варианта Plus в phone-frame (393x700), copy-paste разметка
├── promo-banner.html      # demo: 4 варианта Promo узкая strip-полоска
├── PlusBanner.tsx         # React-компонент Plus full-screen, читает PlusVariantData
├── PromoBanner.tsx        # React-компонент Promo, читает PromoVariantData
├── plus-bg/               # 3 PNG-фона для Plus
│   ├── v1-cyan-waves.png
│   ├── v2-cyan-aurora.png
│   └── v3-cyan-flow.png
└── README.md
```

## Источники текстов

Все тексты вариантов лежат в `../assets/providers.json` (semver v1.0.0):

```json
{
  "banners": {
    "plus_full_screen": {
      "primary_variant": "A",
      "variants": [
        { "id": "A", "tag": "все ии · plus", "title": "...", ... },
        { "id": "B", "tag": "скидка действует 24ч", ... },
        { "id": "C", "tag": "plus открыт · 24 часа", ... }
      ]
    },
    "promo_home": {
      "primary_variant": "A",
      "variants": [
        { "id": "A", "label": "PLUS — 999 ₽/мес", "strike": "2 999 ₽", "tone": "cyan" },
        { "id": "B", "label": "Все нейросети по цене одной — −67%", "tone": "cyan" },
        { "id": "C", "label": "Все нейросети без лимита — открыть Plus", "tone": "cyan" },
        { "id": "D", "label": "Скидка 67% на Plus — действует 24 часа", "tone": "gold", "star": "🎁" }
      ]
    }
  }
}
```

**Фронт не хардкодит тексты** — fetch'ит `providers.json` на старте app или импортит build-time.

## Использование (HTML)

```html
<!-- 1. Подключи fonts и CSS -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/providers-banners/banners.css">

<!-- 2. Plus full-screen modal — открой при /plus?v=A -->
<div class="plus-screen">
  <div class="plus-bg" style="background-image: url('/providers-banners/plus-bg/v1-cyan-waves.png');"></div>
  <div class="plus-card">
    <div class="plus-close" onclick="closePlus()">✕</div>
    <div class="plus-tag">все ии · plus</div>
    <h2>Все нейросети без лимитов</h2>
    <p>GPT, Claude, Gemini, Grok и ещё 20+ моделей. <strong>Без VPN</strong>, <strong>без зарубежных карт</strong>.</p>
    <div class="plus-promo">
      <div class="pp-line1">только сегодня</div>
      <div class="pp-line2">999 ₽ <span class="strike">2 999 ₽</span></div>
    </div>
  </div>
  <div class="plus-cta-wrap">
    <div class="plus-cta" onclick="checkout()">Подключить Plus</div>
  </div>
</div>

<!-- 3. Promo на главной — узкая strip-полоска -->
<div class="promo-banner" onclick="openPlus('A')">
  <div class="pb-left">
    <span class="star">✦</span>
    <span>PLUS — 999 ₽/мес</span>
    <span class="strike">2 999 ₽</span>
  </div>
  <div class="pb-arrow">→</div>
</div>
```

## Использование (React)

```tsx
import { PlusBanner } from "./providers-banners/PlusBanner";
import { PromoBanner } from "./providers-banners/PromoBanner";
import providers from "./assets/providers.json";
import "./providers-banners/banners.css";

const plusVariants = providers.banners.plus_full_screen.variants;
const promoVariants = providers.banners.promo_home.variants;

function HomePage() {
  const promoA = promoVariants.find(v => v.id === "A")!;
  const [plusOpen, setPlusOpen] = useState(false);

  return (
    <>
      <PromoBanner variant={promoA} onClick={() => setPlusOpen(true)} />
      {plusOpen && (
        <PlusBanner
          variant={plusVariants[0]}
          bgBasePath="/providers-banners/plus-bg"
          onClose={() => setPlusOpen(false)}
          onCtaClick={(id) => router.push(`/checkout?v=${id}`)}
        />
      )}
    </>
  );
}
```

## Тёмная тема

Все цвета — из CSS-переменных в `banners.css`. Если у вас есть свой `:root` с переопределёнными `--accent-cyan`, `--text-primary` и т.д., — banners подхватят их автоматически.

## A/B-тестирование

Поле `primary_variant` в `providers.json` указывает текущий «победитель». Остальные варианты — для A/B. Когда поменяете primary, обновите `primary_variant` в JSON, фронту менять код не нужно.

## Откуда это берётся

`mockups-providers.html` (страница «Провайдеры + баннеры» в брендбуке) — единый source of truth дизайна. Стили в этом архиве `banners.css` извлечены оттуда 1-в-1. Если меняется дизайн на странице, обнови этот пакет: пересобери `banners.css`, обнови `plus-fullscreen.html` / `promo-banner.html` примеры, бамни версию в `providers.json`.

## Версия

`providers.json` следует semver. Текущая версия: **1.0.0**. Этот пакет извлечён 2026-05-15.