/* TokSeq – шрифтовая база под мультиязычность. Этап 2Б, 2026-07-29.
   Канонический файл: Caddy/landing/fonts.css. Побайтовая копия: Core-v1/dashboard/web/fonts.css
   (борд отдаётся с другого vhost'а и своего рута). Паритет копий держит гард
   `Caddy/tools/check_fonts.py` – правку вносить в обе, как у гейтов допуска.

   ЗАЧЕМ ЭТОТ ФАЙЛ СУЩЕСТВУЕТ. Проект три года стоит на СИСТЕМНЫХ шрифтах: витрина и борд не
   грузят ни одного веб-шрифта (замер 2026-07-29: 0 `@font-face` во всех страницах кроме постера
   архитектуры). Для латиницы, кириллицы и греческого это работает и ломать это ради единообразия
   рендеринга незачем. Ломается другое: у системного стека `system-ui, -apple-system, "Segoe UI",
   Roboto, sans-serif` НЕТ гарантии на армянский, грузинский, деванагари и CJK. Там, где системная
   гарнитура скрипт не покрывает, браузер уходит в свой дефолт – а это Times New Roman, то есть
   ровно тот дефект, который уже ловили на постере (см. ниже).

   ПРИНЦИП: не грузить ни одного байта, пока не доказано, что системного шрифта нет.
   Поэтому здесь – СТЕКИ ПО ЛОКАЛИ (ноль трафика, мгновенный фолбэк), а не веб-шрифты.
   Сабсет подключается только для скриптов, где системного покрытия нет ни на одной массовой
   платформе; реестр таких скриптов – `Caddy/tools/fonts.manifest.json` (лежит ВНЕ раздаваемого
   каталога: это метаданные сборки, посетителю их отдавать незачем), сборщик сабсетов –
   `Caddy/tools/build_font_subsets.py`, блок `@font-face` в конце файла пишет он же.

   ЧТО ЭТОТ ФАЙЛ НЕ МЕНЯЕТ. Для ru, en и всего тира 1 (es, fr, de, pl, pt-BR, tr, az, kk, uk) и
   для греческого (el) правил здесь НЕТ намеренно: их скрипты покрыты базовым стеком, и рендеринг
   принятых на проде страниц обязан остаться байт-в-байт прежним. Правила появляются только у
   локалей, чей скрипт базовым стеком не покрыт.

   ДВА МЕХАНИЗМА – потому что поверхности устроены по-разному:
     M1. Переменные `--font-ui` / `--font-mono` – их читают борд и панель
         (`dashboard/web/*.html`, `:root{--font-ui:…}`).
     M2. Наследуемый `font-family` на `body` – витрина пишет стек литералом
         (`landing/index.html:49`), переменных там нет.
   Селекторы покрывают обе схемы переключения языка: `html[lang]` (борд ставит его в `applyLang()`)
   и `body[data-lang]` (витрина, парные блоки). `|=` матчит и регион: `zh` и `zh-Hans`.

   CSP. Ни одна строка здесь не требует ослабления политики: подключение идёт `<link
   rel="stylesheet" href="/fonts.css">` со СВОЕГО origin (`style-src 'self'` уже разрешает),
   веб-шрифты – файлами со своего домена (`font-src 'self' data:` уже разрешает и это, и `data:`).
   Сторонние CDN шрифтов (Google Fonts) политикой запрещены и должны остаться запрещёнными:
   подключение с внешнего хоста потребовало бы правки CSP, а правку делать не нужно. */

/* ─────────────────────────────────────────────────────────────────────────────
   Базовые стеки. Значения совпадают с тем, что уже стоит в страницах, – файл их
   не переопределяет, а даёт единое имя для тех поверхностей, где переменных не было.
   ───────────────────────────────────────────────────────────────────────────── */
/* Родовое имя (`sans-serif`, `monospace`) вынесено из `*-core` НАМЕРЕННО. Стек читается
   браузером ПОГЛИФНО, и родовое имя не обрывает перебор, но разворачивается в конкретную
   гарнитуру (на Windows – Arial/Courier New), которая нужного письма не несёт. Держать его
   в СЕРЕДИНЕ стека значит вставлять между «нашими» гарнитурами и гарнитурой письма ещё одну
   попытку, никогда не срабатывающую; правило собирается как `core, письмо, родовое`. */
