## Why

Текущий веб-UI — черновой: инлайн `<style>`, хардкод цветов, грубый
`<meta http-equiv="refresh" content="5">` для «живости». Готов полноценный
дизайн (`tmp/design/`) — семантический HTML + один CSS-файл, заточенный ровно
под нашу архитектуру (server-rendered Go, без сборки/npm/React). Пора перенести
его в прод, чтобы «единое окно» стало пригодным для ежедневного использования.

Это презентационный change: поведение ядра (приём, распознавание, раскладка,
петля ревью) не меняется — оформляем уже существующие действия и состояния.

## What Changes

- **Отдача статики:** роут `/static/*` через `http.FileServer` над `web.FS`,
  `go:embed` для `web/static/{css,js,fonts,vendor}`, разумные `Cache-Control`.
- **Шрифты self-hosted:** IBM Plex Sans + IBM Plex Mono кладём локально и
  подключаем через `@font-face` (без Google Fonts CDN — не зависим от внешней
  сети, не светим referrer).
- **Дизайн-система:** `jellybit.css` (токены, тёмная тема по настройке ОС) как
  единственный CSS; новые цвета не вводим — только из токенов.
- **Зависимости фронта:** вендорные ассеты (htmx + шрифты) **не храним в репо** —
  `web/static/vendor/` в gitignore. `task assets` идемпотентно добывает их по
  манифесту (имя/версия/URL/sha256): нет файла или хеш не сошёлся — качает, иначе
  берёт с диска. Без Node и бандлера. Авторские css/js — обычный коммит.
- **Общие партиалы:** шапка `.app-header`, бейдж статуса (карта `state→class`),
  виджет «файл источника → раскладка» (общий для review и download).
- **Шаблоны:** переносим `index` и `review`, добавляем `download` (просмотр одной
  загрузки). Референсные `states.html`/`directions.html` в прод не идут.
- **Убираем meta-refresh** и инлайн-стили; до отдельного change живых
  обновлений список остаётся статичным (без авто-обновления прогресса).
- **Клиентский JS по минимуму:** `copyHash` (vanilla), спойлер контекста
  (нативный `<details>`). Реактивных виджетов нет — все действия идут через
  формы/htmx.
- **Превью путей** на экране ревью отображается из серверного расчёта
  (`internal/layout`), без дублирования правил в шаблоне.
- **Формы:** проставить `name` полей, совпадающие с Go-структурами обработчиков.

## Capabilities

### New Capabilities
- `web-ui`: презентационный слой веб-интерфейса — встроенная отдача статики и
  шрифтов, единая дизайн-система, рендеринг страниц (список/ревью/просмотр),
  бейджи статусов и клиентские взаимодействия без сборки (копирование infohash,
  спойлер, режим ручной раскладки с live-превью).

### Modified Capabilities
<!-- Нет. Доменное поведение приёма/распознавания/ревью не меняется; правила
     ревью-поверхности живут в docs/specs/review-ux.md (ещё не перенесены в
     OpenSpec). Этот change оформляет уже существующие действия и состояния. -->

## Impact

- **Код:** `internal/httpapi` (роут статики, новые/обновлённые хендлеры рендера,
  партиалы), `web/web.go` (`go:embed` статики), новые `web/static/**` и
  `web/templates/{index,review,download}.html`. Превью зовёт `internal/naming`.
- **Зависимости:** вендор (htmx + шрифты) добывается `task assets` по манифесту с
  checksum, не npm/не Go-модуль; Node не вводим. `web/static/vendor/` в gitignore.
  `go:embed` требует ассеты на сборке, поэтому `task build`/`task run` зависят от
  `task assets` (идемпотентного) — бинарь остаётся самодостаточным, но голый
  `go build` без фетча неполноценен (осознанный размен).
- **Поведение:** без изменений в API/ядре. Вне scope: живые обновления прогресса
  (отдельный change `web-live-updates`) и клиентский режим ручной раскладки
  файл→серия (отложен до реальной необходимости — операция редкая).
