# VidConf — тёмные варианты оболочки

Обязательный референс для разработки.

Тёмная тема для экранов «оболочки» (auth/лобби/календарь/join/«мои
конференции»/админка), реализована **поверх** дизайн-системы, а не взамен
неё. `design/tokens.css` и `design/DESIGN_SYSTEM.md` — единственный
источник истины по значениям (см. §0 `DESIGN_SYSTEM.md`: «светлая тема —
оболочка (со светлым/тёмным вариантом), тёмная — комната конференции
всегда»). Реализация во frontend — `frontend/src/hooks/useTheme.ts` и
`frontend/src/components/ui/ThemeToggle.tsx` (см. `frontend/README.md`,
раздел «Темы оболочки»).

## Что здесь

Разметка, контент и русские данные каждого файла — 1:1 копия
соответствующего светлого макета из `design/mockups/`. Меняется только
цветовая схема: вместо индиго-на-белом (`referens.png`) — графит-мята-роза-
янтарь той же гаммы, что уже утверждена для комнаты конференции
(`collor_ico.png`, токены `[data-theme="room"]` в `tokens.css`).

| Файл | Светлый прообраз | Экран |
|---|---|---|
| `login.html` | `../auth.html` | Вход / регистрация / подтверждение email |
| `lobby.html` | `../lobby.html` | Лобби — хаб действий 2×2 |
| `calendar.html` | `../calendar.html` | Календарь-менеджер конференций (+ создание/редактирование/отмена) |
| `join.html` | `../join.html` | Подключение по ссылке/номеру → представиться (гость) → пароль |
| `my-conferences.html` | `../my-conferences.html` | Мои конференции |
| `admin.html` | `../admin.html` | Админка (конференции, пользователи, рассылка приглашений) |

`room.html` и `email-summary.html` в комплект не входят: комната уже тёмная
(эталон гаммы), а письмо-саммари по правилам проекта всегда светлое
(почтовые клиенты не гарантируют поддержку тёмной темы/CSS-переменных).
Ссылки на «Войти»/«Создать» из `lobby.html`/`my-conferences.html` ведут на
уже существующий `../room.html`; ссылка «Открыть саммари» — на
`../email-summary.html`.

Каждый файл самодостаточен: встроенный `<style>`, инлайн-SVG-иконки
(lucide-совместимые контуры), без CDN и внешних сетевых зависимостей —
открывается двойным кликом. Единственная локальная зависимость —
`<link rel="stylesheet" href="../../tokens.css">` (тот же приём, что и в
светлых макетах: используются базовые не-цветовые токены — spacing, радиусы,
типографика, тени-заготовки, шрифты).

## Переключатель темы

В шапке каждого макета — сегментированный переключатель ☀ / 🌙 (иконки
`Sun`/`Moon`, lucide-стиль), «Тёмная» — активный сегмент. Элемент
статичный (демонстрирует точку входа в реальный toggle, не переключает
тему по клику в макете) и размещён:
- `login.html` — плавающей плашкой в правом верхнем углу (у экрана нет
  общего топбара, панель бренда/форма — раздельные колонки);
- `lobby.html`, `calendar.html`, `my-conferences.html` — внутри правой
  группы топбара, рядом с меню пользователя;
- `join.html` — в топбаре, справа от логотипа;
- `admin.html` — в шапке сайдбара, рядом с логотипом.

## Как получена палитра

### Принцип

Тёмная схема **не изобретает новых цветов**, а переиспользует уже
утверждённые токены комнаты конференции (`tokens.css`, блок
`[data-theme='room']`, см. `DESIGN_SYSTEM.md` §1.2) в новых ролях — так
оболочка и комната читаются как одна система, когда пользователь входит
из тёмного лобби в тёмную комнату. Все переопределения делаются одним
блоком `:root { … }` в начале `<style>` каждого файла — он перекрывает
одноимённые переменные `:root` из `tokens.css` (та же специфичность,
позже в источнике — выигрывает), поэтому весь остальной CSS ниже —
дословная копия светлого макета и автоматически перекрашивается.

### Токены, переиспользованные из комнаты 1:1 (без изменения hex)