:root {
  --font-sans-core: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial;
  --font-ui-core: system-ui, -apple-system, "Segoe UI", Roboto;
  --font-mono-core: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas;
  --font-sans-base: var(--font-sans-core), sans-serif;
  --font-ui-base: var(--font-ui-core), sans-serif;
  --font-mono-base: var(--font-mono-core), monospace;
}

/* ─────────────────────────────────────────────────────────────────────────────
   Армянский (hy). Windows несёт Sylfaen, macOS – Mshtakan, на Android армянский
   есть НЕ всегда. Гарнитуры письма идут ПОСЛЕ базового стека: латиница, цифры и тикеры
   («BTC perp.», «15m») обязаны остаться в том же гротеске, что на остальных страницах, –
   иначе внутри одной строки соседствуют два рисунка знака. Армянские глифы браузер и так
   возьмёт из первой гарнитуры стека, которая их содержит.
   ───────────────────────────────────────────────────────────────────────────── */
html[lang|="hy"], body[data-lang|="hy"] {
  /* «TSQ Fallback …» – СВОЙ сабсет, объявленный блоком @font-face в конце файла. Он стоит
     ПОСЛЕДНИМ среди гарнитур письма намеренно: браузер выбирает гарнитуру поглифно и доходит
     до веб-шрифта только тогда, когда ни одной системной не нашлось. На Windows и macOS
     (Sylfaen, Mshtakan) сабсет НЕ СКАЧИВАЕТСЯ вовсе – ноль байт; платит трафиком только тот,
     у кого письма нет, и платит 8 КБ вместо тофу. */
  --font-armenian: "Noto Sans Armenian", "Noto Sans Armenian UI", Sylfaen, Mshtakan, "Arial Armenian", "DejaVu Sans", "TSQ Fallback Armenian";
  --font-sans: var(--font-sans-core), var(--font-armenian), sans-serif;
  --font-ui: var(--font-ui-core), var(--font-armenian), sans-serif;
  --font-mono: var(--font-mono-core), var(--font-armenian), monospace;
}
html[lang|="hy"] body, body[data-lang|="hy"] { font-family: var(--font-sans); }

/* ─────────────────────────────────────────────────────────────────────────────
   Грузинский (ka). Windows 10+ несёт грузинский в Sylfaen и Segoe UI, на Android – не всегда.
   Мтаврули (U+1C90–1CBF) моложе мхедрули и есть далеко не во всех системных гарнитурах:
   заглавная строка заголовка осыплется первой, поэтому Noto Sans Georgian стоит первым
   СРЕДИ ГАРНИТУР ПИСЬМА. Порядок «база, письмо, родовое» тот же, что у остальных локалей.
   ───────────────────────────────────────────────────────────────────────────── */
html[lang|="ka"], body[data-lang|="ka"] {
  --font-georgian: "Noto Sans Georgian", "BPG Arial", "BPG Nino Mtavruli", Sylfaen, "DejaVu Sans", "TSQ Fallback Georgian";
  --font-sans: var(--font-sans-core), var(--font-georgian), sans-serif;
  --font-ui: var(--font-ui-core), var(--font-georgian), sans-serif;
  --font-mono: var(--font-mono-core), var(--font-georgian), monospace;
}
html[lang|="ka"] body, body[data-lang|="ka"] { font-family: var(--font-sans); }

/* ─────────────────────────────────────────────────────────────────────────────
   Хинди, деванагари (hi). Требует ШЕЙПИНГА: лигатуры-конъюнкты, знаки над и под
   базовой линией. Строка, корректная по кодовым точкам, рендерится с разорванными
   лигатурами, если гарнитура без GSUB/GPOS для скрипта, – поэтому системный
   `sans-serif` здесь не спасает и проверять надо глазами, а не гардом.
   Высота строки поднята: диакритика деванагари выходит за обычный интерлиньяж 1.42
   и слипается со следующей строкой в плотных карточках борда.

   СВОЕГО ФАЙЛА У ДЕВАНАГАРИ НЕТ, и стек это честно отражает: перечислены только СИСТЕМНЫЕ
   гарнитуры. Покрытие: Windows 8+ – Nirmala UI, macOS/iOS – Devanagari Sangam MN и Kohinoor,
   Android/ChromeOS – Noto. Дыра: Linux-десктоп без пакета Noto деванагари не нарисует. Раньше
   в стеке стояло имя «TSQ Fallback Devanagari» без единого `@font-face` – браузер такое имя
   молча пропускает, и звено выглядело страховкой, не будучи ею. Имя вернётся вместе с файлом:
   исходник Noto Sans Devanagari (SIL OFL 1.1) кладёт оператор, см. `Caddy/TODO.md`.
   ───────────────────────────────────────────────────────────────────────────── */
