/* Дизайн-система центра Replicast: чернила и бумага.
 *
 * Один файл, без сборки и без внешних адресов: центр стоит внутри периметра площадки,
 * где интернета может не быть вовсе. Шрифты вложены рядом (`static/fonts/`), значки —
 * юникод и SVG в разметке.
 *
 * Главное правило этого файла: ЦВЕТ ОЗНАЧАЕТ, А НЕ УКРАШАЕТ. У нейтрального тона цвета
 * нет вовсе — ссылки и главные кнопки набраны чернилами, а не синим. Цветных ровно три,
 * и каждый отвечает на свой вопрос человека, читающего экран перед тем, как удалить
 * файлы бекапов:
 *
 *   внимание     — требует взгляда: тревога, приглушено, прогноз ненадёжен;
 *   опасность    — необратимое: боевая политика, удаление мимо карантина, отзыв ключа;
 *   спокойствие  — закрыто, подтверждено, доступно.
 *
 * Четвёртого тона нет намеренно. Радуга из состояний читается как оформление, и тогда
 * красная кнопка перестаёт отличаться от синей ровно в тот момент, когда это важно.
 * Раньше синим был акцент — то есть самый громкий цвет на экране тратился на «ссылку».
 *
 * Имена классов кириллические — как `.ошибка` и `.нет`, которые были здесь с фазы 2.
 * Это разметка, а не имена в коде: правило «имена английские» (PLC2401) к ней не
 * относится, а два имени в одном файле разъехались бы.
 *
 * Порядок слоёв объявлен явно: правила компонентов не должны гасить друг друга по
 * случайности порядка в файле, а утилита обязана побеждать компонент всегда.
 */

@layer сброс, основы, компоненты, утилиты;

/* ─────────────────────────────── Шрифты ────────────────────────────────
 *
 * Гарнитуры вложены файлами. `system-ui` в этой роли означал буквально «шрифт по
 * умолчанию»: на Windows-сервере экран продукта неотличим от диспетчера задач.
 *
 * Golos UI взят ради мультиплексности: одна и та же строка занимает 276,28 px и при
 * 400, и при 700, поэтому жирная ячейка не сдвигает колонку таблицы. У Golos Text —
 * 277,25 и 278,72 (измерено, `docs/design-plan.md`, «Шрифты»).
 *
 * Кириллица и латиница разнесены: кириллический файл моноширинного нужен ровно там,
 * где в путь попало русское имя, — то есть редко.
 */

@font-face {
  font-family: "Golos UI";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/golos-ui-400.woff2) format("woff2");
}

@font-face {
  font-family: "Golos UI";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/static/fonts/golos-ui-500.woff2) format("woff2");
}

/* Geologica — вариативная по насыщенности: 41 КБ на обе половины алфавита, то есть
   опасение плана «вариативный весит кратно больше» на подмножестве Google не сбылось.
   Диапазон объявлен честно, иначе браузер дорисовал бы жир сам. */
@font-face {
  font-family: "Geologica";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/static/fonts/geologica-cyrillic.woff2) format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Geologica";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/static/fonts/geologica-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2212;
}

@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/jetbrains-mono-cyrillic.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(/static/fonts/jetbrains-mono-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2212;
}