| Токен оболочки (dark) | = токен комнаты | Hex | Новая роль в оболочке |
|---|---|---|---|
| `--color-bg` | `--color-room-bg` | `#1E1E1E` | фон страницы |
| `--color-surface` | `--color-room-surface` | `#2A2A2A` | карточки, топбар, поля |
| `--color-border` | `--color-room-tile-border` | `#3F3F3F` | базовая обводка |
| `--color-ink-900` | `--color-room-text-primary` | `#E8E8E8` | основной текст |
| `--color-ink-500` | `--color-room-text-secondary` | `#B0B0B0` | вторичный текст |
| `--color-ink-300` | `--color-room-text-tertiary` | `#7A7A7A` | плейсхолдеры/disabled |
| `--color-ink-700`, `--color-accent`, `--color-border-pill`, `--color-success`, `--color-success-dot` | `--color-room-mic-on` | `#7FDDA8` | мята: бренд/заголовки/ссылки/CTA/«успех» — единый пастельно-зелёный вектор (см. ниже) |
| `--color-danger`, `--color-danger-dot` | `--color-room-mic-off` | `#EB93A1` | розово-красный: текст/иконки/обводка статуса «отменена»/ошибки |
| `--color-warning`, `--color-warning-dot` | `--color-room-speaker-ring` | `#D6A83D` | янтарь: статус «запланирована» |
| `--color-focus-ring` | `--color-room-focus-ring` | `#D6A83D` | кольцо `:focus-visible` — то же значение, что и в комнате |
| `--color-danger-solid` | `--color-room-danger-bg` | `#B85468` | заливка **сплошных** danger-кнопок (см. ниже, почему это отдельный токен) |
| `--color-danger-solid-hover` | `--color-room-danger-bg-hover` | `#B9495F` | hover сплошной danger-кнопки |

**Одна мята — три роли.** В светлой оболочке бренд-индиго (`--color-ink-700`,
заголовки/ссылки/обводка pill-кнопок) и мятный CTA (`--color-accent`) — два
разных токена с разными hex. В комнате пастельная мята уже одна на всё
«позитивное» (`--color-room-mic-on` = «микрофон включён» + активная
демонстрация экрана + счётчик участников + кнопка отправки в чате). Чтобы
не завозить в тёмную оболочку новый, ничем не подкреплённый в комнате
оттенок, `--color-ink-700` и `--color-accent` в тёмной оболочке **сведены
к одному и тому же** `#7FDDA8` — бренд, заголовки, ссылки, обводка
secondary-кнопок и заливка CTA используют один и тот же «фирменный» зелёный.
Различие ролей (бренд-текст vs интерактивная заливка) остаётся читаемым за
счёт контекста (текст vs заливка с тёмным текстом поверх), а не за счёт
второго оттенка — это соответствует прецеденту самой комнаты.

**Почему заливка danger-кнопок — отдельный токен, а не `--color-danger`.**
В светлой теме один hex (`#C7364F`) одинаково хорошо работает и как текст на
белом, и как заливка кнопки с белым текстом (тёмный, насыщенный тон). В
тёмной теме эти две роли расходятся: `--color-room-mic-off` (`#EB93A1`) —
светлый пастельный тон, читаемый как **текст на тёмном фоне** (6.30:1 на
`#2A2A2A`), но слишком светлый, чтобы на нём читался белый текст кнопки
(≈1.9:1, провал). Поэтому для сплошных danger-кнопок (`.btn-danger` —
«Отменить все повторения» в календаре, «Удалить» в админке) заведена
отдельная пара `--color-danger-solid` / `--color-danger-solid-hover`,
переиспользующая уже готовые `--color-room-danger-bg(-hover)` (`#B85468` /
`#B9495F`, задокументированы в `DESIGN_SYSTEM.md` §1.2 с контрастом
4.66:1/5.02:1 для белого текста).

### Новые токены (введены только там, где у комнаты нет готового аналога)

Комната — экран без брендинга, форм и многошаговых карточек, поэтому под
нужды оболочки понадобилось несколько новых значений. Все получены
подмешиванием уже утверждённых цветов комнаты к графитовому фону/друг к
другу (не независимо придуманные тона), проверены по WCAG 2.1 (см. расчёт
ниже, тот же метод, что в `design/tools/contrast.py`):

| Токен | Hex | Как получен | Контраст | Роль |
|---|---|---|---|---|
| `--color-bg-alt` | `#242424` | между `--color-room-bg` (`#1E1E1E`) и `--color-room-surface` (`#2A2A2A`) | — | альт-фон секций, инпуты, disabled-поля |
| `--color-border-strong` | `#585858` | осветление `--color-border` | 2.02:1 на surface (нетекст, декоративный hover-акцент — дублируется тенью/курсором, не единственный носитель состояния) | обводка при hover |
| `--color-ink-400` | `#5D9A78` | мята `#7FDDA8` × фон `#1E1E1E`, смешение 35% | 5.05:1 на bg / 4.35:1 на surface | эйбрау-подписи `[ В СКОБКАХ ]`, крупные подписи (аналог ⚠︎ large-text-only из светлой темы, но с запасом) |
| `--color-accent-hover` | `#75CA9A` | мята × фон, смешение 10% | текст `#10331F` на заливке: 7.04:1 | hover CTA |
| `--color-accent-active` | `#6CB78C` | мята × фон, смешение 20% | текст `#10331F` на заливке: 5.80:1 | active/pressed CTA |
| `--color-accent-text` | `#10331F` | **не новый** — переиспользован буквальный hex, уже встречающийся инлайн в `room.html` (`.chat-input-row button`, `.tb-btn.is-positive-active`, `.badge-count`) как цвет текста на заливке `--color-room-mic-on` | 8.45:1 на мяте | текст на CTA/бренд-заливках мятой |
| `--color-success-bg` | `rgba(127,221,168,.14)` | мята с низкой непрозрачностью поверх тёмной поверхности | — | подложка бейджей «идёт сейчас»/«свободна»/«активен» |
| `--color-danger-bg` | `rgba(235,147,161,.14)` | розовый (mic-off) с низкой непрозрачностью | — | подложка бейджей «отменена» |
| `--color-warning-bg` | `rgba(214,168,61,.16)` | янтарь (speaker-ring) с низкой непрозрачностью | — | подложка бейджей «запланирована» |
| `--shadow-sm/md/lg/glass` | `rgba(0,0,0,.35–.5)` | по образцу `--shadow-room-panel` комнаты (тёмные тени вместо индиго-тонированных) | — | тени карточек/модалок/glass-панелей |