html[lang|="hi"], body[data-lang|="hi"] {
  --font-devanagari: "Noto Sans Devanagari", "Nirmala UI", "Kohinoor Devanagari", "Devanagari Sangam MN", Mangal;
  --font-sans: var(--font-sans-core), var(--font-devanagari), sans-serif;
  --font-ui: var(--font-ui-core), var(--font-devanagari), sans-serif;
  --font-mono: var(--font-mono-core), var(--font-devanagari), monospace;
}
html[lang|="hi"] body, body[data-lang|="hi"] {
  font-family: var(--font-sans);
  line-height: 1.62;
}

/* ─────────────────────────────────────────────────────────────────────────────
   CJK: японский (ja) и китайский упрощённый (zh).
   ШРИФТ НЕ ГРУЗИМ И НЕ САБСЕТИМ – решение по замеру, а не по лени:
     * полная гарнитура Noto Sans SC – мегабайты (единицы МБ даже в woff2);
     * сабсет по нашему корпусу (~1 210 сообщений) даёт 1 500–2 500 иероглифов,
       это всё равно сотни килобайт И ломается на ЛЮБОМ новом знаке, включая
       текст, приходящий из API, – то есть даёт «квадратики» в проде молча;
     * системная CJK-гарнитура есть на КАЖДОЙ платформе, где на CJK смотрят.
   Цена решения: рендеринг у японца и китайца будет системным, а не «фирменным».
   Это осознанный размен – он же действует для латиницы и кириллицы с самого начала.
   ───────────────────────────────────────────────────────────────────────────── */
html[lang|="ja"], body[data-lang|="ja"] {
  --font-cjk: "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic UI", "Yu Gothic", "Noto Sans JP", "Noto Sans CJK JP", Meiryo, "MS PGothic";
  --font-sans: var(--font-sans-core), var(--font-cjk), sans-serif;
  --font-ui: var(--font-ui-core), var(--font-cjk), sans-serif;
  --font-mono: var(--font-mono-core), var(--font-cjk), monospace;
}
html[lang|="zh"], body[data-lang|="zh"] {
  --font-cjk: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans SC", "Noto Sans CJK SC", "Source Han Sans SC", SimHei;
  --font-sans: var(--font-sans-core), var(--font-cjk), sans-serif;
  --font-ui: var(--font-ui-core), var(--font-cjk), sans-serif;
  --font-mono: var(--font-mono-core), var(--font-cjk), monospace;
}
html[lang|="ja"] body, body[data-lang|="ja"],
html[lang|="zh"] body, body[data-lang|="zh"] { font-family: var(--font-sans); }

/* Типографика CJK. Два дефекта чинятся стилями, третий – не чинится, и врать про него нельзя.
     1. ПЕРЕНОС. В CJK нет пробелов, строка рвётся между иероглифами. Без `line-break: strict`
        браузер разрешает начинать строку со знаков, которые начинать её не имеют права
        (。、」）) – плотные карточки борда получают висячую пунктуацию в начале строки.
        `word-break` НЕ трогаем: между ханьскими знаками браузер и так переносит, а
        `break-all`/`anywhere` сломали бы латинские вставки (тикеры, числа, «BTC perp.»).
     2. ИНТЕРЛИНЬЯЖ. 1.42 базовой вёрстки рассчитан на латиницу; иероглиф занимает полную
        кегельную площадку, и на 1.42 строки визуально слипаются.
     3. КЕГЕЛЬ – ЧИНИТСЯ НЕ ЗДЕСЬ. 7–9px, читаемые на латинице (подписи осей, легенды, бейджи
        борда), для CJK нечитаемы физически. Поднять минимум глобальным правилом нельзя:
        размеры заданы селекторами по классу (`.b13stat .l{font-size:8px}`, специфичность 0,2,0),
        и любое правило вида `body *` их не перебивает – получилась бы строка, которая
        выглядит как решение и не делает ничего. Настоящий рычаг – переменная `--scale` борда
        и ревизия мелких кеглей при приёмке тира 3, это работа вёрстки, а не шрифтовой базы.
        Гард на длину (`i18n_check.py`, проверка 6) для CJK тоже неинформативен: строка короче
        по знакам и шире по пикселям. */
