/* СОБРАНО из assets/ui (tokens/*) по assemble из assets/ui/kit.json — не редактировать здесь, правьте источники и запустите node tools/sync-ui.mjs --write. Версия kit 0.1.0 (assets/ui/kit.json). */
/* Примитивы — палитра и шкалы без смысла (SPEC-344 §3.1/§3.2). Заготовка
 * шага 2 плана (§8): извлечение значений из tokens/semantic.css в примитивы
 * и построение шкал (--space-*, --radius-*, --dur-*, --z-*, --fs-*) —
 * задача шага 3. Пусто до тех пор, buildKit() подключает файл сейчас,
 * чтобы порядок склейки (примитивы → семантика → компонентные токены) не
 * пришлось менять шагом позже.
 */
/* Токены «Мягкого матового чёрного» для приложений без сборки: Mini App
 * (apps/pwa, маршрут /tg/) и управление (apps/admin). ЕДИНСТВЕННЫЙ ИСТОЧНИК —
 * assets/ui/tokens.css; копии в apps/pwa/public/ui и apps/admin/public/ui раскладывает и сверяет
 * `node tools/sync-ui.mjs`. Правка в копии — красная проверка.
 *
 * Решение оператора 25.09: чистый #000/#FFF заменён на тёплый матовый чёрный
 * и тёплую «бумагу», с одним акцентным (латунь) токеном — раньше хроматики
 * не было вовсе, теперь она есть, ровно один тон.
 *
 * РОЛИ ТОКЕНОВ те же, что в apps/site/public/tokens.css, и между темами не
 * меняются — меняются только значения:
 *   --ink        только фон страницы
 *   --graphite   слегка приподнятая поверхность (карточка), НЕ фон страницы
 *   --bone       текст высшего контраста (основной текст)
 *   --mist       обычный/вторичный текст
 *   --ash        служебное, подписи — равен --mist: оператор задал ровно два
 *                уровня текста (основной, вторичный), третий не придуман
 *   --accent     латунь — акцент: активное состояние, фокус, заливка
 *                основного действия (текст на заливке — var(--ink), он уже
 *                инвертирован по теме и даёт контраст без отдельного токена)
 *   --hairline   границы
 *   --radius-compact
 *                компактное прямоугольное скругление для управляющих
 *                элементов и приподнятых поверхностей; форма, не отступ
 *   --radius-pill
 *                скругление «таблетки» — круглые торцы у чипа/переключателя
 *   --radius-round
 *                круглая форма для точки-индикатора; радиус, а не отступ
 *
 * Контраст (WCAG 2.1, посчитан tools/check-contrast.mjs, тест —
 * apps/pwa/tests/contrast.test.mjs и apps/admin/tests/contrast.test.mjs):
 * основной текст ≥7:1 к фону И к поверхности, вторичный/акцент ≥4.5:1 к
 * фону И к поверхности — в каждой теме ниже, включая особые.
 *
 * Гарнитуры — фирменные и self-hosted (аудит шрифтов 28.09): текст Dony
 * Sans, заголовки и знак — Dony Display (собственный, 0.201), @font-face —
 * atoms/type.css и atoms/mark.css, файлы — копии в <приложение>/public/fonts/. CSP обоих маршрутов — style-src 'self' и
 * default-src 'self': сторонних источников шрифтов нет, системная стопка
 * остаётся запасной.
 *
 * Режим темы выбирает assets/ui/theme.js (копии — apps/<приложение>/public/ui/theme.js):
 * «как в системе» (умолчание, без атрибута — решает prefers-color-scheme
 * ниже), «тёмная»/«светлая» (явный data-theme), особые темы старших
 * уровней — свой data-theme, раздача по уровню клиента решается на шлюзе
 * (apps/gateway/src/theme-access.mjs) и сегодня выключена рубильником для
 * всех (решение оператора 25.09, d314dd) — список допустимых тем пуст, пока
 * оператор не включит раздачу. Из темы клиента Telegram (Mini App) берётся
 * ровно один признак — светлая она или тёмная (решение оператора
 * 2026-09-22, п.3); внутри Mini App человек может переопределить её вручную
 * тем же переключателем.
 */