Контраст всех текстовых пар проверен по формуле WCAG 2.1 — пары, использованные
в макетах (основной текст, вторичный текст, мята/роза/янтарь как текст на
`bg`/`surface`/`tile`, белый текст на `--color-danger-solid`), все дают
≥ 4.5:1 (текст) либо ≥ 3:1 (декоративные элементы, статус которых также
задублирован иконкой/текстом — см. правило §5 `DESIGN_SYSTEM.md`). Регрессия
этих пар — в `design/tools/contrast.py`.

## Точечные правки поверх скопированного CSS

Для каждого файла CSS светлого макета скопирован дословно (все `.class`
правила без изменений) — перекраска идёт только через блок `:root`. Ручных
точечных правок пять видов, во всех случаях — потому что исходное правило
использовало **литеральный hex/rgba**, а не `var()`, и не могло
перекраситься автоматически:

1. **Аватары и `.weekday-chip.is-selected`/`.badge-role-admin`** — в
   светлой теме заливка `var(--color-ink-700)` (тёмный индиго) сочеталась с
   жёстким `color: #fff`. Так как `--color-ink-700` теперь = мята (светлый
   тон), белый текст перестаёт читаться (≈1.9:1) — заменено на
   `var(--color-accent-text)` (`#10331F`, 8.45:1 на мяте).
2. **`.btn-danger`** (`calendar.html`, `admin.html`) — добавлена отдельная
   заливка `var(--color-danger-solid)` вместо `var(--color-danger)` (см.
   таблицу выше); белый текст кнопки не менялся.
3. **`.copy-toast`** (`my-conferences.html`) — фон был `var(--color-ink-900)`
   (тёмный в светлой теме → стал бы светло-серым в тёмной, ломая тёмный
   тултип); заменён на буквальный `#333333` (= `--color-room-surface-raised`),
   текст остаётся `var(--color-ink-900)` (теперь светлый) — тултип снова
   тёмный чип со светлым текстом.
4. **Декоративные градиенты/rgba-подложки** (`login.html`
   `.brand-panel`/`.brand-panel::after`, `lobby.html` фон `body`,
   `calendar.html` `.day-col.is-today`/`.cancel-alert`, `login.html`/
   `join.html`/`calendar.html` box-shadow фокуса и ошибки, glass-обводка
   `rgba(255,255,255,.7)` в `login.html`/`admin.html`, disabled-заливка
   кнопок) — старые rgba были построены на индиго/старом danger-hex;
   заменены на тональные аналоги новой палитры (мятное свечение вместо
   индигового/мятного на белом, янтарный focus-glow вместо индигового,
   розовый error-glow, `rgba(255,255,255,.08)` вместо `.7` для тёмного
   стекла).
5. **`color-scheme: dark`** добавлен в блок `:root`, чтобы нативные
   элементы форм (скроллбар, чекбоксы без кастомной стилизации) тоже
   рендерились в тёмной палитре браузера.

## Доступность (проверено при подборе палитры)

- Текст ≥ 4.5:1 везде, кроме крупных/декоративных элементов (аналогично
  правилу §5 `DESIGN_SYSTEM.md` для светлой темы, порог 3:1).
- Статус не передаётся только цветом: бейджи конференций — иконка + текст
  (как в светлой теме), «скопировано» — смена иконки `Copy → Check` +
  текстовый тултип, ошибки полей — иконка `AlertCircle` + текст под полем,
  `:focus-visible` — везде видимое кольцо (`--color-focus-ring`, тот же
  янтарь, что и в комнате).
- Палитра пастельная (мята/роза/янтарь той же светлоты, что уже утверждена
  для комнаты), неоновых/кислотных акцентов не вводилось.