html[lang|="ja"] body, body[data-lang|="ja"],
html[lang|="zh"] body, body[data-lang|="zh"] {
  line-height: 1.72;
  line-break: strict;
}

/* ─────────────────────────────────────────────────────────────────────────────
   МЕНЮ ЯЗЫКА – единственное место, где стек по активной локали не работает.

   Пункты меню показывают САМОНАЗВАНИЯ языков на их собственном письме («Հայերեն», «ქართული»,
   «हिन्दी», «日本語», «简体中文» – см. `meta.language_name` в каталоге и `locales.json`), и показывают
   их НА ЛЮБОЙ ЛОКАЛИ: русскоязычный посетитель открывает меню и видит все письма сразу.
   Правило `html[lang|="hy"]` здесь бессильно – язык документа при этом русский, а не армянский.
   Без этого стека самоназвания рисуются дефолтом браузера или «квадратиками», то есть ровно тот
   пункт меню, который человек ищет глазами, оказывается нечитаемым.

   Стек не грузит ни байта: перечислены системные гарнитуры всех платформ. Он намеренно ДЛИННЫЙ –
   браузер выбирает первую, где ЕСТЬ нужный глиф, а не первую установленную. Порядок:
   базовая латиница/кириллица, затем письма по алфавиту скриптов.
   ───────────────────────────────────────────────────────────────────────────── */
#b13-lang .tsq-thmenu, .tsq-langsw .tsq-thmenu,
#b13-lang button[data-lang], .tsq-langsw button[data-l] {
  font-family:
    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial,
    "Noto Sans Armenian", Sylfaen, Mshtakan, "TSQ Fallback Armenian",
    "Noto Sans Georgian", "BPG Arial", "TSQ Fallback Georgian",
    "Noto Sans Devanagari", "Nirmala UI", "Devanagari Sangam MN",
    "Hiragino Sans", "Yu Gothic UI", "Noto Sans JP", Meiryo,
    "PingFang SC", "Microsoft YaHei UI", "Noto Sans SC",
    sans-serif;
}

/* ─────────────────────────────────────────────────────────────────────────────
   Страховочные сабсеты. Блок ГЕНЕРИРУЕТСЯ – руками не править.

   Его пишет `Caddy/tools/build_font_subsets.py` по манифесту: кладёт woff2 в
   `landing/fonts/` и вписывает сюда `@font-face` с `unicode-range`. Без `unicode-range`
   браузер скачал бы армянский сабсет ради английской страницы.

   Здесь только те скрипты, у которых системного покрытия нет НИ НА ОДНОЙ массовой
   платформе (`coverage: subset` в манифесте): сегодня это армянский и грузинский.
   Деванагари сюда НЕ входит – его рисует системная гарнитура (`coverage: stack`),
   а свободного исходника для сабсета в дереве нет; правило проекта – «в проект не
   попадает бинарь, который агент не может ни проверить, ни легально получить сам».
   Гард `check_fonts.py` держит обе стороны: объявленный сабсет обязан лежать файлом,
   а файл без объявления – нарушение.

   FONT-FACE:BEGIN (маркер сборщика – не удалять) */
@font-face{font-family:'TSQ Fallback Armenian';font-style:normal;font-weight:400;
  font-display:swap;src:url('fonts/tsq-fallback-armenian.woff2') format('woff2');
  unicode-range:U+0531-0556, U+0559-055F, U+0561-0587, U+0589-058A, U+FB13-FB17}
@font-face{font-family:'TSQ Fallback Georgian';font-style:normal;font-weight:400;
  font-display:swap;src:url('fonts/tsq-fallback-georgian.woff2') format('woff2');
  unicode-range:U+10A0-10C5, U+10D0-10FC, U+2D00-2D25}
/* FONT-FACE:END */
