/*
 * Токены экранов стадиона. Один файл на табло, «Топы» и консоль.
 *
 * До этого каждый экран объявлял свой набор переменных: `--gold` совпал случайно,
 * `--accent` означал разное, «успех» существовал только в консоли. Три тёмных экрана
 * без общей системы — это и есть шаблон, за который дизайн-контур отклонил прежний
 * вид (design/README.md).
 *
 * Палитра НЕ изобретена: это бренд публичного сайта (landing/design/tokens.css),
 * поднятый по светлоте там, где он лежит на тёмной подложке табло.
 *
 * Контраст проверен по WCAG 2.1 (4.5:1 для текста, 3:1 для крупного):
 *   --board-fg   на --board-bg   17.8:1
 *   --board-mut  на --board-bg    7.1:1
 *   --run        на --board-bg    8.9:1   (часы бегущего)
 *   --pb         на --board-bg   10.4:1   (личный рекорд)
 *   --alarm-fg   на --alarm-bg    9.6:1   (плашка «нет связи»)
 *   --desk-text  на --desk-bg    18.1:1
 *   --desk-mut   на --desk-bg     6.4:1
 *   --brand-red  на --desk-bg     4.6:1   (только текст ≥ 15px и обводки)
 */

/* ================================================================ ГАРНИТУРЫ ==
 * До этого в репозитории не было ни одного `@font-face` и ни одного файла
 * шрифта: весь согласованный типографический характер существовал только в
 * комментариях, а все три экрана набирались system-ui — то есть Roboto на
 * ТВ-стике, Segoe на ноутбуке оператора и San Francisco на планшете. Три разных
 * шрифта на трёх поверхностях одной системы — тот же дефект, что три палитры,
 * ради которых заведён этот файл.
 *
 * ГДЕ ЛЕЖАТ БИНАРНИКИ: `public/shared/fonts/`. Выбор не случайный — это
 * единственная директория, которая (а) уже раздаётся всем трём экранам
 * существующим монтированием `/shared` в src/api/operatorApi.ts и (б) целиком
 * попадает в образ ядра (`COPY public ./public`). Публичный сайт собирается из
 * `landing/` ОТДЕЛЬНЫМ контекстом сборки и до этой папки не дотягивается, а
 * копия бинарника разъезжается ровно так же, как разъезжались копии токенов;
 * поэтому там те же самые начертания уложены внутрь файла токенов — почему
 * именно так, написано в landing/design/tokens.css.
 *
 * CDN запрещён: экраны стадиона живут в изолированной LAN, где чужого домена
 * просто нет, а посетитель публичного сайта не обязан платить за шрифт визитом
 * к третьей стороне.
 *
 * ЧЕТЫРЕ ФАЙЛА, А НЕ ШЕСТНАДЦАТЬ: Google Fonts отдаёт Golos Text переменным
 * шрифтом — на запрос `wght@400;600;700;900` все четыре начертания приходят
 * ОДНИМ адресом на подмножество (проверено: запрос одного веса даёт другой,
 * статический файл). Поэтому `font-weight: 400 900` — это не «примерно», а вся
 * запрошенная ось целиком, включая 600 и 700, за 96 КБ на четыре подмножества.
 * `unicode-range` — дословно из ответа Google: без него браузер тянет латиницу
 * ради страницы, на которой нет ни одной латинской буквы.
 */

