Перейти к основному содержимому

ADR 0181 — Тёмная тема становится нейтрально-чёрной, и долг контраста заканчивается

Статус​

Accepted. 2026-09-30 (AT-283 и AT-284, история HS-073, эпик EP-031, раунд 29). Поверх ADR 0074 (достижимая тема, измерение в обеих темах, восемь синтаксических ролей) и ADR 0036 (мерило "handoff устанавливает намерение, измерение устанавливает число"). Не редактирует их: МЕХАНИЗМ 0074 остаётся целиком — boot файлом, две измеряемые темы, выведенный паритет, восемь --syntax-*; меняется ЧИСЛО почти каждого цветового токена, а с ним три вещи, которые 0074 утверждал о тёмной теме.

Контекст​

Тёмная тема была насыщенной сине-бирюзовой (--surface-0 #061b24, тон 198°, насыщенность ~71%) с кремовым текстом и ярким терракотовым акцентом (#d6633a). Решение владельца от 2026-09-30: продукт получает рыночную нейтрально-чёрную тёмную тему, спокойную, со смягчённым терракотовым акцентом (идентичность остаётся в акценте, а не в поверхности), а светлая становится нейтральной из того же семейства вместо песочной бумаги.

Перед заменой весили три измеренных факта:

  1. Тёмная тема несла долг контраста с FASE 16. Пять используемых пар были ниже 4,5:1 — --text-muted на --surface-1 (3,89) и --surface-2 (3,10), --accent и --danger на --surface-1 (3,88), и --success на --surface-2 (4,41). 0074 зафиксировал их числом, и четыре экрана сменили токен, чтобы обойти это (.hint, .link, блок состояния окружения, навигация ошибки Shell).
  2. У основной кнопки было "известное исключение". --on-accent (крем) на --accent давал 3,20:1 в тёмной; ADR 0036 отказался это чинить, потому что "меняет марку во всём UI". Тот же крем на --success в Button давал 2,07:1.
  3. Цвет вне токенов. Три места, рисующие runtime-библиотекой (Mermaid, xterm, canvas миникарты), имели 27 hex-fallback, написанных вручную, в прежнем бирюзовом, а "person" C4 использовал СЫРУЮ палитру --teal-400/600. Три цвета агентов были отдельными hex в lib/agents.ts, откалиброванными только по тёмной. Overlay Modal был бирюзовым в rgba. И два используемых токена не существовали: --surface-3 и --radius-pill.

Решение​

1. Семантические значения меняются; имена — нет. Ни одному модулю не нужно менять ссылку: --surface-*, --text-*, --accent*, --on-accent, состояния, --violet, границы, --code-bg, --diff-* и восемь --syntax-* сохраняют прежние имена. Вводится сырая шкала --neutro-* (000…950, цинк без тона), на которую ссылаются поверхности, вторичный текст и границы обеих тем; четыре старые сырые матрицы остаются (никто не использует их в UI, а их удаление ничего бы не дало).

2. Число берётся из измерения, а не из черновика. Черновик владельца был отправной точкой; где он не проходил, число корректировалось, пока порог не проходил:

токен (тёмная)черновикитогпочему
--text-muted#71717a#86868fчерновик повторял долг (3,80 / 3,51 на карточке и заголовке); итог даёт 5,38 / 5,10 / 4,70 и остаётся ниже --text-secondary
--on-accent(светлый)--neutro-900белый на #c8744f дал бы 3,46 и 2,68 при hover; нейтральный чёрный даёт 5,61 / 7,25, и 7,65 на --success, 5,24 на --danger
токен (светлая)черновикитогпочему
--text-muted#71717a#696972черновик давал 4,40 на --surface-2, а светлая закрывает текст на 4,5 со времён 0074

Остальной черновик прошёл как был: поверхности #0d0d0f/#141417/#1c1c21, границы #2a2a30/#3a3a42, текст #ececef/#a1a1aa, акцент #c8744f, состояния #3fb68b/#d4a13a/#e5534b, --code-bg #0a0a0c; в светлой #ffffff/#fafafa/ #f4f4f5, текст #18181b/#52525b и затемнённая терракота #a4502c (5,08 против --code-bg, 5,58 с белым кнопки). Восемь --syntax-* были пересчитаны против двух новых --code-bg и проходят 4,5:1 в обеих темах (наименьший — --syntax-type светлой, 4,85). Акцент остаётся терракотовым: тон держится около ~18° в обеих темах, и это проверяется тестом.

3. Долг тёмной темы заканчивается, а то, что было зафиксированным числом, становится ПОРОГОМ. Пять пар долга проходят 4,5:1 в обеих темах, и тест теперь требует порог вместо "continua em 3,89". Два ИНВЕРТИРОВАННЫХ утверждения design-contraste.test.ts ("muted reprova sobre card", "accent reprova sobre card") переписаны как порог, а потребители пересмотрены: .link (AuthLayout) возвращается к --accent, которого всегда требовал макет; .hint (Input) остаётся на --text-secondary, теперь по иерархии, а не по контрасту. Исключение основной кнопки перестаёт существовать, и исправление не изменило марку — изменило ТЕКСТ на ней.

4. Цвет вне токенов входит в токены (AT-284).

  • apps/web/src/lib/tokens-padrao.ts хранит ОДНУ копию значений основной темы для Mermaid, xterm и миникарты, а tokens-padrao.test.ts проваливается, когда она расходится с :root. "person" C4 переходит на --accent на --surface-1.
  • --agent-leve, --agent-frontend и --agent-secops рождаются со значением для каждой темы и измеряются на 3:1 на трёх поверхностях; в lib/agents.ts остаётся только var(--token), и тест проваливает hex.
  • --overlay — вуаль Modal, для каждой темы.
  • --surface-3 и --radius-pill НЕ рождаются: оба использования переходят на то, что уже отрисовывали (--surface-1/--surface-2 и --r-pill), а design-tokens-existentes.test.ts проваливает следующий var(--x) без объявления в CSS и без записи в runtime.

Последствия​

  • Пробел "dívida de contraste do tema ESCURO travada por número (ADR 0074)" в CLAUDE.md закрывается. Правило никогда не ослаблять порог сохраняется, теперь без зарегистрированного исключения.
  • 111 color-mix() модулей (AT-285) здесь НЕ пересматривались: они смешивают токены и остаются валидными, но визуальный результат каждого меняется с новой базой, и пересмотр — дело отдельной lane.
  • Несколько комментариев CSS-модулей цитируют старые числа долга (Shell.module.css, SinaisDoAmbiente.module.css, ProjectCard.module.css, ProjectRail.module.css, TurnActivityStrip.module.css, Input.module.css в placeholder). Обосновываемые ими выборы остаются валидными; цитируемое число историческое. Их обновление — дело пересмотра модулей.
  • Сайт документации (website/src/css/custom.css) имеет собственную палитру и не затрагивался.
  • Превью .design-sync, зависящие от контраста, остаются невалидными до следующей визуальной валидации (об этом говорит сам тамошний NOTES.md).