@layer основы {
  /* ────────────────────── Переменные оформления ───────────────────────── */

  :root {
    color-scheme: light;
    font-size: 15px;

    --бумага: #f7f7f6;
    --панель: #ffffff;
    --панель-2: #f0f0ee;
    --волос: #e4e4e0;
    --волос-2: #cfcfc9;
    --чернила: #14161a;
    --чернила-2: #5c6068;
    --чернила-3: #8e9299;
    --внимание: #8a5300;
    --опасность: #b3261e;
    --спокойствие: #14663f;

    /* Шкала кеглей: размах 3,3× вместо прежних 1,6×. Иерархии не было вовсе —
       заголовок экрана, заголовок раздела и строка таблицы весили одинаково. */
    --кегль-0: 0.6875rem;
    --кегль-1: 0.8125rem;
    --кегль-2: 0.9375rem;
    --кегль-3: 1.0625rem;
    --кегль-4: 1.5rem;
    --кегль-5: 2.25rem;

    --о-1: 0.25rem;
    --о-2: 0.5rem;
    --о-3: 0.75rem;
    --о-4: 1rem;
    --о-5: 1.5rem;
    --о-6: 2rem;

    --скругление: 8px;
    --скругление-мал: 5px;

    --шрифт: "Golos UI", system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
    --шрифт-заголовок: "Geologica", "Golos UI", system-ui, sans-serif;
    --шрифт-моно: "JetBrains Mono", ui-monospace, Consolas, monospace;

    --ширина-меню: 15.5rem;
    --ширина-полотна: 78rem;

    /* Высота липкой шапки. Шапка таблицы прилипает под ней, а не под верхом окна:
       иначе `thead` уезжает под шапку страницы и не виден вовсе. */
    --высота-шапки: 3.2rem;

    --переход: 120ms ease;
  }

  /* Тёмная тема описана явно, а не инверсией: на тёмном фоне «опасность» обязана
     оставаться самым громким тоном, и подобрать это можно только руками.
     Оговорка `:not([data-тема="светлая"])` нужна для выбора человеком: явно выбранная
     светлая тема побеждает системную тёмную. */
  @media (prefers-color-scheme: dark) {
    :root:not([data-тема="светлая"]) {
      color-scheme: dark;

      --бумага: #0f1113;
      --панель: #16181b;
      --панель-2: #1c1f23;
      --волос: #262a2f;
      --волос-2: #363b41;
      --чернила: #e8e8e5;
      --чернила-2: #9aa0a6;
      --чернила-3: #6b7176;
      --внимание: #e6b160;
      --опасность: #f08a80;
      --спокойствие: #6cc99a;
    }
  }

  /* Тот же набор для явно выбранной тёмной темы. Значения обязаны совпадать с блоком
     выше — расхождение держит `test_both_dark_blocks_agree`. */
  :root[data-тема="тёмная"] {
    color-scheme: dark;

    --бумага: #0f1113;
    --панель: #16181b;
    --панель-2: #1c1f23;
    --волос: #262a2f;
    --волос-2: #363b41;
    --чернила: #e8e8e5;
    --чернила-2: #9aa0a6;
    --чернила-3: #6b7176;
    --внимание: #e6b160;
    --опасность: #f08a80;
    --спокойствие: #6cc99a;
  }

  /* ──────────────────────────── Основы ──────────────────────────── */

  body {
    margin: 0;
    background: var(--бумага);
    color: var(--чернила);
    font-family: var(--шрифт);
    font-size: var(--кегль-2);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
  }

  /* Ссылка — чернилами и подчёркиванием, а не цветом: синий кричал громче тонов,
     которые в продукте означают новость. */
  a {
    color: var(--чернила);
    text-decoration: underline;
    text-decoration-color: var(--волос-2);
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    transition: text-decoration-color var(--переход);
  }
  a:hover { text-decoration-color: var(--чернила-2); }

  code, pre, .моно {
    font-family: var(--шрифт-моно);
    font-size: 0.92em;
  }

  /* Путь, адрес и шаблон имени — то, в чём ищут опечатку. Их видно как отдельную
     сущность, а не как продолжение фразы. */
  code {
    padding: 0.05rem 0.3rem;
    background: var(--панель-2);
    border: 1px solid var(--волос);
    border-radius: 4px;
  }

  /* Длинный адрес рвётся, только когда иначе не помещается: `anywhere` разрешает разрыв
     и тогда, когда место есть, и `\\nas\backup` показывается двумя строками без нужды. */
  .моно { overflow-wrap: break-word; }

  /* Фокус — чернильная рамка, а не цветная: цвет здесь отнял бы громкость у семантики,
     а видимость фокуса нужна на каждом элементе одинаково. */
  :focus-visible {
    outline: 2px solid var(--чернила);
    outline-offset: 2px;
    border-radius: 3px;
  }

  /* Ссылка для клавиатуры: первым Tab'ом уводит мимо семнадцати пунктов меню. */
  .к-содержимому {
    position: absolute;
    left: -9999px;
    top: var(--о-2);
    z-index: 10;
    padding: var(--о-2) var(--о-3);
    background: var(--панель);
    border: 1px solid var(--волос-2);
    border-radius: var(--скругление-мал);
  }
  .к-содержимому:focus { left: var(--о-2); }

  /* ───────────────────────────  Типографика  ─────────────────────────── */

  h1 {
    font-family: var(--шрифт-заголовок);
    font-size: var(--кегль-4);
    font-weight: 600;
    letter-spacing: -0.01em;
    line-height: 1.2;
    margin: 0 0 var(--о-2);
    text-wrap: balance;
  }

  h2 {
    font-size: var(--кегль-3);
    font-weight: 500;
    margin: var(--о-6) 0 var(--о-3);
    padding-bottom: var(--о-2);
    border-bottom: 1px solid var(--волос);
  }

  h3 {
    font-size: var(--кегль-2);
    font-weight: 500;
    margin: var(--о-5) 0 var(--о-2);
  }

  p { margin: var(--о-2) 0; }

  /* Второстепенное — тише основного, но не серым по серому: этим текстом продукт
     объясняет, почему кнопки нет, а это самое нужное предложение на экране.
     ⚠️ Именно `--чернила-2`, а не `--чернила-3`: третий тон под обычный текст не
     годится по контрасту (2,7–3,1:1) и держится только на крупном числе. */
  .нет { color: var(--чернила-2); }

  /* Ответ строкой — то, ради чего утром открывают дашборд. Крупнее обычного текста,
     потому что читают его первым и часто единственным. */
  .сводка {
    font-size: var(--кегль-2);
    line-height: 1.45;
    margin: 0 0 var(--о-4);
    max-width: 46rem;
  }

  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      transition-duration: 0.01ms !important;
      animation-duration: 0.01ms !important;
    }
  }
}

@layer сброс {
  *, *::before, *::after { box-sizing: border-box; }
}