@font-face {
  font-family: 'Golos Text';
  font-style: normal;
  font-weight: 400 900;
  /* Данные важнее буквиц: до загрузки текст читается запасной гарнитурой. */
  font-display: swap;
  src: url('fonts/GolosText-cyrillic-ext.woff2') format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Golos Text';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url('fonts/GolosText-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Golos Text';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url('fonts/GolosText-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
    U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
    U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Golos Text';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url('fonts/GolosText-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
    U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/*
 * ALSTrigger И ALSPofo — БИНАРНИКИ ПРИЕХАЛИ 2026-09-30.
 *
 * Слот под ALSTrigger стоял здесь выключенным с 2026-08-11: гарнитура была
 * согласована письменно, а файлов не было, и живой `@font-face` на
 * несуществующий файл давал бы красную строку 404 на каждой загрузке каждого
 * экрана. Владелец прислал два семейства — `ALSTriggerLuzhniki` (собственная
 * резка для Лужников) и `ALS Pofo`, — и слот включён.
 *
 * ВЕСА ВЗЯТЫ ПО НАЗНАЧЕНИЮ, А НЕ ВСЕ ПОДРЯД. Владелец назвал четыре роли:
 * название клуба — Trigger Bold, имя спортсмена — Trigger Black, рубрика
 * таблицы — Trigger Black, пояснение — Pofo Bold. Это ровно три файла из
 * двенадцати присланных; остальные девять лежат исходниками в
 * `design/brand/fonts/` и в раздачу не попадают: вес, который никто не зовёт,
 * — это килобайты на каждой загрузке киоска и ещё одна вещь, которую придётся
 * держать в голове.
 *
 * ИСХОДНИКИ ХРАНЯТСЯ. `.otf` и `.ttf` целиком лежат в `design/brand/fonts/`:
 * из woff2 обратно полноценный шрифт не собрать, а следующий вес однажды
 * понадобится.
 *
 * ЦИФРЫ ЭТОТ СЛОТ НЕ ТРОГАЕТ. Время сравнивают по столбцу, и `--num` остаётся
 * Golos Text. У Trigger табличные цифры есть (`tnum`), у Pofo их НЕТ — только
 * пропорциональные (`pnum`), проверено по самим файлам. Поэтому Pofo набирает
 * пояснения, а не числа.
 */
@font-face {
  font-family: 'ALSTrigger';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('fonts/ALSTrigger-700.woff2') format('woff2');
}
@font-face {
  font-family: 'ALSTrigger';
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url('fonts/ALSTrigger-900.woff2') format('woff2');
}
@font-face {
  font-family: 'ALSPofo';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('fonts/ALSPofo-700.woff2') format('woff2');
}

/*
 * Запасная гарнитура с выправленными метриками.
 *
 * `font-display: swap` означает, что первые доли секунды страница набрана НЕ
 * Golos Text, а потом перенабирается им. Без выправления метрик этот момент
 * дёргает таблицы: строки меняют высоту, колонка времени прыгает по ширине — на
 * табло это выглядит как сбой панели, а в консоли уводит строку из-под пальца
 * оператора ровно тогда, когда он в неё целится (движение под пальцем запрещено
 * design/README.md).
 *
 * Числа ИЗМЕРЕНЫ по самим файлам (fontTools), а не взяты на глаз:
 *   Golos Text  upm 1000, ascent 980, descent −220, lineGap 0;
 *               средняя ширина строчной латиницы 0.545em, кириллицы 0.615em
 *   Arial       upm 2048; те же средние — 0.490em и 0.578em
 * Отношение ширин: 1.114 на латинице и цифрах, 1.064 на кириллице. Взято 107% —
 * между ними, ближе к кириллице: ширину таблиц задаёт колонка фамилий.
 * Вертикальные метрики делятся на size-adjust, потому что он масштабирует и их:
 * 98% / 1.07 = 91.6%, 22% / 1.07 = 20.6%.
 */
@font-face {
  font-family: 'Golos Fallback';
  /* Только локальные метрически предсказуемые гротески. Не нашлось ни одного —
     объявление не загрузится, и стек спокойно уедет на system-ui. */
  src: local('Arial'), local('Helvetica'), local('Liberation Sans');
  size-adjust: 107%;
  ascent-override: 91.6%;
  descent-override: 20.6%;
  line-gap-override: 0%;
}

:root {
  /* ------------------------------------------------------------------ бренд */
  --brand-red: #e53d4f;
  --brand-navy: #003e7c;
  --brand-navy-deep: #031b30;

  /* Медальные — те же, что на публичном сайте: золото значит золото и там и тут. */
  --gold: #ffcf4a;
  --silver: #c9d3df;
  --bronze: #e0975a;

  /* ------------------------------------------------------------ типографика */
  /*
   * ALSTrigger ЗДЕСЬ БОЛЬШЕ НЕ СТОИТ — и это решение, а не недосмотр.
   *
   * Прежняя редакция держала его первым в общем `--font-display`, чтобы
   * «заголовки системы сменили голос без единой другой правки». В день, когда
   * файлы приехали, эта правка сменила бы голос и КОНСОЛИ ОПЕРАТОРА — а
   * владелец просил про мониторы (2026-09-30). Консоль набрана заодно с
   * публичным сайтом намеренно (design/README.md, решение 2): оператор весь
   * день показывает посетителю сайт, и две светлые поверхности живут одной
   * типографикой. Молча развести их — значит отменить это решение походя.
   *
   * Поэтому Trigger подключается ТОЛЬКО в теме табло, ниже. Захотят его в
   * консоли — это отдельная просьба и одна строка здесь.
   *
   * 'Golos Fallback' — тот же system-ui, но с метриками Golos Text: он держит
   * геометрию те доли секунды, пока настоящий шрифт ещё едет.
   */
  --font-display: 'Golos Text', 'Golos Fallback', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-text: 'Golos Text', 'Golos Fallback', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  /* Пояснения на табло. В светлых темах слот не зовут — там его нет. */
  --font-note: 'Golos Text', 'Golos Fallback', system-ui, sans-serif;

  /* Время сравнивают глазом по столбцу — только табличные цифры. Гарнитура та
     же, что у текста: «один голос числа» — время на сайте, на табло и в консоли
     набрано одним шрифтом, а не тремя разными. */
  --num: 'Golos Text', 'Golos Fallback', system-ui, sans-serif;
  --num-feat: tabular-nums lining-nums;

  --eyebrow-size: 13px;
  --eyebrow-track: 0.16em;

  /* --------------------------------------------------------------- движение */
  /* Дольше — уже заметно как задержка; под пальцем оператора ничего не ездит. */
  --t-fast: 90ms;
  --t: 140ms;

  /* ------------------------------------------------------------------ фокус */
  /* Никогда не смысловой цвет: иначе кнопка в фокусе читается как «бежит». */
  --focus: var(--brand-navy);
  --focus-halo: rgba(0, 62, 124, 0.35);
}

/* ============================================================== ТАБЛО АРЕНЫ ==
 * Тёмная тема. Эмиссивная панель 50″ в манеже: белое поле слепит и убивает
 * контраст соседних строк, поэтому асфальт под светящейся цифрой.
 */
.theme-board {
  --board-bg: #0a0c10;          /* асфальт */
  --board-bg-2: #12161d;        /* полоса дорожки — чередование строк */
  --board-fg: #f4f8fb;
  --board-mut: #94a3b4;
  --board-line: #1e2733;

  --run: #46e08a;               /* бежит сейчас — часы и метка */
  --pb: var(--gold);            /* личный рекорд */
  --miss: #ffb02e;              /* мат не увидел отсечку */
  --finish: var(--brand-red);   /* финишная черта — ровно одна на экран */

  --alarm-bg: #ffb02e;          /* нет связи: плашка во всю ширину */
  --alarm-fg: #160c00;

  /*
   * Надзаголовок на табло крупнее, чем в консоли, и это не вкус.
   * Собственный пол проекта — «минимум 18 px абсолютных» (design/ux.md,
   * «Плотность»), а 13 px, унаследованные от референса, на панели 50″ в манеже
   * дают семь миллиметров: с десяти метров «СЕЙЧАС НА ДОРОЖКЕ» просто не
   * существует, и таблица результатов начинается без заголовка.
   * `max()`, а не голые vh: на 720p 1.8vh = 13 px, то есть ровно та же дыра.
   */
  --eyebrow-size: max(18px, 1.8vh);

  /*
   * ГОЛОС ТАБЛО — ПРИСЛАННЫЕ ГАРНИТУРЫ, И ТОЛЬКО ЗДЕСЬ (владелец 2026-09-30).
   *
   * Четыре роли названы им дословно: название клуба — Trigger Bold, имя
   * спортсмена — Trigger Black, рубрика таблицы — Trigger Black при 50 %
   * прозрачности, пояснение — Pofo Bold. Роли разведены по селекторам в
   * `public/display/live.html`; здесь — только семейства.
   *
   * `--num` не переопределяется: цифры остаются Golos Text, потому что их
   * сравнивают по столбцу, а табличных цифр у Pofo нет вовсе.
   */
  --font-display: 'ALSTrigger', 'Golos Text', 'Golos Fallback', system-ui, sans-serif;
  --font-note: 'ALSPofo', 'Golos Text', 'Golos Fallback', system-ui, sans-serif;

  color: var(--board-fg);
  background:
    /* Единственный градиент в системе, и он не украшение: гасит бандинг
       восьмибитных панелей на большой заливке. */
    radial-gradient(1200px 600px at 50% -10%, #131a25 0%, var(--board-bg) 60%);
  font-family: var(--font-text);
}

/* ========================================================= КОНСОЛЬ ОПЕРАТОРА ==
 * Светлая тема. Смена за столом при верхнем свете, и оператор постоянно
 * показывает посетителю публичный сайт — две светлые поверхности с одной
 * типографикой вместо переключения глаза между тёмным и светлым.
 */
.theme-desk {
  --desk-bg: #ffffff;
  --desk-surface: #f6f6f6;      /* та же ступень, что на публичном сайте */
  --desk-surface-2: #efefef;
  --desk-line: #e2e2e2;
  --desk-line-strong: #c9c9c9;

  --desk-text: #0b0b0c;
  --desk-mut: #5b6068;          /* 6.4:1 — проходит AA для текста */
  --desk-faint: #767c85;        /* 4.6:1 — нижняя граница, не мельче 14px */

  /* Личный рекорд на светлой поверхности. То же затемнённое золото, что
     --c-gold публичного сайта (4.92:1 на белом): зритель ходит глазами между
     консолью у стойки и телефоном, и золото обязано означать золото в обоих
     местах. Светлое --gold здесь запрещено — на белом оно 1.4:1, то есть
     невидимо. Значение продублировано из landing/design/tokens.css сознательно
     (два контура сборки); синхронность двух копий держит тест AC-K494. */
  --pb: #8a6d00;

  --ok: #067647;                /* принято, на дорожке */
  --ok-bg: #e7f6ee;
  --warn: #8a5a00;              /* внимание: отсечки нет, чип потерян */
  --warn-bg: #fff6e3;
  --danger: #9a2c2c;            /* отклонено, ошибка */
  --danger-bg: #fdeceb;
  --accent: var(--brand-navy);  /* действие по умолчанию */
  --accent-bg: #e8f0f8;

  color: var(--desk-text);
  background: var(--desk-bg);
  font-family: var(--font-text);
}

/* ================================================================== ОБЩЕЕ == */

/* Надзаголовок — голос референса: широкий трекинг, uppercase, мелкий кегль. */
.eyebrow {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: var(--eyebrow-size);
  letter-spacing: var(--eyebrow-track);
  text-transform: uppercase;
}

/* Любое время. Табличные цифры — не украшение: столбец читают сверху вниз. */
.num {
  font-family: var(--num);
  font-variant-numeric: var(--num-feat);
  font-feature-settings: 'tnum' 1, 'lnum' 1;
}

/* Полоса дорожки: жёсткая левая кромка вместо скругления и тени. */
.lane {
  border-left: 3px solid transparent;
}
.lane[data-active] {
  border-left-color: var(--finish, var(--accent));
}

/* Финишная черта. Ровно одна на экран, поэтому это модификатор, а не утилита. */
.finish-rule {
  border: 0;
  border-top: 2px solid var(--finish, var(--brand-red));
}

*:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px var(--focus-halo);
}

/*
 * Атрибут hidden обязан побеждать ЛЮБОЙ display из классов.
 *
 * UA-правило `[hidden] { display: none }` проигрывает любому авторскому
 * объявлению display вне зависимости от специфичности — так скрытое поле типа
 * чипа (`#typeBox`, класс .row с display:flex) стояло видимым на консоли всегда,
 * а его комментарий обещал «скрытый элемент браузер не фокусирует, и скан в
 * него физически не попадёт». jsdom-тесты этого не видят: они читают свойство
 * hidden, а не каскад. !important здесь — не лень, а сам смысл правила:
 * перекрыть авторский display закрытого элемента.
 */
[hidden] {
  display: none !important;
}

/* Человек, который выключил анимацию, выключил её и здесь. */
@media (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
  }
}