/* Тёмная — умолчание направления, применяется без атрибута data-theme. */
:root {
  --ink: #121110;
  --graphite: #1b1a18;
  --bone: #e9e5dc;
  --mist: #9c978d;
  --ash: #9c978d;
  --accent: #c9a15a;
  --hairline: rgba(233, 229, 220, 0.14);
  --hairline-strong: rgba(233, 229, 220, 0.32);

  --ui: 'Dony Sans', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --display: 'Dony Display', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --mono: ui-monospace, 'SF Mono', Menlo, 'Roboto Mono', monospace;

  --fs-title: 40px;
  --fs-display-sm: 26px;
  --fs-h2: 26px;
  --fs-lead: 18px;
  --fs-item: 17px;
  --fs-body: 16px;
  --fs-small: 14px;
  --fs-meta: 12px;

  /* Ритм: крупные паузы между группами, мелкие — внутри строки. */
  --gap-row: 16px;
  --gap-group: 36px;
  --gap-page: 20px;

  /* Форма: минимальное скругление прямоугольных контролов/поверхностей,
     независимо от плотности строк и групп. */
  --radius-compact: 2px;

  /* Форма скругления без размеров: 999px у таблетки и 50% у точки —
     это ФОРМА, а не длина, и по построению не может вырасти вместе с
     элементом. Появились из замера 16.10: check-ui-tokens (U4) счёл
     два новых литерала в apps/admin/public/screens.css («чип-фильтр»
     и «точка статуса») нарушением, а токена формы для них не было —
     то есть правило запрещало писать по-новому без выхода. */
  --radius-pill: 999px;
  --radius-round: 50%;

  /* Широкая раскладка: колонка чтения и навигация слева от неё. */
  --measure: 720px;
  --rail: 240px;

  color-scheme: dark;
}

/* Значения светлой темы подключаются двумя путями: системным
   предпочтением (первый кадр до скрипта, и живое переключение ОС при
   выбранном «как в системе» — без него) и явным data-theme (ручной выбор
   или ответ клиента Telegram). Блок значений один и тот же. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    --ink: #f3eee5;
    --graphite: #ffffff;
    --bone: #1f1b16;
    --mist: #6f665a;
    --ash: #6f665a;
    --accent: #8b631c;
    --hairline: rgba(31, 27, 22, 0.14);
    --hairline-strong: rgba(31, 27, 22, 0.32);
    color-scheme: light;
  }
}

:root[data-theme='light'] {
  --ink: #f3eee5;
  --graphite: #ffffff;
  --bone: #1f1b16;
  --mist: #6f665a;
  --ash: #6f665a;
  --accent: #8b631c;
  --hairline: rgba(31, 27, 22, 0.14);
  --hairline-strong: rgba(31, 27, 22, 0.32);
  color-scheme: light;
}

/* Явная тёмная — нужна там, где ручной выбор должен пересилить светлую ОС
   (data-theme='dark' не совпадает с [data-theme='light'] и не входит в
   :not([data-theme]) выше, поэтому наследует значения :root по умолчанию —
   отдельного блока не требуется, но color-scheme проговорён явно). */
:root[data-theme='dark'] {
  color-scheme: dark;
}

/* ── Особые темы старших уровней (SPEC — раздача по уровню клиента, п.4
   операторского задания 25.09; d314dd). Рубильник в
   apps/gateway/src/theme-access.mjs выключен по умолчанию — сегодня ни один
   клиент их не получает от сервера. CSS готов и создание переключателя
   (assets/ui/theme.js, параметр allowed) умеет принять список с сервера —
   но apps/{pwa,admin}/public/app.js сегодня создают его с allowed:[]
   безусловно, ответ /v1/auth/{link,telegram} (поле themes) в интерфейс
   ещё не доведён. Тема применяется только явно, через data-theme в
   разметке/консоли — не через интерфейс приложения. Follow-up. ── */

/* Винная — от уровня Signature. */
:root[data-theme='wine'] {
  --ink: #2a1116;
  --graphite: #3a1a20;
  --bone: #f1e6df;
  --mist: #b89a98;
  --ash: #b89a98;
  --accent: #c9a15a;
  --hairline: rgba(241, 230, 223, 0.14);
  --hairline-strong: rgba(241, 230, 223, 0.32);
  color-scheme: dark;
}

/* Крем-брюле — от уровня Signature. Вторичный и акцент темнее, чем в
   задании оператора (#7e6b58 и #a8743b): на заданных значениях
   tools/check-contrast.mjs даёт вторичный 4.23:1 к фону / 3.66:1 к
   карточке, акцент 3.34:1 к фону / 2.89:1 к карточке — оба ниже 4.5:1
   по обеим поверхностям — см. PR, «что проверить». */
:root[data-theme='creme'] {
  --ink: #f3e9d8;
  --graphite: #e8d9c0;
  --bone: #2b211a;
  --mist: #6d5a47;
  --ash: #6d5a47;
  --accent: #865219;
  --hairline: rgba(43, 33, 26, 0.14);
  --hairline-strong: rgba(43, 33, 26, 0.32);
  color-scheme: light;
}

/* Нави — от уровня Exclusive (идентификатор в коде остался navy). */
:root[data-theme='navy'] {
  --ink: #0f1a2b;
  --graphite: #18253a;
  --bone: #e6eaf0;
  --mist: #8e9bae;
  --ash: #8e9bae;
  --accent: #c9a15a;
  --hairline: rgba(230, 234, 240, 0.14);
  --hairline-strong: rgba(230, 234, 240, 0.32);
  color-scheme: dark;
}