@layer компоненты {
  /* ───────────────────────────────  Каркас  ─────────────────────────────── */

  .каркас {
    display: grid;
    grid-template-columns: var(--ширина-меню) minmax(0, 1fr);
    min-height: 100vh;
  }

  .боковое {
    display: flex;
    flex-direction: column;
    gap: var(--о-2);
    padding: var(--о-4) var(--о-3);
    background: var(--панель);
    border-right: 1px solid var(--волос);
    min-width: 0;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
  }

  .полотно { min-width: 0; }

  main {
    max-width: var(--ширина-полотна);
    padding: var(--о-5) var(--о-6) var(--о-6);
  }

  /* ────────────────────────────────  Меню  ─────────────────────────────── */

  .верх-меню {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--о-2);
  }

  .знак {
    display: flex;
    align-items: center;
    gap: var(--о-2);
    font-family: var(--шрифт-заголовок);
    font-weight: 600;
    font-size: var(--кегль-3);
    letter-spacing: -0.01em;
    color: var(--чернила);
    padding: var(--о-1) var(--о-2);
    text-decoration: none;
  }
  .знак:hover { text-decoration: none; }
  .знак-рисунок { width: 1.15rem; height: 1.15rem; color: var(--чернила); flex: none; }

  /* ⚠️ На широком экране галочка не просто невидима, а исключена из порядка обхода:
     `opacity: 0` оставляет её фокусируемой, и первым же Tab'ом человек попадал на
     невидимый элемент, о котором нельзя сказать ни что это, ни что он делает.
     Найдено приёмкой этапа 9 — проходом по экрану одной клавиатурой. */
  .переключатель-меню { display: none; }
  .кнопка-меню {
    display: none;
    cursor: pointer;
    padding: var(--о-1) var(--о-3);
    border: 1px solid var(--волос-2);
    border-radius: var(--скругление-мал);
    color: var(--чернила-2);
  }

  .тело-меню {
    display: flex;
    flex-direction: column;
    gap: var(--о-2);
    flex: 1;
  }

  /* Площадка названа над меню: у пунктов ниже адреса начинаются с неё, и без имени
     человек не видит, чьи это тревоги. Переход к списку — ссылкой рядом. */
  .площадка {
    margin: var(--о-2) 0 var(--о-1);
    padding: var(--о-2) var(--о-3);
    background: var(--панель-2);
    border-radius: var(--скругление-мал);
  }
  .площадка b { display: block; font-weight: 500; }
  .площадка small { display: block; color: var(--чернила-2); font-size: var(--кегль-1); }
  .площадка a { display: inline-block; margin-top: var(--о-1); font-size: var(--кегль-1); }

  nav { display: flex; flex-direction: column; gap: 1px; }

  .группа {
    margin: var(--о-4) 0 var(--о-1);
    padding: 0 var(--о-3);
    font-size: var(--кегль-0);
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--чернила-2);
  }
  .группа:first-child { margin-top: var(--о-2); }

  .пункт {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--о-2);
    padding: 0.3rem var(--о-3);
    border-radius: var(--скругление-мал);
    color: var(--чернила-2);
    font-size: var(--кегль-2);
    text-decoration: none;
    transition: background var(--переход), color var(--переход);
  }
  .пункт:hover {
    background: var(--панель-2);
    color: var(--чернила);
    text-decoration: none;
  }

  /* Где человек находится — залитый чернилами блок. Цветную подсветку тут ставить
     нельзя: она отняла бы громкость у тонов, которыми продукт сообщает новость. */
  .пункт.активный {
    background: var(--чернила);
    color: var(--бумага);
    font-weight: 500;
  }

  /* Счётчик у пункта меню — число открытых тревог. Считается в queries.py, как и всякое
     число в продукте: у числа на экране обязан быть список ровно такой длины (И-3). */
  .счётчик {
    min-width: 1.35rem;
    padding: 0 0.3rem;
    border-radius: 999px;
    background: var(--опасность);
    color: var(--панель);
    font-size: var(--кегль-0);
    font-weight: 500;
    line-height: 1.35rem;
    text-align: center;
    font-variant-numeric: tabular-nums;
  }
  .пункт.активный .счётчик { background: var(--бумага); color: var(--чернила); }

  .подвал-меню {
    margin-top: auto;
    padding-top: var(--о-3);
    border-top: 1px solid var(--волос);
    display: flex;
    flex-direction: column;
    gap: var(--о-2);
    font-size: var(--кегль-1);
  }
  .выбор-площадки {
    display: flex;
    gap: var(--о-2);
    align-items: center;
    margin: 0 0 var(--о-1);
    max-width: none;
  }
  .выбор-площадки select { flex: 1; min-width: 0; font-size: var(--кегль-1); }

  /* Три формы в ряд, а не список: выбор темы — это одна строка, а не раздел настроек.
     Выбранное помечено заливкой, как активный пункт меню. */
  .переключатель-темы { display: flex; gap: 2px; }
  .переключатель-темы form { margin: 0; max-width: none; }
  .переключатель-темы button { font-size: var(--кегль-0); padding: 0.2rem 0.4rem; }
  .переключатель-темы .выбрана {
    background: var(--чернила);
    color: var(--бумага);
    border-color: var(--чернила);
  }
  .переключатель-темы .выбрана:hover { background: var(--чернила-2); }

  .подвал-меню .кто { color: var(--чернила); font-weight: 500; }
  .подвал-меню .роль { color: var(--чернила-2); font-size: var(--кегль-1); }
  .подвал-меню form { margin: 0; max-width: none; }

  /* ─────────────────────────────  Шапка страницы  ───────────────────────── */

  .шапка {
    display: flex;
    align-items: center;
    gap: var(--о-3);
    height: var(--высота-шапки);
    padding: 0 var(--о-6);
    background: var(--панель);
    border-bottom: 1px solid var(--волос);
    position: sticky;
    top: 0;
    z-index: 5;
  }
  .шапка .путь { color: var(--чернила-2); font-size: var(--кегль-1); }
  .шапка .путь b { color: var(--чернила); font-weight: 500; }
  .шапка .разделитель { color: var(--чернила-2); padding: 0 0.15rem; }
  .шапка .справа { margin-left: auto; display: flex; gap: var(--о-2); align-items: center; }

  .заголовок-страницы {
    display: flex;
    align-items: flex-start;
    gap: var(--о-4);
    margin-bottom: var(--о-4);
  }
  .заголовок-страницы .действия { margin-left: auto; display: flex; gap: var(--о-2); }

  /* ────────────────────────────────  Таблицы  ───────────────────────────── */

  .таблица-обёртка {
    overflow-x: auto;
    background: var(--панель);
    border: 1px solid var(--волос);
    border-radius: var(--скругление);
    margin: var(--о-3) 0 var(--о-5);
  }

  table {
    border-collapse: collapse;
    width: 100%;
    font-size: var(--кегль-1);
  }

  /* ⚠️ Шапка таблицы липнет под шапкой страницы, а не под верхом окна. С `top: 0`
     она уезжала ровно под неё и не была видна вообще — то есть липкость была, а
     пользы от неё не было. */
  thead th, table > tr:first-child th {
    position: sticky;
    top: var(--высота-шапки);
    background: var(--панель-2);
    color: var(--чернила-2);
    font-size: var(--кегль-0);
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
  }

  th, td {
    text-align: left;
    padding: 0.5rem 0.7rem;
    border-bottom: 1px solid var(--волос);
    vertical-align: top;
  }
  th:first-child, td:first-child { padding-left: var(--о-4); }
  th:last-child, td:last-child { padding-right: var(--о-4); }

  tbody tr:last-child td, table > tr:last-child td { border-bottom: none; }
  tbody tr:hover td { background: color-mix(in srgb, var(--панель-2) 55%, transparent); }

  /* Числа читаются столбцом, а не змейкой: цифры одной ширины. */
  td { font-variant-numeric: tabular-nums; }

  /* Действия строки — в ряд и справа, без вертикальной лесенки из форм. */
  .действия-строки { display: flex; flex-wrap: wrap; gap: var(--о-2); align-items: center; }
  .действия-строки form { margin: 0; display: inline-flex; gap: var(--о-2); max-width: none; }
  .действия-строки input, .действия-строки select { min-width: 0; }

  /* Действие с вводом (снять тревогу с комментарием, приглушить на срок) в ряд не
     помещается ни в какую колонку: поле, список и кнопка уезжали за край таблицы.
     ⚠️ Предел ширины полю обязателен: без него ячейка распирает колонку, таблица
     уезжает за правый край, и кнопки «снять» и «приглушить» — то, ради чего на экран
     тревог заходят, — оказываются за горизонтальной прокруткой. Ровно это видно на
     снимке «до» этапа 0. */
  .действия-строки.колонкой { flex-direction: column; align-items: stretch; }
  /* Перенос обязателен: форма «приглушить» — это список сроков, поле и кнопка, и в одну
     строку ячейки они не помещаются ни при какой ширине колонки. Без переноса за край
     уезжала именно кнопка, то есть само действие. */
  .действия-строки.колонкой form { display: flex; flex-wrap: wrap; }
  .действия-строки.колонкой input { flex: 1 1 8rem; max-width: 11rem; }
  .действия-строки.колонкой select { max-width: 7rem; }

  /* Правка прямо в строке таблицы: права доступа и порог молчания. Обе формы стоят в
     ячейке, а общий вид формы — колонка шириной 34rem — растянул бы таблицу так, что
     читать её стало бы нечем. */
  td > form.права, td > form.порог {
    display: flex;
    flex-wrap: wrap;
    gap: var(--о-2);
    align-items: center;
    max-width: none;
    margin: 0;
  }
  td > form.права label { font-size: var(--кегль-1); white-space: nowrap; }
  td > form.порог input { width: 5rem; }

  /* Строка тревоги помечена краем, а не цветом каждой ячейки: на экране тревог тревожно
     всё, и красное в каждой строке перестаёт что-либо значить. */
  tr.тревожная td:first-child { box-shadow: inset 3px 0 0 var(--опасность); }
  tr.приглушена td:first-child { box-shadow: inset 3px 0 0 var(--волос-2); }
  tr.приглушена td { color: var(--чернила-2); }

  /* ────────────────────────────────  Формы  ─────────────────────────────── */

  form {
    display: grid;
    gap: var(--о-3);
    max-width: 34rem;
    margin: var(--о-3) 0 var(--о-5);
  }

  label { display: grid; gap: var(--о-1); font-size: var(--кегль-1); }
  label > input[type="checkbox"] { margin-right: var(--о-1); }

  /* Галочка не растягивается на всю ширину: подпись рядом, а не под ней. */
  label:has(> input[type="checkbox"]) {
    display: flex;
    align-items: flex-start;
    gap: var(--о-2);
    line-height: 1.45;
  }

  input, select, textarea {
    font: inherit;
    font-size: var(--кегль-2);
    padding: 0.35rem 0.5rem;
    color: var(--чернила);
    background: var(--панель);
    border: 1px solid var(--волос-2);
    border-radius: var(--скругление-мал);
    transition: border-color var(--переход);
  }
  input[type="checkbox"] { width: auto; accent-color: var(--чернила); }
  input:focus, select:focus, textarea:focus {
    outline: 2px solid var(--чернила);
    outline-offset: 1px;
    border-color: var(--чернила-2);
  }

  /* Подсказка под полем — то же, что раньше было `<p class="нет">` следом за label. */
  .подсказка { margin: 0; color: var(--чернила-2); font-size: var(--кегль-1); }

  /* Последствия выбора — рядом с самим выбором. Форма выдачи доступа была пятью голыми
     галочками, а то, что из них следует, объяснялось на соседнем экране и после того,
     как доступ уже выдан. */
  .последствия { margin: 0; display: grid; gap: var(--о-2); font-size: var(--кегль-1); }
  .последствия dt { font-weight: 500; }
  .последствия dd { margin: 0 0 var(--о-2); color: var(--чернила-2); }

  /* Свёрнутая точная настройка: раскладок больше, чем назначений, и прятать их совсем
     нельзя — но и показывать пять битов первым, что видит человек, незачем. */
  details > summary { cursor: pointer; font-weight: 500; }
  details[open] > summary { margin-bottom: var(--о-2); }

  /* ───────────────────────────────  Кнопки  ─────────────────────────────── */

  button, .кнопка {
    font: inherit;
    font-size: var(--кегль-2);
    font-weight: 500;
    width: fit-content;
    white-space: nowrap;
    cursor: pointer;
    padding: 0.35rem 0.75rem;
    color: var(--чернила);
    background: var(--панель);
    border: 1px solid var(--волос-2);
    border-radius: var(--скругление-мал);
    text-decoration: none;
    transition: background var(--переход), border-color var(--переход);
  }
  button:hover, .кнопка:hover { background: var(--панель-2); text-decoration: none; }

  /* Главное действие — залито чернилами. Тон под него не берётся: тон означает новость,
     а «сохранить» новостью не является. */
  .главная {
    background: var(--чернила);
    border-color: var(--чернила);
    color: var(--бумага);
  }
  .главная:hover { background: var(--чернила-2); border-color: var(--чернила-2); }

  /* Опасная кнопка выглядит опасной. До этого «Перевести в боевой режим» — после неё
     продукт удаляет файлы — была неотличима от «Проверить сейчас». */
  .опасная {
    background: var(--панель);
    border-color: var(--опасность);
    color: var(--опасность);
  }
  .опасная:hover { background: var(--опасность); border-color: var(--опасность); color: var(--панель); }

  .тихая {
    background: transparent;
    border-color: transparent;
    color: var(--чернила-2);
    padding: 0.3rem 0.5rem;
  }
  .тихая:hover { background: var(--панель-2); color: var(--чернила); }

  /* ───────────────────────────  Карточки чисел (И-3)  ────────────────────── */

  .числа {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(11rem, 100%), 1fr));
    gap: var(--о-3);
    list-style: none;
    padding: 0;
    margin: var(--о-3) 0 var(--о-5);
  }

  .числа li {
    background: var(--панель);
    border: 1px solid var(--волос);
    border-radius: var(--скругление);
    padding: 0;
  }

  /* Кликабельна карточка целиком, а не число внутри: у каждого числа есть переход в
     список ровно такой длины, и промахнуться мимо ссылки нельзя. */
  .числа a, .числа .карточка {
    display: block;
    padding: var(--о-3) var(--о-4);
    color: var(--чернила-2);
    font-size: var(--кегль-1);
    text-decoration: none;
  }
  .числа a:hover {
    text-decoration: none;
    background: var(--панель-2);
    border-radius: var(--скругление);
  }
  .числа li:has(a:hover) { border-color: var(--волос-2); }

  .числа b {
    display: block;
    font-family: var(--шрифт-заголовок);
    font-size: var(--кегль-5);
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: var(--чернила);
    font-variant-numeric: tabular-nums;
    margin-bottom: 0.1rem;
  }

  /* Ноль тише прочего: экран из двенадцати жирных нулей не сообщает ничего, а тревога
     среди них теряется. Само число при этом остаётся на месте — «пропавших копий нет»
     и «мы не считали» разные новости, и прятать ноль нельзя.
     ⚠️ Единственное место, где законен `--чернила-3`: кегль здесь 2,25rem, то есть
     крупный текст, которому WCAG разрешает 3:1. */
  .числа b.ноль {
    color: var(--чернила-3);
    font-size: var(--кегль-5);
    font-weight: 500;
  }

  /* Карточки со словом вместо числа: «доступна», «подтверждена сумма». Слово длиннее
     цифры, и кегль числа рвал бы его на строки. */
  .числа.словами b { font-size: var(--кегль-3); letter-spacing: 0; line-height: 1.35; }

  /* Поле формы вместе со своей подсказкой — один блок, а не абзац рядом. */
  .поле { display: grid; gap: var(--о-1); }

  /* Необратимое действие стоит особняком: галочка, кнопка и воздух вокруг них. */
  .опасное-действие {
    gap: var(--о-3);
    padding: var(--о-3) var(--о-4);
    border: 1px solid var(--опасность);
    border-radius: var(--скругление-мал);
    background: var(--панель);
  }

  /* ──────────────────────────────  Рисунки  ─────────────────────────────── */

  /* Разметку рисует `web/charts.py`; здесь только тона и размеры. Цвет в самом SVG
     жил бы мимо темы: чернила на чёрном фоне светятся. */

  .полоса { margin: var(--о-2) 0 var(--о-1); }
  .полоса-путь {
    height: 8px;
    background: var(--панель-2);
    border-radius: 2px;
    overflow: hidden;
  }
  .полоса-налив { height: 100%; background: var(--чернила); }
  .полоса-налив.внимание { background: var(--внимание); }
  .полоса-налив.опасность { background: var(--опасность); }
  .полоса-налив.спокойствие { background: var(--спокойствие); }

  /* Лента дней: клетка — одни сутки. Сутки без сведений показаны контуром: залитая
     клетка читается как факт, а «наряда на эти сутки не было» — не факт о бекапах. */
  .лента { display: flex; gap: 3px; margin: var(--о-2) 0 var(--о-1); max-width: 40rem; }
  .лента a { text-decoration: none; }
  .лента .сутки {
    display: block;
    width: 14px;
    height: 30px;
    border-radius: 2px;
    background: var(--чернила);
    transition: transform var(--переход);
  }
  .лента .сутки.нет-данных { background: transparent; border: 1px solid var(--волос-2); }
  .лента .сутки.внимание { background: var(--внимание); }
  .лента .сутки.опасность { background: var(--опасность); }
  .лента .сутки.спокойствие { background: var(--спокойствие); }
  .лента a:hover .сутки { transform: translateY(-2px); }
  .лента-ось {
    display: flex;
    justify-content: space-between;
    max-width: 40rem;
    font-size: var(--кегль-0);
    color: var(--чернила-2);
  }

  /* Кривая симулятора: сплошная — что накопится без политики, пунктир — что останется,
     заливка между ними и есть то, что политика уносит. */
  .кривая { width: 100%; height: auto; max-width: 45rem; }
  .кривая .сетка { stroke: var(--волос); stroke-width: 1; }
  .кривая .ось, .шкала-зон .ось { fill: var(--чернила-2); font-size: 10px; }
  .шкала-зон .ось-опасно { fill: var(--опасность); font-size: 10px; }
  .полоса-разницы { fill: var(--панель-2); }
  .линия-до { fill: none; stroke: var(--чернила-2); stroke-width: 1.5; }
  .линия-после { fill: none; stroke: var(--чернила); stroke-width: 2; stroke-dasharray: 5 4; }
  .отметка { fill: var(--чернила); }
  .подпись-отметки { fill: var(--чернила); font-size: 10px; font-weight: 500; }
  .легенда {
    display: flex;
    flex-wrap: wrap;
    gap: var(--о-4);
    font-size: var(--кегль-1);
    color: var(--чернила-2);
  }
  .ключ::before {
    content: "";
    display: inline-block;
    width: 18px;
    height: 0;
    margin-right: var(--о-2);
    vertical-align: middle;
  }
  .ключ.до::before { border-top: 1.5px solid var(--чернила-2); }
  .ключ.после::before { border-top: 2px dashed var(--чернила); }
  .ключ.разница::before { height: 10px; background: var(--панель-2); border: 1px solid var(--волос); }

  /* Шкала зон: густота рисок и есть шаг, а разрыв обведён тоном опасности — «не
     покрыто зоной» означает «удаляется». */
  .шкала-зон { width: 100%; height: auto; max-width: 45rem; }
  .шкала-зон .зона { fill: var(--панель-2); stroke: var(--волос-2); }
  .шкала-зон .зона-1 { fill: var(--панель); }
  .шкала-зон .риска { stroke: var(--чернила-2); stroke-width: 1; }
  .шкала-зон .разрыв { fill: none; stroke: var(--опасность); stroke-width: 1; stroke-dasharray: 3 3; }

  /* Перечень под рисунком — тот же ответ словами: рисунок читается разом, список
     построчно, и на печати остаётся именно он. */
  .перечень {
    list-style: none;
    padding: 0;
    margin: var(--о-2) 0 var(--о-4);
    display: grid;
    gap: var(--о-1);
    font-size: var(--кегль-1);
    color: var(--чернила-2);
  }
  .перечень li { padding-left: var(--о-3); border-left: 2px solid var(--волос-2); }
  .перечень li.удаляется { border-left-color: var(--опасность); }

  /* Искра: форма ряда в ячейке таблицы. Значения читают рядом числом. */
  .искра { width: 5rem; height: 1.2rem; }
  .линия-искры { fill: none; stroke: var(--чернила-2); stroke-width: 1.5; vector-effect: non-scaling-stroke; }

  /* ────────────────────  Голова экрана и разделы действий  ───────────────── */

  /* Надзаголовок называет тип записи: имя без него не отвечает, чья это запись, а
     приходят на такой экран ссылкой из списка, журнала и тревоги. */
  .шапка-экрана { margin: 0 0 var(--о-3); }
  .шапка-экрана h1 { margin: 0; }
  .надзаголовок {
    margin: 0 0 var(--о-1);
    font-size: var(--кегль-0);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--чернила-2);
  }

  /* Отбор над списком: поля в строку, а не колонкой. Общий вид формы — колонка в
     34rem — занял бы половину экрана над таблицей, ради которой сюда и пришли. */
  .отбор {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--о-3);
    max-width: none;
    margin: 0 0 var(--о-3);
  }
  .отбор label { display: grid; gap: var(--о-1); font-size: var(--кегль-1); }
  .отбор input, .отбор select { max-width: 14rem; }

  /* Снятие группы — необратимое действие над всем, что видно: оно и выглядит так же,
     как перевод политики в бой, и требует комментария. */
  .снять-группу {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--о-3);
    max-width: none;
    margin: var(--о-3) 0 0;
  }
  .снять-группу label { display: grid; gap: var(--о-1); font-size: var(--кегль-1); flex: 1 1 22rem; }

  /* Панель над списком: счёт слева, действия справа. Число здесь — то же самое, что
     строк в таблице под ним; читают его раньше, чем саму таблицу. */
  .панель-списка {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--о-3);
    margin: 0 0 var(--о-2);
  }
  .панель-списка .счёт {
    margin: 0;
    font-size: var(--кегль-1);
    color: var(--чернила-2);
  }

  /* Раздел действия: своя граница, чтобы кнопка «Сохранить» относилась к видимому
     куску экрана, а не к ленте из пяти форм подряд. */
  .раздел {
    margin: 0 0 var(--о-4);
    padding: var(--о-4);
    background: var(--панель);
    border: 1px solid var(--волос);
    border-radius: var(--скругление);
  }
  .раздел > h2 {
    margin: 0 0 var(--о-3);
    padding-bottom: var(--о-2);
  }
  .раздел > :last-child { margin-bottom: 0; }

  /* ───────────────────────  Пара, реквизиты, отсчёт  ────────────────────── */

  /* Состояние и доверие рядом и разделены волосом: один значок из них не собрать
     ни глазами, ни правкой одной строки — а собранный был бы отказом О-5. */
  .пара {
    display: inline-flex;
    border: 1px solid var(--волос-2);
    border-radius: var(--скругление-мал);
    overflow: hidden;
    font-size: var(--кегль-1);
  }
  .пара .состояние { padding: 0.15rem 0.5rem; background: var(--панель-2); font-weight: 500; }
  .пара .доверие {
    padding: 0.15rem 0.5rem;
    border-left: 1px solid var(--волос-2);
    color: var(--чернила-2);
  }

  /* Реквизиты объекта: подпись сверху, значение под ней, всё в одну полосу. */
  .реквизиты {
    display: flex;
    flex-wrap: wrap;
    gap: 0;
    margin: var(--о-3) 0 var(--о-5);
    border: 1px solid var(--волос);
    border-radius: var(--скругление);
    background: var(--панель);
    overflow: hidden;
  }
  .реквизиты > div {
    flex: 1 1 12rem;
    padding: var(--о-3) var(--о-4);
    border-right: 1px solid var(--волос);
  }
  .реквизиты > div:last-child { border-right: none; }
  .реквизиты dt {
    font-size: var(--кегль-0);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--чернила-2);
    margin-bottom: 0.1rem;
  }
  .реквизиты dd { margin: 0; font-weight: 500; overflow-wrap: break-word; }

  /* Обратный отсчёт: сколько осталось — крупно, когда именно — тише. */
  .обратный { display: inline-flex; flex-direction: column; }
  .обратный .осталось { font-weight: 500; font-variant-numeric: tabular-nums; }

  /* ────────────────────────────────  Значки  ────────────────────────────── */

  .значок {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.08rem 0.45rem;
    border-radius: 999px;
    border: 1px solid var(--волос-2);
    background: var(--панель-2);
    color: var(--чернила-2);
    font-size: var(--кегль-1);
    font-weight: 500;
    white-space: nowrap;
  }
  .значок.внимание { background: var(--панель); border-color: var(--внимание); color: var(--внимание); }
  .значок.опасность { background: var(--панель); border-color: var(--опасность); color: var(--опасность); }
  .значок.спокойствие { background: var(--панель); border-color: var(--спокойствие); color: var(--спокойствие); }

  /* ────────────────────────────────  Заметки  ───────────────────────────── */

  .заметка {
    display: block;
    margin: var(--о-3) 0;
    padding: var(--о-3) var(--о-4);
    border: 1px solid var(--волос);
    border-left: 3px solid var(--волос-2);
    border-radius: var(--скругление-мал);
    background: var(--панель);
  }
  .заметка.внимание { border-left-color: var(--внимание); }
  .заметка.опасность { border-left-color: var(--опасность); }
  .заметка.спокойствие { border-left-color: var(--спокойствие); }
  .заметка > :first-child { margin-top: 0; }
  .заметка > :last-child { margin-bottom: 0; }

  /* Класс с фазы 2: на него завязаны тесты форм, и переименовывать его нельзя. */
  .ошибка {
    margin: var(--о-3) 0;
    padding: var(--о-3) var(--о-4);
    border: 1px solid var(--волос);
    border-left: 3px solid var(--опасность);
    border-radius: var(--скругление-мал);
    background: var(--панель);
    color: var(--опасность);
    font-weight: 500;
  }

  /* Полоса П-5: пока сверка после восстановления центра не закончена, это видно везде. */
  .полоса-восстановления {
    margin: 0 0 var(--о-4);
    padding: var(--о-3) var(--о-4);
    border: 1px solid var(--волос);
    border-left: 3px solid var(--опасность);
    border-radius: var(--скругление-мал);
    background: var(--панель);
    color: var(--опасность);
    font-weight: 500;
  }

  /* ───────────────────────  Пустота и недоступное  ──────────────────────── */

  .пусто {
    padding: var(--о-5) var(--о-4);
    border: 1px dashed var(--волос-2);
    border-radius: var(--скругление);
    color: var(--чернила-2);
    text-align: center;
    background: var(--панель);
  }

  /* Недоступное показывается с причиной, а не прячется молча (domain.md). Пропавшая
     кнопка без объяснения читается как поломка, и человек идёт править базу руками. */
  .недоступно {
    display: inline-block;
    color: var(--чернила-2);
    font-size: var(--кегль-1);
    border-left: 2px solid var(--волос-2);
    padding-left: var(--о-2);
  }

  /* ─────────────────────────────────  Вход  ─────────────────────────────── */

  /* Первое, что видит человек. Общий каркас показывал здесь пустое боковое меню —
     рамку от площадки, которой у вошедшего ещё нет. */
  .вход {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: var(--о-5);
  }
  .вход-карточка {
    width: min(24rem, 100%);
    padding: var(--о-6);
    background: var(--панель);
    border: 1px solid var(--волос);
    border-radius: var(--скругление);
  }
  .вход-карточка .знак { padding: 0; margin-bottom: var(--о-5); }
  .вход-карточка h1 { margin-bottom: var(--о-2); }
  .вход-карточка form { max-width: none; margin-bottom: 0; }
  .вход-карточка button { width: 100%; }

  /* ────────────────────────────────  Команда  ───────────────────────────── */

  .команда {
    display: block;
    margin: var(--о-2) 0 var(--о-3);
    padding: var(--о-3) var(--о-4);
    background: var(--панель-2);
    border: 1px solid var(--волос);
    border-radius: var(--скругление-мал);
    white-space: pre-wrap;
    word-break: break-all;
    font-family: var(--шрифт-моно);
    font-size: var(--кегль-1);
    line-height: 1.5;
  }
}

