/* base.css - единая основа UI Controller32: вшитые шрифты, токены :root, ресет, keyframes.
   Один источник для всех экранов и kitchen-sink. Токены пришли из design/Controller32.dc.html,
   но с тех пор база развёрнута в тёплый тон - разбор прямо над блоком :root. */

/* Шрифты вшиты локально (self-host, без Google Fonts): клиент офлайн. */
@font-face{font-family:'Onest';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/onest-cyrillic-400.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'Onest';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/onest-latin-400.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215}
@font-face{font-family:'Onest';font-style:normal;font-weight:500;font-display:swap;src:url('fonts/onest-cyrillic-500.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'Onest';font-style:normal;font-weight:500;font-display:swap;src:url('fonts/onest-latin-500.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215}
@font-face{font-family:'Onest';font-style:normal;font-weight:600;font-display:swap;src:url('fonts/onest-cyrillic-600.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'Onest';font-style:normal;font-weight:600;font-display:swap;src:url('fonts/onest-latin-600.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215}
@font-face{font-family:'Onest';font-style:normal;font-weight:700;font-display:swap;src:url('fonts/onest-cyrillic-700.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'Onest';font-style:normal;font-weight:700;font-display:swap;src:url('fonts/onest-latin-700.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215}
@font-face{font-family:'Onest';font-style:normal;font-weight:800;font-display:swap;src:url('fonts/onest-cyrillic-800.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'Onest';font-style:normal;font-weight:800;font-display:swap;src:url('fonts/onest-latin-800.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/jbmono-cyrillic-400.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/jbmono-latin-400.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:500;font-display:swap;src:url('fonts/jbmono-cyrillic-500.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:500;font-display:swap;src:url('fonts/jbmono-latin-500.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:600;font-display:swap;src:url('fonts/jbmono-cyrillic-600.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:600;font-display:swap;src:url('fonts/jbmono-latin-600.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215}

/* Токены дизайна.

   БАЗА ТЁПЛАЯ, А НЕ СИНЕ-СЕРАЯ. Прежние поверхности были холодными (в каждом значении синего
   больше, чем красного: #121415 это R18 G20 B21). На таком фоне единственные тёплые цвета
   кабинета - «внимание» и «беда» - выглядели инородными наклейками, а зелёный акцент уходил в
   бирюзу и спорил с фоном. Вся нейтраль развёрнута в коричневато-чёрный: R > G > B.

   СВЕТЛОТА СОХРАНЕНА С ТОЧНОСТЬЮ ДО ТРЕТЬЕГО ЗНАКА. Каждое значение подобрано так, чтобы
   относительная яркость по WCAG совпала со старой: ступени поверхностей стоят там же, где
   стояли, и ни один контраст текста не просел от смены тона. Считано, а не на глаз.

   ТРИ ЗНАЧЕНИЯ ПОДНЯТЫ НАМЕРЕННО, потому что не дотягивали до 4.5:1 и до поворота тона:
   --text-off и --term-dim (было 4.30 на --surface-4, стало 4.70), --accent2-dim (было 4.34,
   стало 4.83) и --disabled (погашенная кнопка была СВЕТЛЕЕ самой светлой поверхности - теперь
   она ниже уровня --chip и текст на ней читается). Полная таблица замеров - в отчёте ветки. */
:root{
  /* поверхности */
  --canvas:#121415; --rail:#17191B; --surface:#1B1E20; --surface-2:#1E2123;
  --surface-3:#212527; --surface-4:#24282A; --terminal:#16191B; --chip:#272B2D;
  --btn:#222629; --btn-2:#191F21; --disabled:#2B2E30; --toggle-off:#3E4245;
  --stripe:#202325; --dots:#262A2C;
  /* ЛЕСТНИЦА ВЛОЖЕННОСТИ. Ступеней было пять, и верхняя упиралась в --surface-4: плашка внутри
     плашки внутри карточки красилась тем же, чем сама карточка, и три уровня вложенности
     сливались в один прямоугольник. Добавлены две ступени вверх и одна вниз.

     Шаг между рабочими рунгами 3.3 по L* (CIE Lab). Это больше порога различимости на большой
     заливке тёмного экрана (около 2) и заметно меньше того, на чём поверхность начинает читаться
     как чужая. Замер, а не глазомер:

       --surface-0   4.45   паз: врезка ВНУТРЬ, ниже холста (жёлоб полосы, поле, лог)
       --canvas      6.19   фон страницы
       --rail        8.64   рейка и шапка
       --surface    11.03   вложенность 1: карточка на фоне
       --surface-2  12.51   полуступень: шапка секции, тихая плашка
       --surface-3  14.34   вложенность 2: плашка в карточке, наведение на карточку
       --surface-4  15.77   полуступень: слабое наведение
       --surface-5  17.67   вложенность 3: плашка в плашке, наведение на плашку
       --surface-6  19.64   вложенность 4 и наведение на неё

     ПОТОЛОК ЧИТАЕМОСТИ У ВЕРХНИХ СТУПЕНЕЙ. Чем светлее заливка, тем меньше тихого текста на ней
     живёт. Считано по всей таблице: на --surface-5 самый тихий допустимый текст это --text-mono
     (4.92:1), на --surface-6 это --text-dim (5.07:1). --text-faint (4.36 на -6) и --text-off
     (4.45 на -5) туда ставить нельзя. Правилом, а не подгонкой цвета: поднимать --text-off ещё
     раз значит стирать разницу между «тихо» и «совсем тихо».

     Заодно замер нашёл старую пару, которая до порога не дотягивала и раньше: --accent-dim
     (4.46 на --surface-4, 4.28 на --chip). Значение не тронуто, потому что живёт оно ровно в
     одном месте (.onb-step в shell.css) и лежит там на --surface, где даёт 5.02. Его потолок
     это --surface-3. Третий потолок: --accent2-dim (надзаголовки .plate__lab, .pulse__lab,
     .tbl__head) держится до --surface-5 (4.57) и проваливается на --surface-6 (4.31) - то есть
     надзаголовок нельзя ставить на плашку третьего уровня ПОД КУРСОРОМ.

     ЧТО В ЭТОЙ ТАБЛИЦЕ НЕ ТЕКСТ И ПОТОМУ ПОРОГ 4.5 К НЕМУ НЕ ОТНОСИТСЯ, чтобы следующий замер
     не начал «чинить» исправное: --nd (точка чипа), --accent2-deep (полоса пустого состояния),
     --chart-2 и --chart-6 (линия ряда и ключ легенды). Для них порог 3:1, как для графики, и
     все четыре его держат с запасом: 3.81, 4.00, 5.05, 4.27 на --surface. */
  --surface-0:#0D1011; --surface-5:#282C2E; --surface-6:#2D3032;
  /* границы */
  --line:#2A2E30; --line-soft:#26292B; --line-row:#232628; --line-mid:#2E3234;
  --line-strong:#333739; --line-btn:#383C3F; --line-input:#43474A; --line-hover:#4B4F52;
  --edge:#404447;
  /* текст */
  --text:#ECEEED; --text-2:#D7DAD9; --text-3:#CBCFCE; --text-muted:#ADB2B0;
  --text-dim:#9CA1A0; --text-mono:#949A98; --text-faint:#8A908E; --text-off:#868B89;
  --term-dim:#868D8A;
  /* акцент: тот же зелёный продукта, повёрнутый на 6.5 градуса от бирюзы к траве, чтобы он
     сидел на тёплой базе, а не спорил с ней. Светлота не тронута. */
  --accent:#6FB79C; --accent-hover:#82C6AC; --accent-soft:#A3C9B9; --accent-soft-2:#B4D3C7;
  --accent-deep:#4E8871; --accent-num:#8FBCA6; --on-mark:#F2F5F4; --accent-deeper:#33574A; --accent-dim:#7E918A; --on-accent:#0D1714;
  /* ЛЕСЕНКА АКЦЕНТА: ОДИН ЦВЕТ, ДВЕНАДЦАТЬ СТУПЕНЕЙ.

     Владелец попросил сохранить цвет логотипа и добавить оттенков. Это ровно одно решение: тон
     НЕ трогаем, разворачиваем светлоту. Раньше зелёного было по сути два значения - сам акцент и
     его наведение, - и любой блок, которому нужен был третий зелёный (заливка чипа, граница
     плашки, тихая цифра), брал либо тот же акцент, либо серый. Отсюда «плоско»: одним цветом
     нельзя показать глубину.

     ТОН ДЕРЖИТСЯ НА 151 ГРАДУСЕ НА ВСЕХ ДВЕНАДЦАТИ СТУПЕНЯХ - это тот же зелёный логотипа, что
     в --accent. Меняются только светлота и насыщенность. Шесть ступеней из двенадцати это уже
     живущие в продукте токены, и значения у них байт в байт те же, а не «примерно такие»:
     04 = --accent-deeper, 06 = --accent-deep, 08 = --accent, 09 = --accent-hover,
     10 = --accent-soft, 11 = --accent-soft-2. Новых значений шесть: 01, 02, 03, 05, 07, 12.

     Номер двузначный намеренно: --accent-02 нельзя спутать с --accent2, а это ДРУГОЙ цвет
     (синий второй акцент). Однозначный номер такую опечатку прощал бы молча.

     Роли по ступеням (L* в скобках, контраст замерен и лежит в отчёте ветки):
       01 (9.8)  #101E17  самая глубокая заливка: подложка чипа на светлой плашке
       02 (16.5) #182D23  заливка блока, рейка таблицы
       03 (23.8) #233E31  граница спокойного блока
       04 (33.9) #335746  граница выделенного блока, разделитель
       05 (43.1) #416F59  граница на наведении, ось графика
       06 (52.2) #4E886B  нажатая кнопка, тёмная заливка полосы
       07 (61.8) #58A47F  вторая линия графика того же ряда, тихая полоса
       ---- ниже этой черты ступени только для ЗАЛИВОК И ЛИНИЙ, текст начинается с 08 ----
       08 (69.0) #6FB794  САМ АКЦЕНТ: кнопка, точка состояния, ссылка
       09 (74.7) #82C6A5  наведение на кнопку
       10 (77.9) #A3C9B5  надпись состояния на тёмном
       11 (82.0) #B4D3C4  крупное число, заголовок с акцентом
       12 (89.3) #CEE6DA  текст поверх тёмных заливок 01-04

     КАКОЙ КРАСКОЙ ПИСАТЬ ПОВЕРХ ЗАЛИВКИ - НЕ ВКУС, А ЗАМЕР. Строчка «текст поверх 04-08» тут
     стояла раньше и была неправдой: --accent-12 на ступени 05 даёт 4.38, на 06 - 3.15, на 08 -
     1.80, то есть надпись по этому правилу пропадала бы ровно там, где заливка ярче всего.
     Правило считано по всем ступеням и звучит так:

       01-04  светлая краска: --accent-12 (13.08 / 11.09 / 8.84 / 6.15), --accent-11, --text.
              --accent-10 доходит только до 03 (6.42), на 04 у неё уже 4.47.
       05     пограничная: проходит ТОЛЬКО --text (4.95). Светлые ступени акцента - нет.
       06-09  тёмная краска --on-accent: 4.57 / 6.41 / 8.02 / 9.55.

     Ради нижней строчки этого правила --on-accent пришлось опустить с #0D1713 до #0A120F: на
     ступени 06 (это --accent-deep, фон НАЖАТОЙ основной кнопки) старое значение давало 4.40,
     то есть подпись на кнопке под пальцем формально не читалась. На всех остальных ступенях
     правка только прибавила запас. */
  --accent-01:#0F1E18; --accent-02:#162D25; --accent-03:#213E33; --accent-04:#305748;
  --accent-05:#3D6F5D; --accent-06:#468971; --accent-07:#4EA587; --accent-08:#68B89B;
  --accent-09:#7CC7AB; --accent-10:#A0C9B8; --accent-11:#B2D3C5; --accent-12:#CDE6DB;
  /* ВТОРОЙ АКЦЕНТ. Один акцент на весь продукт делал кабинет монотонным: всё, что не «хорошо»,
     «внимание» или «беда», оставалось серым - заголовки разделов, подписи колонок, вкладки,
     пустые состояния. Цвет в таком интерфейсе значит только тревогу, а спокойных акцентов нет
     вовсе, и экран читается как сплошная серая плита.
     Взят прохладный синий: он не спорит с зелёным (тот остаётся брендом и «всё хорошо») и,
     главное, НЕ ПУТАЕТСЯ с жёлтым «внимание» и красным «беда». Тёплый второй акцент тут был бы
     невозможен по этой же причине. Он несмысловой намеренно: им подсвечивают структуру, а не
     состояние. Оттенок отведён от фиолетового к чистому синему: на тёплой базе сиреневый читался
     как ещё одно состояние, а он не состояние. */
  --accent2:#8E9BE0; --accent2-soft:#AAB4E9; --accent2-deep:#6470B8; --accent2-dim:#7A83B5;
  --accent2-line:#3B4166; --accent2-ghost:rgba(142,165,224,0.10); --accent2-tint:rgba(142,165,224,0.055);
  --link-hover:#8AEACB; --accent-line:#40564D; --accent-line-2:#37483F;
  --accent-line-dashed:#3C4B45; --accent-line-hover:#4E645C;
  --accent-ghost:rgba(111,183,148,0.10); --accent-ghost-hover:rgba(111,183,148,0.19);
  --nav-active:rgba(111,183,148,0.11);
  /* статусы. У каждого три роли: --X сам цвет (точка, рейка, иконка), --X-text надпись,
     --X-tint подложка карточки. Плюс --X-glow - мягкое свечение изнутри для блока, который
     обязан быть замечен первым (см. .is-lit в ui.css).

     МИНИ-ШКАЛА ЗАЛИВКИ У КАЖДОГО СОСТОЯНИЯ. Заливок было две с половиной, и на них приходилось
     четыре разные работы: полоса в строке таблицы, подложка карточки, чип, наведение. Строка
     таблицы брала подложку карточки и получалась такой же тяжёлой, как карточка, а наведение на
     цветную строку вообще нечем было показать - брали серый и тон терялся под курсором.

     Теперь у всех пяти состояний одна и та же лесенка из четырёх ступеней, и она читается как
     нарастание тревоги, а не как четыре разных решения:

       --X-wash  ~0.03  полоса в строке списка: цвет угадывается, текст не тонет
       --X-tint  ~0.06  подложка карточки: тон виден с другого конца комнаты
       --X-bg    ~0.13  чип и иконка: самое плотное, что бывает на маленькой площади
       --X-hot   ~0.09  наведение: на ступень плотнее подложки, тон не подменяется серым

     ВЕРХ ЛЕСЕНКИ ОГРАНИЧЕН НЕ ВКУСОМ, А ЗАМЕРОМ. Наведение хотелось сделать вдвое плотнее
     подложки, но на такой заливке ломается самый тихий текст, который на строках живёт:
     --text-off даёт 3.6:1, --text-faint 3.9, --accent2-dim 3.8. Предел посчитан перебором:
     0.09 для «нормы», «внимания» и «к сведению», 0.105 для «беды», 0.075 для незнания - на них
     --text-off держит 4.50-4.54 (при 0.11 у «беды» выходило 4.49, то есть ниже порога). Дальше поднимать нельзя, поэтому вторую половину работы
     делает граница: --X-line-hot светлеет заметно, и наведение видно даже там, где заливка
     прибавила всего один L* (у «внимания» так и есть: 15.9 -> 17.0).

     ПОТОЛОК КРАСКИ НА САМОЙ ПЛОТНОЙ СТУПЕНИ. Замер по всем пяти состояниям: на --X-bg (чип)
     тихие краски уже не держат порог - --text-off даёт 4.10-4.27, --text-faint 4.26-4.44,
     --accent2-dim 4.22-4.39. Поэтому на заливке чипа допустимы только своя надпись состояния
     (--X-text, 5.43-7.36) и --text-muted (6.05-6.76), а на wash/tint/hot читается всё, вплоть
     до --text-off (4.51-5.05).

     Плюс --X-line-hot - граница того же блока под курсором. Считано как цвет состояния при
     альфе 0.34 над --surface: у «беды» это ровно тот --risk-line-strong, что уже жил в наборе,
     остальные четыре теперь ведут себя так же. */
  --ok:#6FB79C; --ok-text:#A3C9B9; --ok-bg:rgba(111,183,148,0.13);
  --ok-tint:rgba(111,183,148,0.06); --ok-icon:rgba(111,183,148,0.15); --ok-line:#37483F;
  --ok-glow:rgba(111,183,148,0);
  --ok-wash:rgba(111,183,148,0.03); --ok-hot:rgba(111,183,148,0.09); --ok-line-hot:#3B5144;
  --warn:#C2A578; --warn-text:#D2BC98; --warn-bg:rgba(194,165,120,0.14);
  --warn-tint:rgba(194,165,120,0.07); --warn-icon:rgba(194,165,120,0.15); --warn-line:#3A342A;
  --warn-glow:rgba(194,165,120,0.10);
  --warn-wash:rgba(194,165,120,0.035); --warn-hot:rgba(194,165,120,0.09); --warn-line-hot:#574B3B;
  --risk:#C9857A; --risk-text:#D9A096; --risk-bg:rgba(201,133,122,0.14);
  --risk-tint:rgba(201,133,122,0.07); --risk-icon:rgba(201,133,122,0.16);
  --risk-ghost:rgba(201,133,122,0.09); --risk-ghost-hover:rgba(201,133,122,0.18);
  --risk-line:#3A302E; --risk-line-strong:#59403C; --risk-glow:rgba(201,133,122,0.18);
  --risk-wash:rgba(201,133,122,0.035); --risk-hot:rgba(201,133,122,0.105);
  --risk-line-hot:var(--risk-line-strong);
  --info:#9BB0C0; --info-text:#9BB0C0; --info-bg:rgba(155,176,192,0.13); --info-line:#3A4548;
  /* «К сведению» было половиной состояния: цвет, надпись и чип есть, а покрасить им карточку
     нечем - ни подложки, ни свечения, ни гнезда. Из-за этого .tone-info в ui.css не существовало
     вовсе, и блок «это не поломка, просто знайте» приходилось красить либо жёлтым (врёт про
     тревогу), либо никак (тонет). Дописаны те же роли, что у остальных четырёх. */
  --info-wash:rgba(155,176,192,0.03); --info-tint:rgba(155,176,192,0.06);
  --info-hot:rgba(155,176,192,0.09); --info-icon:rgba(155,176,192,0.15);
  --info-glow:rgba(155,176,192,0.06); --info-line-hot:#4A4F53;
  /* ПОЛОВИННОЕ СВЕЧЕНИЕ ДЛЯ ФОНОВОГО ТОНА. Свет несёт смысл силой, но когда светится КАЖДАЯ
     тонированная плашка в полную силу, смысл теряется обратно: на Главной два пятна 720x480 и
     720x365 залили треть экрана, и очередь читалась одним бурым мазком - граница между группой
     одной ноды и группой другой размывалась. Замер критика, не рассуждение.
     Поэтому тон светится ВПОЛСИЛЫ сам по себе (лестница цела: норма и незнание не светятся
     вовсе), а .is-lit возвращает полную - им экран помечает ГЛАВНЫЙ блок, и тот снова виден
     раньше соседа. */
  --ok-glow-soft:rgba(111,183,148,0);
  --warn-glow-soft:rgba(194,165,120,0.05);
  --risk-glow-soft:rgba(201,133,122,0.09);
  --info-glow-soft:rgba(155,176,192,0.03);
  /* ПЯТОЕ СОСТОЯНИЕ: НЕЗНАНИЕ. Состояний было четыре, и все четыре - утверждения: «в норме»,
     «внимание», «есть авария», «к сведению». Пятое встречается в кабинете постоянно и ни одним
     из них не является: «Заблокировано IP - агент CrowdSec не подключён», «Egress Guard - нет
     данных», «WARP - нет данных». До этого такой блок весил ровно столько же, сколько живой
     показатель, и владелец читал четыре одинаково громкие плитки, две из которых не измерялись.

     Незнание - НЕ норма (мы не знаем, работает ли) и НЕ отказ (ничего не сломалось). Поэтому у
     него нет своего цвета: только тёплый серый, тише любого статуса, и оформление, которое
     ЛЕГЧЕ живого - подложка ниже уровня карточки и пунктирная граница (.tone-nd в ui.css). */
  /* --nd-text поднят с #A09A97 на одну ступень (L* 64.0 -> 65.1). Причина ровно та же, по
     которой в прошлый раз поднимали --text-off: с появлением ступени --surface-5 чип «нет
     данных» на плашке третьего уровня давал 4.40:1 и стал единственной парой ниже порога.
     Прибавка в один L* незаметна глазом и не трогает главное свойство незнания: оно осталось
     на 7.0 по L* тише --text-muted, то есть по-прежнему тише любого факта. */
  --nd:#757979; --nd-text:#9A9F9E; --nd-line:#292D2F;
  --nd-bg:rgba(152,144,140,0.10); --nd-tint:rgba(152,144,140,0.035); --nd-icon:rgba(152,144,140,0.09);
  /* У незнания та же лесенка, но вся она тише: даже наведение на строку «нет данных» не имеет
     права выглядеть плотнее, чем подложка живого показателя. */
  --nd-wash:rgba(152,144,140,0.018); --nd-hot:rgba(152,144,140,0.075); --nd-line-hot:#36393C; --nd-glow:transparent;
  /* ПЯТАЯ СТУПЕНЬ ЗАЛИВКИ: ПЛАШКА ДЕЛА. Строка списка красится ЦЕЛИКОМ, а не рейкой слева.

     Владелец прислал снимок очереди и сказал дословно: «мне не нравятся все таблицы где просто
     слева красный жёлтый или зелёный, сделай более полноценно то есть прямо всю плашку цветом и
     более понятно что не так». Он прав по замеру, а не только по вкусу: рейка шириной 3px это
     0.4% площади строки, и заметить её можно, только если заранее знаешь, куда смотреть. Сама
     строка при этом брала --X-wash (0.03), то есть отличалась от спокойной соседки в 1.06 раза -
     на глаз никак.

     ГРОМКОСТЬ СТУПЕНИ РАВНА ТЯЖЕСТИ ДЕЛА, И ЭТО ГЛАВНОЕ ЗДЕСЬ. Одно значение на все пять
     состояний дало бы светофор: двадцать одинаково громких строк не выделяют ни одной, и экран
     стало бы читать ТРУДНЕЕ, чем с рейкой. Поэтому ступень повторяет ту же лестницу, по которой
     уже расставлено свечение: норма и незнание почти не красятся, авария красится в полную силу.

       незнание    0.045   тише нормы: мы не знаем, а не «всё хорошо»
       норма       0.05    едва тёплый оттенок, спокойная строка остаётся спокойной
       к сведению  0.08    тон угадывается, тревоги не заявляет
       внимание    0.115   видно боковым зрением
       авария      0.175   видно первым, до чтения слов

     СКОЛЬКО ЭТО НА ГЛАЗ. Отношение яркостей плашки и спокойной строки: авария 1.310, внимание
     1.224, к сведению 1.152, норма 1.085, незнание 1.063. Для сравнения: вся лестница
     вложенности от --surface до --surface-6 это 1.261. То есть авария теперь отличается от
     спокойной строки СИЛЬНЕЕ, чем самая глубокая плашка кабинета отличается от карточки.

     ШАГ МЕЖДУ АВАРИЕЙ И ВНИМАНИЕМ ТОЖЕ ЗАМЕРЕН. Первый подбор дал 0.155 и 0.13 - обе плашки
     выходили одинаково бурыми, расстояние между их цветами 6.0 из 255. Разведены до 0.175 и
     0.115: расстояние 12.8, то есть вдвое. Меньше нельзя - иначе «просит внимания» и «авария»
     на ленте различаются только силуэтом точки, а он размером с ноготь.

     ПОТОЛОК ПОСЧИТАН ПЕРЕБОРОМ, А НЕ УГАДАН. Заливка светлеет, значит съедает контраст текста.
     На плашке и на её наведении держат порог 4.5:1 только краски не тише --text-dim:
       авария    --text 10.41  --text-2 8.62  --text-muted 5.64  --text-dim 4.63  --text-mono 4.24
       внимание  --text 10.95  --text-2 9.07  --text-muted 5.94  --text-dim 4.87  --text-mono 4.46
     (числа сняты на самой громкой ступени - наведении). Отсюда правило, записанное в ui.css:
     НА ПЛАШКЕ ДЕЛА САМАЯ ТИХАЯ КРАСКА ЭТО --text-dim. Всё, что тише (--text-mono, --text-faint
     3.73, --text-off 3.50, --accent2-dim 3.32), на плашке берёт голос состояния --X-text: он и
     читается лучше (5.44-8.17), и связывает строку в один цветной объект.

     И ПОДЛОЖКА ПЛАШКИ НЕ ИМЕЕТ ПРАВА СВЕТЛЕТЬ ПОД КУРСОРОМ. Наведение на строку таблицы ставило
     background-color:var(--surface-3); сложенное с заливкой аварии, это давало --text-dim 4.27 -
     единственную пару ниже порога во всём наборе. Тонированная строка держит своей базой
     --surface (ui.css, раздел 4), а курсор усиливает ТОН, а не подкладывает серую ступень.

     ЦВЕТ ОСТАЁТСЯ ВТОРЫМ ПРИЗНАКОМ. Силуэт состояния (круг, треугольник, квадрат) никуда не
     делся: в сером измерении норма и внимание отличаются в 1.02 раза, и заливка этого не чинит. */
  --ok-plate:rgba(111,183,148,0.05); --ok-plate-hot:rgba(111,183,148,0.075);
  --warn-plate:rgba(194,165,120,0.115); --warn-plate-hot:rgba(194,165,120,0.15);
  --risk-plate:rgba(201,133,122,0.175); --risk-plate-hot:rgba(201,133,122,0.205);
  --info-plate:rgba(155,176,192,0.08); --info-plate-hot:rgba(155,176,192,0.11);
  --nd-plate:rgba(152,144,140,0.045); --nd-plate-hot:rgba(152,144,140,0.07);
  /* СВЕЧЕНИЕ ИЗНУТРИ: СИЛА СВЕТА НЕСЁТ СМЫСЛ, А НЕ КРАСОТУ.

     Плашка была плоской заливкой с границей, и состояние на ней читалось наклейкой, а не
     свойством самого блока. Свечение делает вид, что источник света стоит ВНУТРИ карточки, в
     том углу, где сидит метка состояния, и оттуда мягко разливается по подложке.

     Это НЕ стекло и НЕ размытие: ни blur, ни полупрозрачных поверхностей тут нет вовсе. Слой -
     обычный радиальный градиент цветом состояния, положенный ПОВЕРХ непрозрачной подложки.

     ЛЕСТНИЦА СИЛЫ, И ОНА ЕСТЬ СМЫСЛ. Светится не всё цветное, а то, что обязано быть замечено
     первым (сами значения стоят выше, у своих состояний):
       норма       0      не светится ВОВСЕ. Спокойный блок, у которого нет новости, не имеет
                          права спорить за внимание с аварией. Было 0.10, и «всё спокойно» на
                          главной светилось ровно так же ярко, как беда.
       незнание    0      «нет данных» тем более: у него и цвета своего нет.
       к сведению  0.06   едва: тон угадывается, тревоги не заявляет
       внимание    0.10   слабо
       авария      0.18   заметнее всех, и это ПОТОЛОК, а не вкус (ниже почему)

     ПОТОЛОК ПОСЧИТАН. Свечение поднимает светлоту подложки, значит съедает контраст текста,
     который на этой подложке лежит. Замер по светящемуся углу (поверхность плюс тинт состояния
     плюс пик свечения, с поправкой на геометрию слоя):
       авария     --text-dim 4.64, --text-mono 4.25, --text-off 3.84
       внимание   --text-dim 4.93, --text-mono 4.51, --text-off 4.08
       к сведению --text-dim 5.30, --text-mono 4.85, --text-off 4.38
     Отсюда правило одной строкой: В СВЕТЯЩЕМСЯ УГЛУ ТЕКСТ НЕ ТИШЕ --text-dim. Всё, что тише
     (--text-mono, --text-faint, --text-off, --nd-text, --accent2-dim), ставится за пределами
     свечения. Поднять аварию выше 0.18 нельзя: уже на 0.19 --text-dim проваливается под 4.5.

     ГЕОМЕТРИЯ ОТДЕЛЬНЫМИ ТОКЕНАМИ, ЧТОБЫ УГОЛ МОЖНО БЫЛО ПЕРЕСТАВИТЬ. Значения по умолчанию
     повторяют байт в байт то, что сегодня вписано строкой в правило .tone-* (ui.css:381): свет
     идёт из правого верхнего угла, чуть выше кромки. Готовый слой лежит в --glow-layer - клади
     его первым в background-image и не собирай градиент заново:

       background-color:var(--surface);
       background-image:var(--glow-layer),linear-gradient(var(--tone-tint),var(--tone-tint));

     Слой сам по себе прозрачен: он читает --tone-glow, а выставляет его .is-lit (ui.css:411).
     Пока не попросили - не светится ничего и не стоит ничего. Обратная сторона: --tone-glow
     НАСЛЕДУЕТСЯ, поэтому вложенный блок внутри светящейся карточки, если он тоже рисует
     --glow-layer, засветится за компанию; гасить своим --tone-glow:transparent.

     Угол переставляется классами .glow-tr / .glow-tl / .glow-br / .glow-bl - они стоят сразу
     за :root и только меняют два токена ниже. */
  --glow-x:82%; --glow-y:-20%; --glow-w:120%; --glow-h:150%; --glow-fade:62%;
  --glow-layer:radial-gradient(var(--glow-w) var(--glow-h) at var(--glow-x) var(--glow-y),var(--tone-glow,transparent),transparent var(--glow-fade));
  /* ГРАФИКИ И ПОЛОСЫ. В кабинете завелись измерения, которым цвет состояния не подходит:
     полоса доступности за сутки, разложение балла на составляющие, полоски нагрузки, линии
     метрик. Раньше каждая такая деталь брала цвет откуда придётся - чаще всего --accent для
     линии и --line-mid для жёлоба, - и «сеть» на карточке ноды оказывалась того же зелёного,
     что и «всё в порядке» рядом. Показатель начинал выглядеть вердиктом.

     ДВА НАБОРА, И ОНИ ОТВЕЧАЮТ НА РАЗНЫЕ ВОПРОСЫ.

     --chart-1..6 отвечают на «который это ряд»: у величины нет тревоги, у неё есть имя. Все
     шесть стоят на одной светлоте (L* 65-75, кроме двух тихих), чтобы ни один ряд не выглядел
     важнее соседа, и все взяты из ХОЛОДНОЙ половины круга плюс два нейтральных. Причина
     арифметическая: тёплая дуга от 0 до 45 градусов занята «вниманием» и «бедой», и любой
     оранжевый ряд на этой базе читается как авария. Отсюда же ответ, почему рядов шесть, а не
     десять: чистых холодных тонов, различимых тонкой линией, на тёплой базе ровно четыре.

     --load-1..4 отвечают на «насколько горячо»: это уже тревога, поэтому шкала НАМЕРЕННО
     проходит через цвета состояний - концы совпадают с --accent и --risk байт в байт. Владелец
     не должен видеть два разных красных, значащих одно и то же. Ступени почти равносветлы
     (L* 69.0 / 69.6 / 69.3 / 62.2), меняется только тон 151 -> 100 -> 36 -> 8: полоса теплеет,
     а не тяжелеет.

     Жёлоб под полосой тоже токен, а не первый попавшийся --line-mid: --bar-track для полосы на
     карточке, --bar-track-deep для полосы на светлой плашке, где жёлоб обязан быть врезкой. */
  --chart-1:#75C79F; --chart-2:#758CC7; --chart-3:#75BFC7;
  --chart-4:#96C775; --chart-5:#9AA09E; --chart-6:#7D8180;
  /* Заливка площади под линией: тот же цвет, разбавленный до подложки. */
  --chart-1-fill:rgba(117,199,159,0.16); --chart-2-fill:rgba(117,140,199,0.16);
  --chart-3-fill:rgba(117,191,199,0.16); --chart-4-fill:rgba(150,199,117,0.16);
  --chart-5-fill:rgba(166,157,150,0.16); --chart-6-fill:rgba(138,126,122,0.16);
  /* Сетка и ось. Прежние значения (#2A2422 и #39312E) считались от фона страницы, а график
     живёт на карточке или на плашке: сетка давала 1.01 к --surface-3, то есть на плашке её не
     было видно вовсе, а ось отличалась от сетки на 0.09 - «нулевая линия» ничем не выделялась.
     Пересчитано от поверхностей, на которых график действительно рисуется:
       --chart-grid  1.23 к --surface, 1.13 к --surface-3   тонкая сетка, читается, но не спорит
       --chart-axis  1.49 к --surface, 1.37 к --surface-3   ось и нулевая линия, заметно крепче */
  --chart-grid:#2B2E30; --chart-axis:#383B3E;
  --load-1:var(--accent); --load-2:#87B76F; --load-3:var(--warn); --load-4:var(--risk);
  --bar-track:#222628; --bar-track-deep:#151719;
  /* ПАЛИТРА ИЗМЕРЕНИЙ: СЛЕД, ЗАСЕЧКА ПОРОГА И ДЕЛЬТА.

     Продолжение той же мысли, что и --chart-*: у величины нет тревоги, у неё есть имя. Но три
     детали измерения выше не покрыты, и каждая брала цвет откуда придётся.

     СЛЕД ЗАМЕРА - тихая линия истории под живым значением: спарклайн за сутки, тень прошлой
     проверки, фоновая кривая под текущей. Он обязан быть ТИШЕ ЛЮБОГО ТЕКСТА на той же плашке,
     иначе фон начинает читаться раньше факта. Порог тут графический, 3:1, а не текстовый:
     3.92 на --surface, 3.30 на --surface-5, 3.11 на --surface-6 - держит везде.

     ЗАСЕЧКА ПОРОГА - линия, которую поставил человек: «85% диска», «300 Мбит/с». Она НЕ красится
     жёлтым и НЕ красится красным, пока порог не перейдён, иначе на каждом спокойном графике
     висела бы вечная тревога, и цвет состояния обесценился бы. Молчит - нейтральная
     (4.62 на --surface, 3.67 на --surface-6, графический порог держит). Перешли - берёт
     --metric-thresh-hot, и вот тогда это уже беда, тем же красным, что и везде.

     ДЕЛЬТА ОТДЕЛЬНО ОТ СОСТОЯНИЙ, И ЭТО ГЛАВНОЕ ЗДЕСЬ. Смысл роста зависит от показателя: рост
     диска - беда, рост клиентов онлайн - радость, рост задержки - беда, рост скорости - радость.
     Значит сам по себе знак «стало больше» покрасить в --ok или --risk НЕЛЬЗЯ: один и тот же
     зелёный означал бы в соседних плитках противоположное. Поэтому у дельты цвет НАПРАВЛЕНИЯ, а
     не приговора: оба конца холодные, из семьи второго акцента, различаются светлотой, а знак и
     стрелку рисует экран.
       --delta-up    стало больше   6.95-9.66 по всем рабочим поверхностям
       --delta-down  стало меньше   4.76-6.62
       --delta-flat  без изменений  тише обоих; потолок --surface-5 (4.60), на --surface-6 4.33
     Экран ЗНАЕТ смысл роста? Тогда пусть красит состоянием само ЧИСЛО (--risk-text, --ok-text),
     а стрелку оставит дельте. Два зелёных с разным смыслом в одном кабинете - это и есть та
     путаница, ради которой набор заведён отдельно.

     ЧЕГО ТУТ НАМЕРЕННО НЕТ. Заполнение по ступеням нагрузки уже есть выше и зовётся --load-1..4,
     жёлоб под полосой - --bar-track и --bar-track-deep. Второго набора на ту же работу не
     заводить: разъедется. */
  --metric-trace:#777B7B; --metric-trace-fill:rgba(128,121,118,0.13);
  --metric-thresh:#838786; --metric-thresh-hot:var(--risk);
  --delta-up:#A7BCE6; --delta-down:#8E9BB7; --delta-flat:#8F9492;
  /* ГНЕЗДО ПОД ИКОНКУ: квадрат со скруглением на ступень ТЕМНЕЕ карточки. Иконка, лежащая прямо
     на поверхности, читается как случайный значок; та же иконка в гнезде читается как знак
     раздела. Ступень вниз, а не вверх: гнездо не должно спорить с числом рядом. */
  --nest:#16181A; --nest-line:#25292B;
  /* слои */
  --overlay:rgba(13,10,8,0.72); --scrim:rgba(23,19,16,0.9);
  --shadow-modal:0 40px 90px rgba(0,0,0,0.6); --shadow-pop:0 22px 48px rgba(0,0,0,0.55);
  --shadow-float:0 10px 26px rgba(0,0,0,0.35); --shadow-toast:0 20px 50px rgba(0,0,0,0.55);
  /* Освещённая верхняя кромка поверхности: тонкая светлая линия, из-за которой карточка читается
     объектом, а не наклейкой. Значение жило литералом в двух правилах ui.css, и каждая новая
     секция копировала его к себе третьим и четвёртым разом. Здесь оно одно на весь продукт. */
  --edge-light:inset 0 1px 0 rgba(255,238,226,0.045);
  /* Обратная кромка: тень ВНУТРЬ по верхнему краю. Врезка (жёлоб полосы, поле, лог) отличалась
     от поверхности только тем, что темнее, и на маленькой высоте - шесть пикселей у полосы
     нагрузки - разницу в светлоте глаз не берёт: жёлоб читался как ещё одна плашка, а не как
     канавка. Тень сверху даёт то, чего светлота дать не может: направление. Пара к --edge-light,
     и ставятся они всегда порознь - поверхность либо выступает, либо утоплена. */
  --edge-inset:inset 0 1px 2px rgba(0,0,0,0.32);
  /* ШУМ НА КРУПНЫХ ПОВЕРХНОСТЯХ: ТЕКСТУРА ВМЕСТО ПЛАСТИКА.

     Ровная тёмная заливка на площади в пол-экрана читается пластиковой панелью: глазу не за что
     зацепиться, и холст выглядит дешевле, чем карточки, которые на нём лежат. Лечится еле
     заметной плёнкой зерна. Только на САМЫХ КРУПНЫХ поверхностях - холст и боковина; на карточке
     или чипе зерно не добавляет глубины, а мусор добавляет.

     Внешних файлов нет и быть не может (фронт вкомпилен в бинарник через go:embed), поэтому
     зерно рисует сам браузер: SVG-фильтр feTurbulence, вшитый в токен как data-URI. Тайл 160 на
     160, стыкуется сам (stitchTiles), цвет снят (feColorMatrix saturate 0) - иначе зерно было бы
     разноцветной сыпью. Ни одной сетевой ссылки.

     ЗАЧЕМ У КАЖДОГО ТОКЕНА ВТОРОЙ СЛОЙ. Полупрозрачное серое зерно над тёмной заливкой не только
     рябит, но и ОСВЕТЛЯЕТ её: середина шума - серый 128, а холст - 20. При честной заливке в 6%
     холст уезжал вверх на 8 единиц яркости, то есть лестница поверхностей, считанная по L*,
     разъезжалась, и карточка переставала выступать над фоном. Поэтому под зерном лежит второй
     слой - чёрная вуаль ровно той плотности, которая возвращает среднее на место. Замерено в
     браузере по 25 600 пикселям, а не на глаз:
       холст    #171310  плоский 19.87   с зерном 19.89   разброс 1.42
       боковина #1C1816  плоский 24.98   с зерном 25.06   разброс 1.20
     Поверхность осталась там же, где стояла, а рябь появилась. Контрасты не двинулись ни на
     сотую: --text-off на холсте было 5.83, стало 5.82.

     ОТСЮДА ГЛАВНОЕ ОГРАНИЧЕНИЕ: вуаль подобрана под КОНКРЕТНУЮ заливку. --noise-canvas кладётся
     только на --canvas, --noise-rail только на --rail, поэтому они и названы по месту, а не
     номером. Понадобилась третья крупная поверхность - заводите третий токен тем же способом:
     замерить среднюю яркость с зерном без вуали, разделить прибавку на яркость самой заливки,
     это и есть альфа вуали. Чужой токен на чужой заливке уедет по светлоте, то есть сломает
     ровно ту лестницу, ради которой всё считалось.

     Кладётся ПОСЛЕДНИМ слоем в background-image, под всё остальное:
       background-color:var(--canvas); background-image:var(--glow-layer),var(--noise-canvas); */
  --noise-canvas:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n' filterUnits='userSpaceOnUse' x='0' y='0' width='160' height='160'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.06'/%3E%3C/svg%3E"),linear-gradient(rgba(0,0,0,.21),rgba(0,0,0,.21));
  --noise-rail:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n' filterUnits='userSpaceOnUse' x='0' y='0' width='160' height='160'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.05'/%3E%3C/svg%3E"),linear-gradient(rgba(0,0,0,.14),rgba(0,0,0,.14));
  /* скругления по ролям */
  --r-key:5px; --r-chip:6px; --r-badge:7px; --r-btn-sm:8px; --r-btn:9px; --r-input:10px;
  --r-plate:11px; --r-plate-lg:12px; --r-card:14px; --r-section:16px; --r-modal:18px; --r-pill:999px;
  /* шкала отступов */
  --s-1:4px; --s-2:6px; --s-3:8px; --s-4:10px; --s-5:12px; --s-6:14px;
  --s-7:16px; --s-8:20px; --s-9:22px; --s-10:26px;
  /* типографика */
  /* ШКАЛА РАЗМЕРОВ ТЕКСТА. Её не было вовсе, и это корень претензии «дизайн не проработан»:
     кегли жили литералами прямо в разметке, 13 разных значений в одном только ui.css, и любой
     новый экран изобретал размер заново, потому что выбирать было не из чего.

     Замер по боевому коду: 12px встречается 143 раза, 12.5px - 132, 11.5px - 113, 11px - 95,
     10.5px - 72, 13px - 66. Шесть почти неразличимых ступеней в диапазоне полутора пикселей -
     это не иерархия, это шум. Шкала ниже сводит их к пяти внятным ролям.

     Названы по НАЗНАЧЕНИЮ, а не по размеру: «подпись» останется подписью, даже если завтра
     решим сделать её на полпикселя крупнее, и переименовывать по всему продукту не придётся. */
  --t-hero:27px;   /* заголовок экрана, один на странице */
  --t-metric:21px; /* число показателя: то, ради чего владелец пришёл */
  --t-title:15px;  /* заголовок карточки или события */
  --t-body:13px;   /* обычный текст, который читают */
  --t-label:12px;  /* подпись под значением, вторичная строка */
  --t-meta:11px;   /* служебное: чипы, счётчики, время */
  --t-caps:10.5px; /* НАДЗАГОЛОВОК капсом с разрядкой */

  --f-ui:'Onest',system-ui,sans-serif; --f-mono:'JetBrains Mono',ui-monospace,monospace;

  /* ШКАЛА ДВИЖЕНИЯ: ТРИ ДЛИТЕЛЬНОСТИ, ТРИ КРИВЫЕ, БОЛЬШЕ НЕ ЗАВОДИТЬ.

     Длительности жили литералами: .12s в ui.css, .22s у ящика боковины, 2.4s у пульсирующей
     точки в подвале. Три решения на три работы - это ещё не шкала, потому что четвёртый случай
     изобретал четвёртое значение. Названы по РАБОТЕ, а не по числу:

       --dur-tap    110ms   отклик под пальцем: цвет кнопки, граница поля, наведение. Столько,
                            чтобы переход не мигал, и не столько, чтобы интерфейс отставал.
       --dur-enter  220ms   появление: запись въезжает в список, выезжает ящик, встаёт модалка.
       --dur-live   2400ms  дыхание живого замера: точка «данные идут», бегущая рейка. Медленно
                            намеренно - это фон, а не событие.

     Кривые. Пружин нет ни одной: перелёт за конечное значение в рабочем инструменте читается
     дребезгом, а не живостью, и на плотном экране с двадцатью строками он невыносим.
       --ease-move   вход и выход поровну: состояние туда и обратно (наведение, нажатие)
       --ease-enter  быстрый вход, мягкая посадка: то, что появляется
       --ease-live   симметричное дыхание, без рывка на концах цикла

     Готовые пары, чтобы не писать длительность и кривую порознь:
       transition:border-color var(--tr-tap);
       transition:opacity var(--tr-enter),transform var(--tr-enter);

     КАК ЭТО ГАСИТСЯ. Владелец, которого укачивает, обязан получить СТАТИЧНЫЙ интерфейс, а не
     сломанный. Гасится в два эшелона, сам выключатель - в самом низу файла:
       1. Три длительности уходят в ноль на уровне :root. Всё, что собрано на токенах, замирает
          в своём КОНЕЧНОМ виде: запись просто есть, кнопка просто перекрашена, ящик просто
          открыт. Ничего не мигает и ничего не пропадает.
       2. Общее правило по звёздочке остаётся сеткой безопасности - для литералов, которые ещё
          не переехали на токены, и для keyframes.
     Отсюда договор для тех, кто пишет экраны: движение не имеет права быть ЕДИНСТВЕННЫМ
     носителем смысла. Пульсирующая точка обязана быть ещё и цветной точкой, бегущий перегон -
     ещё и подписанным перегоном, всплывающая запись - ещё и записью в списке. Иначе при
     выключенном движении владелец теряет не украшение, а факт. */
  --dur-tap:110ms; --dur-enter:220ms; --dur-live:2400ms;
  --ease-move:cubic-bezier(.4,0,.2,1); --ease-enter:cubic-bezier(.16,.7,.3,1);
  --ease-live:cubic-bezier(.4,0,.6,1);
  --tr-tap:var(--dur-tap) var(--ease-move); --tr-enter:var(--dur-enter) var(--ease-enter);
}
/* УГОЛ СВЕЧЕНИЯ. Это не оформление, а переключатель двух токенов: свет обязан идти из того
   угла, где стоит метка состояния, иначе он врёт про источник. Действует на всё, что рисует
   var(--glow-layer). Правило .tone-* в ui.css сегодня собирает градиент своей строкой, поэтому
   углы там пока не работают: одна правка ui.css:381 на var(--glow-layer) включит их и там. */
.glow-tr{--glow-x:82%;--glow-y:-20%}
.glow-tl{--glow-x:18%;--glow-y:-20%}
.glow-br{--glow-x:82%;--glow-y:120%}
.glow-bl{--glow-x:18%;--glow-y:120%}
*{box-sizing:border-box}
html,body{margin:0;padding:0;background:var(--canvas)}
/* Базовый цвет текста ОБЯЗАН стоять на body: всё, что не выставило color само, иначе
   наследует чёрный по умолчанию от браузера и садится чёрным на тёмную поверхность.
   Так пропадал заголовок модалки (.modal__title цвет не задаёт). Правим в корне, а не
   по одному селектору - иначе следующий элемент без color принесёт ту же беду. */
/* Перенос длинных слов ОБЯЗАН стоять в корне: домены, UUID, имена нод, названия регионов -
   единым «словом» без пробелов вылезали за рамку карточек/плашек/тултипов (жалоба «слово
   вылазит за границу, не видно целиком»). overflow-wrap наследуется -> чиним разом везде, а не
   по одному экрану. break-word (а не anywhere) не ломает интринсик кнопок/коротких меток. */
body{font-family:var(--f-ui);-webkit-font-smoothing:antialiased;color:var(--text);overflow-wrap:break-word}
a{color:var(--accent);text-decoration:none}
a:hover{color:var(--link-hover)}
input,button,textarea{font-family:inherit}
input::placeholder{color:var(--text-faint)}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track{background:var(--canvas)}
::-webkit-scrollbar-thumb{background:var(--line-mid);border-radius:var(--r-btn-sm);border:2px solid var(--canvas)}
::-webkit-scrollbar-thumb:hover{background:var(--info-line)}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:2px}
/* ВЫКЛЮЧАТЕЛЬ ДВИЖЕНИЯ. Разбор - в блоке «ШКАЛА ДВИЖЕНИЯ» выше, тут только механика.
   Первый эшелон: длительности в ноль, и всё, что собрано на токенах, встаёт в конечном виде.
   Второй: правило по звёздочке добивает литералы и keyframes. iteration-count:1 нужен именно
   бесконечным анимациям - без него дыхание длиной .001мс дёргалось бы каждый кадр, то есть
   получилось бы ровно то, от чего человек защищается. */
@media (prefers-reduced-motion:reduce){
  :root{--dur-tap:0ms;--dur-enter:0ms;--dur-live:0ms}
  *,*::before,*::after{animation-duration:.001ms !important;animation-iteration-count:1 !important;transition-duration:.001ms !important;scroll-behavior:auto !important}
}
@keyframes c32rail{0%,100%{opacity:1}50%{opacity:.25}}
@keyframes c32pulse{0%,100%{opacity:1}50%{opacity:.3}}
@keyframes c32in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
@keyframes c32spin{to{transform:rotate(360deg)}}
@keyframes c32flow{to{stroke-dashoffset:-32}}
@keyframes c32shine{from{background-position:200% 0}to{background-position:-200% 0}}
@keyframes c32sheet{from{opacity:0;transform:translateY(16px) scale(.985)}to{opacity:1;transform:none}}