/* Изумруд — от уровня Exclusive. */
:root[data-theme='emerald'] {
  --ink: #0f211c;
  --graphite: #173028;
  --bone: #e7eee8;
  --mist: #8fa69b;
  --ash: #8fa69b;
  --accent: #c9a15a;
  --hairline: rgba(231, 238, 232, 0.14);
  --hairline-strong: rgba(231, 238, 232, 0.32);
  color-scheme: dark;
}

/* Безопасная зона. --tg-* ставит сам скрипт клиента Telegram на
   documentElement; два отступа складываются (железо + интерфейс клиента).
   Вне Telegram переменных нет, остаётся env() браузера. */
:root {
  --pad-top: calc(var(--tg-safe-area-inset-top, 0px) + var(--tg-content-safe-area-inset-top, 0px));
  --pad-bottom: max(
    calc(var(--tg-safe-area-inset-bottom, 0px) + var(--tg-content-safe-area-inset-bottom, 0px)),
    env(safe-area-inset-bottom, 0px)
  );
  --pad-left: max(var(--tg-safe-area-inset-left, 0px), env(safe-area-inset-left, 0px));
  --pad-right: max(var(--tg-safe-area-inset-right, 0px), env(safe-area-inset-right, 0px));
}
/* Компонентные токены и токены состояний (SPEC-344 §3.1, §3.2).
 * Значения собираются из семантического слоя и общих шкал; темы
 * переопределяют только семантику (tokens/semantic.css), но не форму
 * компонентов.
 */
:root {
  /* Фокус и вуаль перекрытий (§3.1, Решение 1) */
  --focus-ring: var(--accent);
  --scrim: color-mix(in srgb, var(--ink) 72%, transparent);

  /* Состояния выражаются формой и плотностью, а не отдельным цветом (§3.1, Решение 2) */
  --state-pending-opacity: 0.6;
  --state-disabled-opacity: 0.4;
  --state-press-opacity: 0.85;
  --state-failed-border-style: dashed;
  --state-attention-border: 1px solid var(--hairline-strong);
  --state-current-offset: 5px;

  /* Касание и геометрия управляющих элементов (§3.1, §3.2) */
  --touch-min: 44px;
  --control-h: 44px;
  --control-h-lg: 52px;
  --button-h: var(--control-h);
  --button-radius: var(--radius-compact);
  --field-border: 1px solid var(--hairline);
  --field-border-focus: 1px solid var(--focus-ring);
  --card-pad: var(--gap-row);
  --card-radius: var(--radius-compact);
  --chip-radius: var(--radius-pill);
  --shadow-pop: 0 12px 32px color-mix(in srgb, var(--ink) 48%, transparent);

  /* Разрядка моно-капса и слои (§3.1, §3.2) */
  --label-tracking: 0.12em;
  --label-tracking-wide: 0.18em;
  --z-base: 0;
  --z-raised: 1;
  --z-sticky: 2;
  --z-overlay: 40;
  --z-skip: 50;
}
/* Длительности как токены (--dur-fast/-base/-loop, SPEC-344 §3.2) и общее
 * место reduced-motion для НИХ. Заготовка шага 2 плана (§8), наполняется
 * шагом 3. До тех пор длительности остаются литералом там же, где были —
 * в assets/ui/atoms/motion.css (`.action, .link` transition), рядом с
 * компонентами, которые их используют.
 *
 * Наполнение — шаг 3, 21.10.2026. Значения по SPEC-344 §3.2:
 *   --dur-fast   140ms  — отклик на касание;
 *   --dur-base   220ms  — смена состояния, раскрытие;
 *   --dur-loop   1200ms — пульс, запись голоса;
 *   --dur-typing 1400ms — бегущее правило «АССИСТЕНТ ПИШЕТ» (#3218).
 * Тема значения не меняет: длительность — это ритм, а не оформление.
 *
 * reduced-motion — одно место, как предписывает §3.2: под
 * prefers-reduced-motion: reduce длительности --dur-fast/-base становятся 0ms,
 * а петли (--dur-loop, --dur-typing) запускаются только под no-preference: их потребители
 * обязаны жить внутри @media (prefers-reduced-motion: no-preference).
 *
 * Пока токены заполнены, а миграция литералов (§8, шаг 3) не доведена,
 * сторож U6 (tools/check-ui-tokens.mjs) считает «длительность transition/
 * animation литералом» и держит базовую линию: новое движение пишется
 * токеном, а не числом.
 */
:root {
  --dur-fast: 140ms;
  --dur-base: 220ms;
  --dur-loop: 1200ms;
  --dur-typing: 1400ms;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 0ms;
    --dur-base: 0ms;
  }
}
