# Лидерра · Developer Handoff

**Версия:** v8 Forest · 2026-05-07
**Назначение:** Всё необходимое разработчику для реализации портала Лидерра без участия дизайнера. Работает поверх HTML-прототипов в `concepts/v8_*.html`.

---

## 0. TL;DR — старт за 5 минут

1. **Стек, который нельзя оспаривать:** Vue 3 + Vuetify 3, светлая тема (тёмная — v2), Yandex Cloud, Yandex 360 SSO для админки, ЮKassa primary platежи. CTO-11.
2. **Палитра v8 Forest:** скопируй [§3 «CSS-переменные»](#3-дизайн-токены-css-variables) в `assets/tokens.css` и подключи глобально.
3. **Шрифты:** Inter (Google Fonts, axis `opsz` 14..32) + JetBrains Mono. Импорт в `<head>` или `@import`. См. [§4](#4-типографика).
4. **Лого:** SVG inline в `assets/logo-mark.svg` (см. [§2 «Бренд»](#2-бренд)).
5. **Все 25 экранов:** живые HTML в [`concepts/`](../concepts/) — открой `v8_dashboard.html` и снимай вёрстку напрямую. WCAG 2.1 AA подтверждено axe-core 4.10.2 на 4 viewports.
6. **Если что-то непонятно — смотри [§14 «FAQ»](#14-faq)** или пиши автору.

---

## 1. Архитектура и стек

### 1.1. Технологии (зафиксировано)

| Слой | Технология | Источник |
|---|---|---|
| Frontend | **Vue 3 + Vuetify 3** | CTO-11, не оспаривается |
| Стейт | Pinia | стандарт Vue 3 |
| Роутер | Vue Router 4 | стандарт |
| Сборка | Vite | стандарт |
| HTTP | Axios или native `fetch` | на выбор разработчика |
| Charts | ApexCharts | бриф §12 — указан напрямую |
| Виртуализация | `vue-virtual-scroller` | бриф §11 для Канбана |
| Drag-and-drop | `@vueuse/integrations` или `vuedraggable` | для Канбана |
| Backend | (out-of-scope) | Yandex Cloud, FastAPI/Node — на выбор |

### 1.2. Структура проекта (рекомендация)

```
src/
├── assets/
│   ├── tokens.css              ← из §3 этого документа
│   ├── fonts.css               ← @import Inter + JBM
│   └── logo-mark.svg           ← из §2.3
├── components/
│   ├── shell/
│   │   ├── AppSidebar.vue
│   │   ├── AppTopbar.vue
│   │   └── BrandMark.vue       ← inline SVG
│   ├── ui/
│   │   ├── BaseButton.vue
│   │   ├── BaseChip.vue        ← с 14 status variants
│   │   ├── BaseInput.vue
│   │   ├── DataTable.vue
│   │   ├── KpiCard.vue
│   │   ├── SlideOverDrawer.vue
│   │   └── BalanceWidget.vue   ← с runway-scale
│   └── domain/
│       ├── DealCard.vue
│       ├── KanbanBoard.vue
│       ├── ActivityLog.vue
│       └── BillingTransactionRow.vue
├── pages/
│   ├── Dashboard.vue
│   ├── DealsList.vue
│   ├── DealCard.vue
│   ├── Kanban.vue
│   ├── Billing.vue
│   ├── Settings.vue
│   ├── Reports.vue
│   ├── Login.vue
│   ├── errors/
│   │   ├── NotFound.vue
│   │   ├── Forbidden.vue
│   │   └── ServerError.vue
│   ├── admin/
│   │   ├── AdminLogin.vue
│   │   ├── TenantsList.vue
│   │   ├── TenantCard.vue
│   │   ├── AdminBilling.vue
│   │   ├── Incidents.vue
│   │   └── SystemSettings.vue
│   └── public/
│       ├── Home.vue
│       ├── Pricing.vue
│       ├── Offer.vue
│       └── Privacy.vue
└── App.vue
```

### 1.3. Окружения

| Окружение | Frontend | API | Что особенного |
|---|---|---|---|
| local | localhost:5173 | localhost:8000 | hot reload, mock data |
| stage | stage.liderra.app | api.stage.liderra.app | seed-данные, без оплат |
| prod | liderra.app + admin.liderra.app | api.liderra.app | полный 2FA, RLS, audit log |

---

## 2. Бренд

### 2.1. Имя

**«Лидерра»** — кириллица. Wordmark с **точкой** в конце: `Лидерра.` Точка покрашена в **bright Teal `#32C8A9`** (`--side-icon-act`) на тёмном sidebar и в **базовый Teal `#0F6E56`** на светлом фоне. Латинская транслитерация: `Liderra` (для домена `liderra.app`, email `support@liderra.app`).

**Tone of voice:** уверенный без помпезности, технический без сухости, премиальный без снобизма. Прямые формулировки про деньги. Никакого «эстетичного решения», «бесшовного опыта», «инновационного подхода».

### 2.2. Лого — `L-Square с Teal-точкой`

```
[ белый rounded-square 22×22 ]
       │
       └─ внутри: L-stroke 4.5px (тёмный) + Teal-точка r=3.5 в конце
```

### 2.3. SVG (inline, копировать в `BrandMark.vue`)

```html
<!-- Версия для тёмного sidebar (на белом квадрате) -->
<svg viewBox="0 0 48 48" width="22" height="22">
  <rect x="2" y="2" width="44" height="44" rx="10" fill="#FFFFFF"/>
  <path d="M16 14 L16 34 L32 34"
        stroke="#012019" stroke-width="4.5"
        stroke-linecap="round" stroke-linejoin="round" fill="none"/>
  <circle cx="32" cy="34" r="3.5" fill="#0F6E56"/>
</svg>
```

```html
<!-- Версия для светлого фона (тёмный квадрат) -->
<svg viewBox="0 0 48 48" width="22" height="22">
  <rect x="2" y="2" width="44" height="44" rx="10" fill="#0A1319"/>
  <path d="M16 14 L16 34 L32 34"
        stroke="#FFFFFF" stroke-width="4.5"
        stroke-linecap="round" stroke-linejoin="round" fill="none"/>
  <circle cx="32" cy="34" r="3.5" fill="#32C8A9"/>
</svg>
```

```html
<!-- Favicon — без рамки и точки (упрощённый) -->
<svg viewBox="0 0 48 48" width="32" height="32">
  <rect width="48" height="48" rx="8" fill="#0F6E56"/>
  <path d="M16 14 L16 34 L32 34"
        stroke="#FFFFFF" stroke-width="5.5"
        stroke-linecap="round" stroke-linejoin="round" fill="none"/>
</svg>
```

### 2.4. Что нельзя

- Менять пропорции, цвета, обводку лого, добавлять тени/градиенты
- Использовать «Лидпоток» (старое имя — deprecated)
- Использовать lowercase «лидерра.» — wordmark капитализирован
- Использовать слово «премиум» в маркетинге без обоснования (мы — про прозрачность и контроль, не про роскошь)

---

## 3. Дизайн-токены (CSS variables)

Все токены — реальные значения из v8 Forest. Скопировать в `assets/tokens.css`, подключить в `<head>` глобально. Все WCAG-контрасты подтверждены через axe-core 4.10.2 на 25 макетах.

```css
:root {
  /* === ПОВЕРХНОСТИ (Forest light, hue ≈ 80, warm ivory) === */
  --bg:            #F6F3EC;  /* Page background */
  --surface:       #FFFDFA;  /* Карточки, поднятые поверхности */
  --sunken:        #F0EDE4;  /* Чуть глубже bg — для table thead, sunken-areas */
  --hairline:      #D9D5CD;  /* 1px UI-border (формальный) */
  --hairline-soft: #E8E3D6;  /* Внутренние дивайдеры строк */

  /* === ТЕКСТ (на ivory bg, проверено WCAG AA) === */
  --ink:           #081319;  /* 16.96:1 — primary text */
  --ink-2:         #343C41;  /* 10.34:1 — secondary */
  --ink-3:         #66635C;  /* 5.42:1  — muted (≥4.5:1) */
  --ink-disabled:  #92907B;  /* 3.48:1  — для UI-компонентов / disabled fields */

  /* === БРЕНД === */
  --accent:        #0F6E56;  /* Teal — primary brand · 5.94:1 на bg */
  --accent-tint:   #E1EEEA;  /* Tint для selection / chip-tinted */
  --accent-deep:   #084635;  /* Hover/active state */

  /* === SIDEBAR (тёмный teal-noir) === */
  --side-bg:        #012019;
  --side-text:      #B1C2BD;  /* 9.23:1 на side-bg */
  --side-text-2:    #7A8C87;  /* nav-eyebrow muted */
  --side-active:    #13382F;  /* Selected item fill */
  --side-icon:      #5C7A72;  /* Idle icon */
  --side-icon-act:  #32C8A9;  /* Bright Teal — active icon · 8.15:1 */
  --side-hover:     #0A2A22;
  --side-border:    #1A3A30;

  /* === 14 СТАТУСОВ ВОРОНКИ (OKLCH, ΔE2000 ≥ 10.57) === */
  --st-new-tint:    #FFD8CF;  --st-new-solid:    #B94837;  /* Новая */
  --st-work-tint:   #FFDBC4;  --st-work-solid:   #B35100;  /* В работе */
  --st-call-tint:   #F6E2BC;  --st-call-solid:   #9A6700;  /* Дозвон */
  --st-nocall-tint: #E9E8BD;  --st-nocall-solid: #7E7500;  /* Не дозвон. */
  --st-neg-tint:    #D9EDC6;  --st-neg-solid:    #538200;  /* Переговоры */
  --st-quote-tint:  #C7F0D7;  --st-quote-solid:  #008A4D;  /* КП отправлено */
  --st-think-tint:  #BCF1E9;  --st-think-solid:  #008C7E;  /* Думает */
  --st-wait-tint:   #BAF0F6;  --st-wait-solid:   #00889B;  /* Ждёт оплату */
  --st-paid-tint:   #C0ECFF;  --st-paid-solid:   #007EB8;  /* Оплачено */
  --st-refund-tint: #D1E5FF;  --st-refund-solid: #406DC8;  /* Возврат */
  --st-fail-tint:   #E1E0FF;  --st-fail-solid:   #6C60C4;  /* Отказ */
  --st-dup-tint:    #F2DAFF;  --st-dup-solid:    #9052AE;  /* Дубликат */
  --st-spam-tint:   #FFD7EE;  --st-spam-solid:   #AA4788;  /* Спам */
  --st-arch-tint:   #FFD6DD;  --st-arch-solid:   #B7445F;  /* Архив */

  /* === РАДИУСЫ === */
  --r-xs: 4px;   /* мелкие пилы (chip count, kbd, mini-badges) */
  --r-sm: 6px;   /* кнопки, инпуты, нав-айтемы */
  --r-md: 10px;  /* карточки, секции, табли */
  --r-lg: 14px;  /* hero-карточки, лендинг-блоки */
  /* radius для аватара/чипа — 50% или 100px */

  /* === ШРИФТЫ === */
  --font-ui:      'Inter', system-ui, sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, 'SF Mono', Consolas, monospace;
}
```

### 3.1. Тени — НЕ используем

**v8 Forest стилистически отказывается от теней.** Глубина обеспечивается **только 1px hairline borders**. Исключение — slide-over drawer (нужен лёгкий left-edge shadow для иерархии слоёв):

```css
.drawer { box-shadow: -16px 0 40px rgba(10,19,25,0.10); }
```

Если разработчик сомневается — **не добавлять `box-shadow`**, использовать `border: 1px solid var(--hairline)`.

### 3.2. Spacing scale (4px-base)

| Token | Value | Применение |
|---|---|---|
| 4px | xs | плотные внутренние gap |
| 8px | sm | gap между кнопками в группе |
| 12px | md | padding внутри карточек |
| 16px | lg | gap между элементами секции |
| 20-24px | xl | padding section, gap между секциями |
| 32px | 2xl | page padding desktop |
| 48-64px | 3xl | hero padding |

---

## 4. Типографика

### 4.1. Шрифты (Google Fonts)

```html
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,400;14..32,500;14..32,600;14..32,700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
```

**Inter с осью `opsz`** — это Inter 4.0+, один файл с двумя «режимами»:

- `font-variation-settings: 'opsz' 14` — UI-режим (мелкий текст)
- `font-variation-settings: 'opsz' 28` — display-режим (заголовки)

Подключается через CSS variable:

```css
body {
  font-family: var(--font-ui);
  font-feature-settings: 'cv11', 'ss01', 'ss03';  /* slashed-zero, single-storey a */
  font-variation-settings: 'opsz' 14;
  -webkit-font-smoothing: antialiased;
}

.page-title {
  font-size: 28px;
  font-weight: 600;
  font-variation-settings: 'opsz' 28;  /* visual switch to display */
  letter-spacing: -0.02em;
}
```

### 4.2. Шкала размеров

| Применение | font-size | weight | opsz | letter-spacing | line-height |
|---|---|---|---|---|---|
| Hero h1 (лендинг) | 56px | 600 | 32 | -0.03em | 1.05 |
| Page title | 28px | 600 | 28 | -0.02em | 1.1 |
| Section h2 | 22px | 600 | 24 | -0.018em | 1.15 |
| Card title | 16px | 600 | 18 | -0.012em | 1.3 |
| Body | 13-14px | 400 | 14 | -0.005em | 1.5 |
| Eyebrow / label | 11.5px | 500 | 14 | letter-spacing 0.005em | 1.4 |
| Mono numeric | 12.5px | 500 | — | -0.005em | 1.4 |
| Caption | 11px | 500 | 14 | 0.005em | 1.4 |

### 4.3. Numeric (числа = деньги)

**Везде где число — `var(--font-mono)` + `font-feature-settings: 'tnum'`.** Это даёт tabular figures (одинаковая ширина цифр), без чего ровный right-align в таблицах ломается.

```css
.price, .deal-price, .balance-amount, .kpi-value, .tx-amount, .timer {
  font-family: var(--font-mono);
  font-feature-settings: 'tnum';
}
```

### 4.4. Стратегия загрузки шрифтов (audit O-stack-09)

Используется `<link rel="stylesheet">` с Google Fonts API v1 + параметр `&display=swap` (см. §4.1).

- **`&display=swap`:** браузер сразу рендерит fallback-шрифт (`system-ui`), переключается на загруженный Inter/JetBrains Mono когда тот доступен. Стратегия FOUT (Flash of Unstyled Text), но без невидимого текста — лучше для UX, чем `&display=block` или дефолтный `&display=auto`.
- **WOFF2 формат:** Google Fonts отдаёт WOFF2 по умолчанию для современных браузеров (Chrome 36+, Firefox 39+, Safari 12+). Сжатие лучше WOFF на 20–30%.
- **Preconnect:** для ускорения первого byte рекомендуется добавить в `<head>`:

  ```html
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  ```

  Это сокращает TTFB на медленных сетях (~50–200 мс). В §4.1 этот блок уже включён в snippet подключения.

- **Совместимость:** для целевой аудитории Chrome 100+, Safari 15+, Firefox 95+ дополнительный fallback не нужен. Для расширенной аудитории — добавить `@font-face` с WOFF (legacy).

### 4.5. Google Fonts API v2 + @font-face fallback (audit O-stack-10)

Текущий `<link rel="stylesheet">` использует Google Fonts API v1 (`https://fonts.googleapis.com/css2?family=...`). Для расширенной совместимости с устаревшими браузерами (поддержка ниже Chrome 100 / Safari 15 / Firefox 95) можно добавить @font-face fallback:

#### Когда использовать API v2

- **Целевая аудитория** Chrome 100+, Safari 15+, Firefox 95+ (default для Лидерры) — оставить только API v1, fallback не нужен.
- **Расширенная аудитория** включая Chrome 50–99, Safari 12–14 — добавить @font-face WOFF fallback.

#### Шаблон @font-face fallback (для расширенной совместимости)

```css
@font-face {
    font-family: 'Inter Fallback';
    src: url('/fonts/inter-variable.woff2') format('woff2-variations'),
         url('/fonts/inter-variable.woff') format('woff');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'JetBrains Mono Fallback';
    src: url('/fonts/jetbrains-mono.woff2') format('woff2'),
         url('/fonts/jetbrains-mono.woff') format('woff');
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
}
```

#### Migration path

1. Скачать `Inter` и `JetBrains Mono` с [google-webfonts-helper.herokuapp.com](https://google-webfonts-helper.herokuapp.com) или [github.com/rsms/inter/releases](https://github.com/rsms/inter/releases) и [github.com/JetBrains/JetBrainsMono/releases](https://github.com/JetBrains/JetBrainsMono/releases).
2. Поместить в `public/fonts/` (или `app/public/fonts/` для Laravel).
3. В `app/resources/css/app.css` (или Vuetify global stylesheet) добавить @font-face блоки.
4. В Vuetify config `defaults` — добавить fallback chain: `font-family: 'Inter', 'Inter Fallback', system-ui, sans-serif;`.

#### Trade-offs

- **+ Self-hosted шрифты** — нет зависимости от Google CDN, GDPR-friendly (нет cookies на fonts.googleapis.com).
- **+ Гарантия совместимости** на 10+ лет в браузерах.
- **− Размер репозитория** — +500 KB на файлы шрифтов (Inter Variable ~250 KB + JetBrains Mono ~250 KB в WOFF2).
- **− Ручной upgrade** — при выходе новых версий Inter/JetBrains Mono нужно скачивать вручную (vs автообновление через Google Fonts).

#### Решение для Лидерры (текущее, 09.05.2026)

Используется только Google Fonts API v1 + `&display=swap` (см. §4.4). @font-face fallback **не применяется** — целевая аудитория покрывает 99%+ современных браузеров. Решение пересмотреть, если: появится требование GDPR-encryption, аудит безопасности обнаружит зависимость от внешнего CDN, или статистика браузеров покажет долю старых ≥5%.

---

## 5. Компонентная библиотека

### 5.1. AppShell — общий каркас (sidebar + topbar)

Sidebar 232px sticky слева на тёмном `--side-bg`, topbar 48px sticky сверху, контент в центре. На viewport ≤ 1100px sidebar сжимается до 56px (icon-only). На ≤ 768px sidebar скрывается.

Живой пример: открой [`v8_dashboard.html`](../concepts/v8_dashboard.html), изучи `.app`, `.side`, `.main`, `.topbar`.

### 5.2. Sidebar nav-item

```html
<a class="nav-item" :class="{ active: isActive }" :aria-current="isActive ? 'page' : null" :href="route">
  <svg class="nav-icon" ... aria-hidden="true"><!-- 15px stroke 1.6 --></svg>
  <span class="nav-text">{{ label }}</span>
  <span v-if="count" class="nav-count">{{ count }}</span>
</a>
```

CSS правила см. в `v8_dashboard.html` `.nav-item` block. Selected state = solid `--side-active` fill, no border, no glow. Active icon — `--side-icon-act` (bright Teal).

### 5.3. Button

```html
<button type="button" class="btn">Базовая</button>
<button type="button" class="btn btn-primary">Primary (Teal)</button>
<button type="button" class="btn btn-danger">Danger</button>
```

Высоты:

- 30px — icon-only
- 32px — компактные / topbar / в фильтрах
- 34-36px — inline в формах
- 38-42px — primary CTA

Variants:

- `.btn` — surface + hairline border
- `.btn-primary` — accent fill, white text
- `.btn-danger` — `--st-new-solid` text + hover `#FFE7E2` bg

### 5.4. Status Chip — 14 вариантов

Два режима:

**1. Plain (dot + text, без фона)** — для таблиц, плотных строк:

```html
<span class="chip chip-paid">
  <span class="dot" aria-hidden="true"></span>Оплачено
</span>
```

**2. Tinted (с фоном)** — для emphasis (drawer current status, dashboard summary):

```html
<span class="chip chip-tinted chip-paid">
  <span class="dot" aria-hidden="true"></span>Оплачено
</span>
```

Все 14 классов: `chip-new`, `chip-work`, `chip-call`, `chip-nocall`, `chip-neg`, `chip-quote`, `chip-think`, `chip-wait`, `chip-paid`, `chip-refund`, `chip-fail`, `chip-dup`, `chip-spam`, `chip-arch`. Цвета — в [§3 токены](#3-дизайн-токены-css-variables).

### 5.5. Avatar (concentric ring)

```html
<span class="avatar" aria-hidden="true">
  ИП  <!-- 2 letter initials -->
</span>
```

```css
.avatar {
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--ink); color: #fff;  /* dark variant; см. v8_*  для tinted */
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 9.5px; font-weight: 600;
  position: relative;
}
.avatar::after {
  content: ''; position: absolute; inset: 0;
  border-radius: 50%;
  border: 1px solid rgba(10,19,25,0.10);  /* concentric ring trick */
  pointer-events: none;
}
```

### 5.6. Table

Hairline-only, no shadows. Sticky `thead`. Hover row → `--sunken`. Selected row → solid `--ink` fill, white text.

См. [`v8_deals.html`](../concepts/v8_deals.html) `.tbl`. На mobile — таблица превращается в карточки.

### 5.7. Drawer (slide-over)

460px справа, `--surface` bg, hairline left border + lazy left-edge shadow. Scrim — `rgba(10,19,25,0.18)` + `backdrop-filter: blur(2px)`.

См. [`v8_deals.html`](../concepts/v8_deals.html) `.drawer`.

### 5.8. KPI card

Hairline border, no shadow. Number в JBM mono с tnum. Trend = single Teal up-arrow на положительной дельте, **`--st-new-solid` red** на отрицательной. Никаких icon-чипов.

См. [`v8_dashboard.html`](../concepts/v8_dashboard.html) `.kpi`.

### 5.9. Balance widget с runway-scale

Наследник KPI. Те же hairlines + дополнительная Teal-рамка через `::before`. Внутри — `runway-bar` (7 сегментов hairline-tick'ов, заполненных под уровень дней).

См. [`v8_dashboard.html`](../concepts/v8_dashboard.html) `.balance` + `.runway`.

### 5.10. Timeline / Activity Log

Vertical 1px line + цветные точки по типу события:

- `create` — Teal `--accent`
- `status-change` — `--st-call-solid` (оранжевый)
- `comment` — `--ink` (чёрный)
- `call` — `--st-quote-solid` (зелёный)
- `tag` — `--st-think-solid` (бирюзовый)
- `assign` — `--st-paid-solid` (синий)
- `next/dashed` — `--ink-disabled` с `border-style: dashed`

Описание + старое→новое значение через `<span class="from">old</span> → <span class="to">new</span>` с line-through на `from` и mono font на обоих.

См. [`v8_deal_card.html`](../concepts/v8_deal_card.html) `.activity`.

---

## 6. Список всех 25 экранов

Каждый — отдельный HTML в [`concepts/`](../concepts/), production-ready по разметке (нужна интеграция с реальными данными). Все прошли axe-core 4.10.2 = **0 violations** на 1680/1440/768/375 (где применимо). Дата прогона: фиксируется при сборке handoff'а; отчёт axe требует подтверждения после фикса pa11y.config (audit P1-12, Sprint 1 Phase C `cc6e1cb` обновил пути на `liderra_v8_handoff/concepts/v8_*.html`). Перепрогон: `npm run a11y` из корня репозитория.

### 6.1. Кабинет тенанта (8 экранов)

| ID | URL | HTML | Что внутри |
|---|---|---|---|
| 01 | `/login`, `/register`, `/2fa`, `/forgot-password` | [v8_login.html](../concepts/v8_login.html) | 5 состояний: login/register с zxcvbn-индикатором/2FA с 6-cell кодом/forgot/recovery с 8 одноразовыми кодами |
| 02 | `/dashboard` | [v8_dashboard.html](../concepts/v8_dashboard.html) | KPI strip + Hero balance + Activity chart + Funnel-bar + Recent deals + System health + Quick actions |
| 03 | `/deals` | [v8_deals.html](../concepts/v8_deals.html) | Таблица 14 строк × 14 status-chips, фильтры (search + selects + density toggle), drawer открыт статически |
| 04 | `/deals/{id}` | [v8_deal_card.html](../concepts/v8_deal_card.html) | Hero + параметры + комментарий с 8 шаблонами + напоминание + footer-actions; aside: менеджер + метрики + history |
| 05 | `/deals/kanban` | [v8_kanban.html](../concepts/v8_kanban.html) | 14 колонок DnD (262px каждая), карточки с иконками 🔥/⏰/✓ |
| 06 | `/billing` | [v8_billing.html](../concepts/v8_billing.html) | Кошелёк ₽ + ГЦК + тариф; pending-banner; история транзакций; счета и УПД (1С 8.3 XML) |
| 07 | `/settings` | [v8_settings.html](../concepts/v8_settings.html) | 8 вкладок (Профиль/Безопасность/Проекты/Команда/API/Интеграции/Тихие часы/Уведомления); 3 раскрыты |
| 08 | `/reports` | [v8_reports.html](../concepts/v8_reports.html) | Форма запроса + список jobs (done/running с progressbar/queued/failed + retry); квота 2/3 |

### 6.2. Экраны ошибок (3)

Все в одном файле с review-tabs: [v8_errors.html](../concepts/v8_errors.html)

| ID | URL | Особенности |
|---|---|---|
| 09 | 404 | Декоративный SVG с маркером, кнопки «На дашборд» / «Назад» |
| 10 | 403 | Replace-key SVG, `REQ-id` для копирования, mailto support |
| 11 | 500/503 | Status-list (API/Telegram/YooKassa OK/деградация), `INC-id`, ссылка на status page |

### 6.3. Админка SaaS (6)

Все в одном файле: [v8_admin.html](../concepts/v8_admin.html). Отдельный домен `admin.liderra.app`. Тёмная плашка `ADMIN` рядом с лого.

| ID | URL | Что показано |
|---|---|---|
| 12 | `/admin/login` | SSO Yandex 360 primary + локальный 2FA fallback |
| 13 | `/admin/tenants` | Список 142 тенанта, фильтры, статус-чипы (active/trial/overdue/suspended) |
| 14 | `/admin/tenants/{id}` | Карточка тенанта: профиль, баланс, действия (impersonation, корректировка, удаление 152-ФЗ), журнал |
| 15 | Impersonation-режим | Красный sticky banner + специальная аватарка `Админ → ИП` + крест выхода |
| 16 | `/admin/incidents` | Журнал HIGH/MED/LOW, read-only для compliance |
| 17 | `/admin/system` | 6 sys-cards: system_settings / tariff_plans / legal_entities / payment_gateways / webhook_log / auth_log |

### 6.4. Лендинг и юр. (4)

Все в одном файле: [v8_landing.html](../concepts/v8_landing.html)

| ID | URL | Особенности |
|---|---|---|
| 18 | `/` | Hero с 3 hi-cards справа + 6 features + 4 tariffs + FAQ + footer (содержимое — Lorem ipsum) |
| 19 | `/pricing` | Только tariffs (4 карточки: Start/Basic/Команда POPULAR/Enterprise) |
| 20 | `/legal/offer` | TOC + 8 разделов оферты (шаблон Прил. Ж) |
| 21 | `/legal/privacy` | TOC + 10 разделов 152-ФЗ Politики |

### 6.5. Бренд-документация

| ID | Файл | Что |
|---|---|---|
| BR-1 | [v8_brand.html](../concepts/v8_brand.html) | 10 имён + 5 знаков + 3 favourite combo. Архив выбора. |
| BR-2 | [v8_palette_options.html](../concepts/v8_palette_options.html) | 5 палитр на выбор (А Graphite/Б Forest/В Slate-Blue/Г Champagne/Д Inverted Hero). Архив. |

---

## 7. Соглашения по доступности (WCAG 2.1 AA)

### 7.1. Что обязательно

- **Все интерактивные** (`<a>`, `<button>`, `<input>`, `<select>`, `<textarea>`, `[tabindex]`) имеют `:focus-visible` с outline:

  ```css
  a:focus-visible, button:focus-visible, input:focus-visible, [tabindex]:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: var(--r-sm);
  }
  ```

- **Все SVG-иконки** — `aria-hidden="true"` (декоративные)
- **Все icon-only кнопки** — `aria-label="..."`
- **Все form-inputs** — `<label for="...">` или `aria-label`
- **Selection state** — solid fill (см. row.selected на dark `--ink`), не tint
- **`role="tablist"`** требует все children = `<button role="tab">` (не просто `<button>`)
- **`prefers-reduced-motion`** — выключает анимации scoped через class `.has-motion`, не через `*`:

  ```css
  @media (prefers-reduced-motion: reduce) {
    .has-motion { animation: none !important; transition: none !important; }
  }
  ```

- **Skip link** на каждой странице для клавиатурной навигации:

  ```html
  <a href="#main" class="skip-link">К контенту</a>
  ```

### 7.2. Контраст — проверка перед мержем

Перед каждым PR прогнать через [axe DevTools](https://www.deque.com/axe/devtools/) или Playwright + axe-core 4.10.2. **0 violations — обязательное условие** для merge. Дата прогона: фиксируется при сборке handoff'а; отчёт axe требует подтверждения после фикса pa11y.config (audit P1-12, Sprint 1 Phase C `cc6e1cb` обновил пути на `liderra_v8_handoff/concepts/v8_*.html`). Перепрогон: `npm run a11y` из корня репозитория.

### 7.3. Известные «проблемные» комбинации

Эти пары давали contrast violations в процессе и были исправлены — повторять НЕ нужно:

| Не делать | Контраст | Решение |
|---|---|---|
| `--ink-disabled` на `--surface` для текста ≥9px | 3.18:1 | `--ink-3` (5.42:1) |
| `--st-quote-solid` (#008A4D) на белом для 11.5px text | 4.36:1 | #006A3B + bold (4.5:1+) |
| Текст 10px на solid `--st-neg-solid` / `--st-quote-solid` / `--st-paid-solid` | 4.14-4.33:1 | Убрать текст из solid-сегмента, перенести в подпись |
| `aria-hidden="true"` на `<aside>` с фокусируемыми ссылками | aria-hidden-focus | Заменить на `aria-label="..."` |
| `<div>` с `aria-label` без role | aria-prohibited-attr | Добавить `role="progressbar"` / `role="img"` |
| 5 tabs в `display:flex` без `flex-wrap` на mobile | Overflow → axe не видит true bg | Добавить `flex-wrap: wrap` |

---

## 8. Vue 3 + Vuetify 3 — практические подсказки

### 8.1. Где брать Vuetify-компонент vs кастомный

| Vuetify-готовый | Полу-кастомный | Полностью кастомный |
|---|---|---|
| `v-text-field`, `v-select`, `v-checkbox`, `v-snackbar`, `v-dialog`, `v-menu` | `v-data-table-server` (с правкой стилей под наши токены) | StatusChip с 14 вариантами, BalanceWidget с runway, Timeline, Sidebar nav |

### 8.2. Vuetify тема через токены

В `vuetify.options.ts`:

```ts
import 'vuetify/styles';
export default {
  theme: {
    defaultTheme: 'liderra',
    themes: {
      liderra: {
        dark: false,
        colors: {
          primary: '#0F6E56',
          'on-primary': '#FFFDFA',
          surface: '#FFFDFA',
          background: '#F6F3EC',
          error: '#B94837',
          warning: '#9A6700',
          success: '#008A4D',
          info: '#007EB8',
        },
      },
    },
  },
};
```

Дополнительно в `assets/tokens.css` подключить ВСЕ переменные из [§3](#3-дизайн-токены-css-variables) — Vuetify не покрывает status-палитру, sidebar tokens и др.

### 8.3. Шаблон страницы

```vue
<template>
  <AppShell>
    <template #topbar-crumb>
      <span>Рабочая область</span>
      <ChevronIcon />
      <strong>{{ pageTitle }}</strong>
    </template>
    <main id="main" class="content">
      <PageHeader :title="pageTitle" :stats="pageStats" />
      <!-- секции -->
    </main>
  </AppShell>
</template>
```

`AppShell` инкапсулирует `.app + .side + .topbar + .main`. Детальная реализация — отдельный issue.

---

## 9. Известные правила проекта (нельзя оспаривать)

Из брифа `01_Scope_i_ekrany.md` §6:

- **Тёмная тема** — отложена на v2 (CSS-vars для будущей dark theme заложены, но макетов нет)
- **2FA** — на всех тарифах, включая бесплатный
- **Минимум 100 ₽** пополнения, округление **вниз** при ₽→лиды
- **Pending-платеж** — нет кнопки «Отменить» (CTO-11), самовосстановление 30 минут
- **Click-wrap при регистрации** — 3 чекбокса (оферта / ПДн / маркетинг-опционально)
- **Yandex Cloud + Yandex 360 SSO** для админки
- **JivoSite** для helpdesk-чата (Биз-5)
- **Webhook outbound** — primary integration option, REST API на втором месте
- **amoCRM** — спринт 14-15, Bitrix24/RetailCRM — Post-MVP

---

## 10. Что точно НЕ делать на MVP

- Темная тема UI
- Wizard «OSINT-рекомендации источников» (Биз-15)
- Телефонная интеграция (UI VoIP) — Биз-12
- Промокоды и реферальная программа — Б-6
- Tab «Удалённые проекты» с покупкой обратно — Биз-14
- Bitrix24 / RetailCRM коннекторы — только amoCRM
- Кнопка «Отменить» pending-платежа — CTO-11
- Кнопка «Отменить подписку» — уход через смену тарифа на Start (Биз-2)

---

## 11. API-контракт (намёки для backend)

Это не полный контракт (он out-of-scope этого документа), но есть конкретные требования из дизайна:

### 11.1. WebSocket / SSE для real-time

Дашборд показывает «LIVE» индикатор на balance widget — это требует push-канала. Минимум: `lead.created`, `payment.completed`, `balance.updated`.

### 11.2. Activity Log

Каждое изменение поля карточки сделки — запись в `deal_activity_log` с полями:

```typescript
{
  id: string,
  deal_id: string,
  actor_id: string | null,         // менеджер или null = system
  type: 'create'|'status-change'|'comment'|'call'|'tag'|'assign'|'reminder',
  timestamp: ISO8601,
  payload: {
    field?: string,                 // 'status' | 'manager_id' | ...
    from?: any,                     // old value
    to?: any,                       // new value
    text?: string,                  // for comments
    duration_sec?: number,          // for calls
  }
}
```

### 11.3. Saas Admin Audit Log

Согласно бриф §23.10 + дизайн админки — каждое действие админа пишется в `saas_admin_audit_log`. Impersonation-режим имеет **обязательное поле `reason`** при входе.

### 11.4. RLS для multi-tenant

Каждый запрос API проверяет `tenant_id` через RLS на стороне БД. Bypass attempt = инцидент HIGH severity (см. админка/Incidents).

### 11.5. Webhook signatures

Outbound webhook подписывается **HMAC SHA-256** в заголовке `X-Liderra-Sign`. Документация для клиентского интегратора — отдельный документ.

### 11.6. Status проекта

```
GET /status → { api: 'OK' | 'degraded' | 'down', integrations: [...] }
```

Используется на 500-странице.

---

## 12. Тестирование

### 12.1. axe-core 4.10.2 — обязательно

Прогон через CI на каждом PR. Pseudo-pipeline:

```bash
playwright test --headed
# в playwright тесте:
await page.evaluate(() => axe.run(document, { runOnly: ['wcag2a','wcag2aa','wcag21aa'] }))
# violations.length должен быть 0
```

### 12.2. Viewport coverage

Все экраны проверять как минимум на 4 viewports:

- **1680×1050** — desktop large
- **1440×900** — desktop стандарт
- **768×1024** — tablet
- **375×812** — mobile (iPhone X reference)

### 12.3. Reduced motion

Включить `prefers-reduced-motion: reduce` в DevTools → проверить, что декоративные анимации (pulse, slide) выключены, но focus rings и hover transitions работают.

### 12.4. Keyboard-only навигация

Tab через всю страницу — все интерактивные элементы должны иметь видимый focus ring.

---

## 13. Полезные команды для разработчика

### 13.1. Локальный preview макетов

```bash
cd дизайн
python -m http.server 8765
# открыть http://localhost:8765/concepts/v8_dashboard.html
```

### 13.2. Прогон axe для проверки

```javascript
// В DevTools console на любой странице:
const s = document.createElement('script');
s.src = 'https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.10.2/axe.min.js';
document.head.appendChild(s);
s.onload = async () => {
  const r = await axe.run(document, { runOnly: ['wcag2a','wcag2aa','wcag21aa'] });
  console.log('Violations:', r.violations.length, r.violations);
  console.log('Passes:', r.passes.length);
};
```

### 13.3. OKLCH палитра — ещё пары

Если нужно добавить новый статус — использовать [`palette_14.py`](../palette_14.py) с другим `start_hue` и repulsion-итерацией. **min ΔE2000 ≥ 10** обязательно.

```bash
cd дизайн
PYTHONIOENCODING=utf-8 python palette_14.py
```

---

## 14. FAQ

**Q: Можно ли использовать Tailwind вместо чистого CSS?**
A: Можно, но токены из [§3](#3-дизайн-токены-css-variables) должны попасть в `tailwind.config.ts`. Проще импортировать tokens.css глобально и использовать классы из v8_*.html напрямую (они стабильные).

**Q: Что делать, если нужен новый статус (15-й)?**
A: Перезапустить `palette_14.py` с N=15, ΔE2000 пересчитается. Все 14 существующих останутся, новый встанет в свободное место hue-кругa. Дизайнер должен утвердить (новый статус = новый workflow в БД).

**Q: Можно ли поменять Teal `#0F6E56` на синий?**
A: НЕТ без явного OK заказчика — это брендовый цвет (зафиксирован Диз-2). Если нужно — сначала переоткрыть бренд-решение.

**Q: ApexCharts не дружит с opsz axis Inter?**
A: Использовать font-family fallback: ApexCharts читает `font-family: 'Inter'` без opsz, выглядит чуть-чуть толще, но не критично.

**Q: Как повторить OKLCH-расчёт?**
A: Python 3.12+ с `pip install colour-science numpy`. Скрипты в `palette_*.py` в корне `дизайн/`.

**Q: Где живёт реальный source of truth для брендбука?**
A: Этот файл (`docs/DEVELOPER_HANDOFF.md`). Файл `дизайн/02_Brand_i_A11y.md` устарел (там про v1.1 «Лидпоток»).

---

## 15. Контакты

| Роль | Контакт |
|---|---|
| Дизайнер | `kpd9363@gmail.com` (Платон) |
| Поддержка дизайна | через данный handoff + `concepts/v8_*.html` |
| Заказчик | Дмитрий |

---

## 16. Изменения

| Версия | Дата | Что изменилось |
|---|---|---|
| v8 Forest | 2026-05-07 | Полная переработка: Лидерра, Forest палитра, L-Square лого, 25 макетов |
| v7 cool-tech | 2026-05-07 | Деприкейтнут (cool-grey слишком белый, sidebar сливался) |
| v4-v6 | до 2026-05-07 | Архивы итераций — не использовать |

---

*Конец `DEVELOPER_HANDOFF.md` v8 Forest.*