@layer утилиты {
  /* ──────────────────────────────  Узкий экран  ─────────────────────────── */

  @media (max-width: 62rem) {
    /* `1fr` — это `minmax(auto, 1fr)`, а `auto` снизу равен min-content: содержимое
       шире экрана растягивает колонку, и страница едет вбок целиком */
    .каркас { grid-template-columns: minmax(0, 1fr); }

    .боковое {
      position: static;
      height: auto;
      border-right: none;
      border-bottom: 1px solid var(--волос);
    }

    /* Раскрытие меню — на CSS, без единой строки скрипта: экран обязан работать и с
       выключенным JavaScript. */
    .кнопка-меню { display: block; }
    /* На узком экране галочка снова существует — ею меню и раскрывается */
    .переключатель-меню { display: block; position: absolute; opacity: 0; }
    .тело-меню { display: none; }
    .переключатель-меню:checked ~ .тело-меню { display: flex; }

    /* Шапка страницы перестаёт быть липкой, а с ней и шапка таблицы: на узком экране
       обе съедали бы половину высоты окна. */
    .шапка { position: static; padding: 0 var(--о-4); }
    thead th, table > tr:first-child th { top: 0; }
    main { padding: var(--о-4); }
    .заголовок-страницы { flex-wrap: wrap; }
  }

  /* ────────────────────────────────  Печать  ────────────────────────────── */

  @media print {
    .боковое, .шапка, .действия, form { display: none; }
    /* ⚠️ Сетка каркаса разбирается целиком: скрытое меню оставляло свою колонку, и
       содержимое печаталось узкой лентой в четверть листа — таблица решений уезжала
       за правый край. Найдено приёмкой этапа 9, печатью экрана политики. */
    .каркас { display: block; }
    main { max-width: none; padding: 0; }
    .раздел { padding: 0; border: none; break-inside: avoid; }
    .таблица-обёртка { border: none; overflow: visible; }
    thead th, table > tr:first-child th { position: static; }
    /* Ссылки на бумаге кликать нечем, а подчёркивание мешает читать таблицу */
    a { text-decoration: none; }
  }
}
