/* kb.css — слой статьи: только внутренние страницы.
 *
 * Выделен из site.css итерацией И1. Сюда попало то, чьи селекторы
 * встречаются на внутренних страницах и не встречаются на главной:
 * голова статьи, лид-ответ, ключевые факты, проза, соседние материалы,
 * финальная полоса статьи.
 *
 * Схемы статей не могут пользоваться классами из `home.css`: страница
 * его не подключает, и правило молча не применяется — линия теряет и
 * цвет, и толщину. Всё, что нужно схемам статей, дублируется здесь.
 *
 * Подключается последним, после base.css, вместо home.css.
 */

/* --- Внутренние страницы: разбавляем полотно текста -------------------
   Приёмы взяты из паттернов эталона (панель, плитки, финальная полоса) и
   перенесены в контекст статьи. Ни одного значения мимо токенов. */

/* Ответный абзац статьи — не рядовой текст, а ответ на вопрос страницы.
   Поднят по кеглю и отделён акцентной линейкой, как панель на главной. */
.kb-lead {
  margin-bottom: var(--space-8);
  padding: var(--space-5) var(--space-6);
  border-left: 2px solid var(--accent-secondary);
  border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
  background: var(--bg-panel-soft);
  color: var(--text-primary);
  font-size: var(--font-lg);
  line-height: 1.6;
}

/* Раздел «дальше по теме» — плитками, а не списком ссылок. */
.kb-related {
  margin-top: var(--space-12);
  padding-top: var(--space-8);
  border-top: 1px solid var(--border-subtle);
}

.kb-related-label {
  margin-bottom: var(--space-4);
  /* не --text-muted: он не проходит AA для мелкого текста (B-37) */
  color: var(--text-secondary);
  font-size: var(--font-xs);
  font-weight: var(--weight-medium);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Финальная полоса на внутренней странице: уже колонки статьи, спокойнее
   главной, но конверсия есть на каждой странице. */
.kb-cta {
  margin-top: var(--space-10);
  padding: var(--space-8);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xl);
  background: var(--bg-panel-soft);
  text-align: center;
}

.kb-cta h2 {
  margin-bottom: var(--space-3);
  font-size: var(--font-xl);
}

.kb-cta p {
  max-width: 52ch;
  margin: 0 auto var(--space-5);
  color: var(--text-secondary);
  font-size: var(--font-sm);
  line-height: 1.6;
}

.kb-cta .index-actions { justify-content: center; }

/* Ширина внутренних страниц равна ширине лендинга.
   `.wrap` дизайн-системы даёт 1120 px, а весь сайт сети живёт в 1200
   (`--index-page`). Разница читается как «страницы разной ширины», что и
   было названо владельцем первым дефектом. */
.kb-page {
  width: var(--index-page);
  max-width: none;
  margin-inline: auto;
  padding-inline: 0;
}

.kb-breadcrumbs { padding-top: var(--space-6); }

/* Перечень тезисов внутри статьи — плитками, как на лендинге.
   Серия абзацев «**Тезис.** пояснение» это список, а не проза; подряд
   идущие такие абзацы читаются полотном и теряют смысл перечисления. */
.kb-points {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-4);
  margin-block: var(--space-6);
  padding: 0;
  list-style: none;
}

.kb-point {
  padding: var(--space-5);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-panel-soft);
}

.kb-point-title {
  margin-bottom: var(--space-2);
  color: var(--text-primary);
  font-size: var(--font-sm);
  font-weight: var(--weight-semibold);
  line-height: 1.35;
}

.kb-point p {
  color: var(--text-secondary);
  font-size: var(--font-sm);
  line-height: 1.6;
}

/* Заголовок навигационной плитки — абзац, а не заголовок раздела:
   плитка не является частью структуры документа, а `<h3>` сразу после
   `<h1>` ломает порядок уровней (поймано приёмкой на `/vs/`). */
.nav-card-title {
  margin-bottom: var(--space-1);
  color: var(--text-primary);
  font-size: var(--font-sm);
  font-weight: var(--weight-semibold);
  line-height: 1.35;
}
/* Печатный лист верстается как узкий экран. Лист A4 — 794 CSS-пикселя, а
   двухколоночные раскладки складываются ниже 760: бумага попадает ровно в
   зазор, узкая для двух колонок и широкая для складывания. Герой из-за
   этого печатался колонками 350px и 300px, вырастал до 1430px при листе в
   1123 и целиком уезжал со второго листа, оставляя первый пустым. Поэтому
   все девять блоков «сложить в одну колонку» распространены на `print`. */
@media (max-width: 760px), print {
  /* Плитки и факты — в одну колонку: на узком экране две колонки дают
     строку в три слова. */
  .kb-points,
  .kb-facts { grid-template-columns: 1fr; }

  .kb-cta { padding: var(--space-6); }

  .kb-lead {
    padding: var(--space-4) var(--space-5);
    font-size: var(--font-md);
  }
}


/* --- Раскладка статьи: свои правила, а не чужие ----------------------
   Сетка статьи трижды за вечер ломалась из-за того, что правило жило в
   `patterns/kb-article.css` и читало переменные, объявленные в другом
   файле. Здесь она объявлена в том же файле, где объявлены её значения, и
   у каждой переменной есть запасное значение: даже если объявление
   потеряется, правило останется валидным и сетка не схлопнется. */

.kb-layout {
  display: grid;
  /* Колонка статьи начинается там же, где хлебные крошки: `center`
     сдвигал её к середине, и текст не совпадал с крошками по левому краю. */
  grid-template-columns: minmax(0, var(--content-article, 680px)) 1fr;
  gap: var(--space-12, 48px);
  justify-content: start;
  align-items: start;
  padding: var(--space-8, 32px) 0 var(--space-20, 80px);
}

.kb-layout > article { min-width: 0; }

.kb-toc {
  justify-self: stretch;
  width: auto;
  position: sticky;
  top: calc(var(--space-16, 64px) + var(--space-4, 16px));
  align-self: start;
  max-height: calc(100vh - var(--space-20, 80px) - var(--space-6, 24px));
  overflow-y: auto;
}

.kb-prose { max-width: var(--content-article, 680px); }

/* `scroll-margin-top` у заголовков снят: он складывался бы с общим
   `scroll-padding-top` на `html` и отбрасывал цель на 185px вниз. Отступ
   под липкую шапку теперь один на весь сайт — см. base.css. */

@media (max-width: 900px) {
  .kb-layout {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-8, 32px);
  }

  .kb-toc { display: none; }
}


/* ============================================================================
   Появление при прокрутке — слой статьи
   ----------------------------------------------------------------------------
   До И14 внутренние страницы не получали появления ВООБЩЕ: список целей в
   `base.css` состоял из одних `.index-*`, то есть был написан под главную и
   молча не доставал ни до одной из шестнадцати статей. Каркас движения был,
   а на статьях не работал.

   `@keyframes rise` объявлен в `base.css`; `kb.css` грузится после него, так
   что дублировать не нужно.

   ОТЛИЧИЕ ОТ ГЛАВНОЙ, И ОНО СУЩЕСТВЕННОЕ. На главной анимируется
   СОДЕРЖИМОЕ ячеек, потому что `.index-counters` собрана встык: `gap: 1px`
   плюс фон-разделитель у контейнера, и прозрачная ячейка пропускает его
   насквозь полосой. На статьях таких сеток нет — проверено: `.kb-points`,
   `.kb-facts` и `.kb-footer-nav` разделены нормальными отступами без
   фона-подложки. Поэтому здесь безопасно двигать сами элементы.

   Оглавление `.kb-toc` намеренно НЕ анимируется: оно липкое, и появление
   по прокрутке у липкого элемента читается как сбой.

   Абзацы прозы тоже не анимируются — только заголовки разделов. Скраб на
   каждом абзаце превращает чтение в мерцание, а движение здесь обязано
   подчёркивать структуру, а не спорить с текстом.
   ========================================================================= */

@supports (animation-timeline: view()) {
  .kb-article-head > *,
  .kb-lead,
  .kb-prose h2,
  .kb-facts > *,
  .kb-points > *,
  .kb-related > *,
  .kb-cta > *,
  .kb-footer-nav > *,
  .faq-item {
    animation-name: rise;
    animation-timeline: view();
    animation-range: entry 0% entry 40%;
    animation-fill-mode: both;
    animation-timing-function: linear;
  }
}


/* Печать и снятое движение. Оба блока оставлены НАМЕРЕННО, хотя доказать
   их необходимость машиной не вышло: попытка снять блок печати и поймать
   это аудитом не сработала — в режиме печати браузер раскладывает весь
   документ, всё оказывается «в кадре», и прокруточная шкала отдаёт
   конечное состояние. То есть проверка печати зубов не имеет, и отчёт
   аудита об этом теперь говорит прямо, а не рапортует «чисто».

   Блок остаётся как страховка: снимок страницы целиком снимается с
   `reducedMotion: reduce`, а вот настоящая печать в PDF из браузера
   посетителя нами не проверена. Убирать защиту, полагаясь на то, что её
   не удалось опровергнуть, — не то же самое, что убедиться. */

@media print {
  .kb-article-head > *,
  .kb-lead,
  .kb-prose h2,
  .kb-facts > *,
  .kb-points > *,
  .kb-related > *,
  .kb-cta > *,
  .kb-footer-nav > *,
  .faq-item {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}


@media (prefers-reduced-motion: reduce) {
  .kb-article-head > *,
  .kb-lead,
  .kb-prose h2,
  .kb-facts > *,
  .kb-points > *,
  .kb-related > *,
  .kb-cta > *,
  .kb-footer-nav > *,
  .faq-item {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}

/* ============================================================================
   УКАЗАТЕЛЬ МЕСТА В ОГЛАВЛЕНИИ — перенос из bridge-waf-static

   То, чего здесь не было и ради чего тело статьи разбито на секции: пункт
   оглавления сам показывает, где читатель. Без скрипта — раздел объявляет
   именованную прокруточную шкалу, ссылка на неё подписывается,
   `timeline-scope` нужен потому, что ссылка разделу не потомок.

   СМЫСЛ НЕ «ТЕКУЩИЙ РАЗДЕЛ», А СЛЕД ПРОЧИТАННОГО, и это решение эталона,
   записанное там же: «подсветить ровно текущий раздел» на шкалах не
   выражается — в кадре почти всегда два-три раздела разом, и три горящих
   пункта читаются как сбой. Поэтому раздел в кадре горит акцентом,
   пройденный остаётся приглушённым, непрочитанный тусклый. Пересечение
   соседних при таком чтении не ошибка.

   Только длинные свойства: шорткат `animation:` сбрасывает
   `animation-range`, и общее правило с меньшей специфичностью его уже не
   вернёт. Ту же ловушку ловит `scripts/check-css-local.py`, правило 4.

   Где браузер шкал не знает, оглавление просто без подсветки.
   ========================================================================= */
/* РОЛИ РАЗВЕДЕНЫ, И ЭТО ОТСТУПЛЕНИЕ ОТ ЭТАЛОНА — намеренное.

   В эталоне и шкала, и скрипт красят ОДНО И ТО ЖЕ: левую границу пункта.
   На его глоссарии из двух разделов это незаметно, на статье из семи —
   сразу: скрипт помечал третий пункт, шкала подсвечивала шестой, и в
   оглавлении горели два указателя в разных местах. Тот самый сбой, о
   котором эталон предупреждает в собственном комментарии, только не от
   трёх горящих, а от двух механизмов на одном свойстве.

   Здесь каждый механизм отвечает за то, что умеет точно:
     скрипт (`is-active`) — ГРАНИЦА и вес: где читатель ровно сейчас;
     шкала (`toc-read`)   — ЦВЕТ ТЕКСТА: что уже пройдено.
   Указатель один, а прочитанное видно градиентом. Пересечения нет. */
/* ТРИ УРОВНЯ, А НЕ ДВА. Первая версия заканчивала анимацию тем же
   `--text-muted`, с которого начинают непрочитанные пункты, — прочитанное
   и нетронутое выглядели одинаково, и след не читался вовсе. Уровни:
     непрочитанный  --text-muted      (тусклее всех, базовое правило)
     в кадре        --text-primary    (ярче всех)
     прочитанный    --text-secondary  (между ними)
   Так же устроено у эталона: там база `--dim`, а прочитанное `--muted`. */
@keyframes toc-read {
  0%,  99% { color: var(--text-primary); }
  100%     { color: var(--text-secondary); }
}


@supports (animation-timeline: view()) {
  .kb-layout {
    timeline-scope: --s1, --s2, --s3, --s4, --s5, --s6, --s7, --s8, --s9, --s10;
  }

  .kb-prose > section:nth-of-type(1)  { view-timeline-name: --s1; }
  .kb-prose > section:nth-of-type(2)  { view-timeline-name: --s2; }
  .kb-prose > section:nth-of-type(3)  { view-timeline-name: --s3; }
  .kb-prose > section:nth-of-type(4)  { view-timeline-name: --s4; }
  .kb-prose > section:nth-of-type(5)  { view-timeline-name: --s5; }
  .kb-prose > section:nth-of-type(6)  { view-timeline-name: --s6; }
  .kb-prose > section:nth-of-type(7)  { view-timeline-name: --s7; }
  .kb-prose > section:nth-of-type(8)  { view-timeline-name: --s8; }
  .kb-prose > section:nth-of-type(9)  { view-timeline-name: --s9; }
  .kb-prose > section:nth-of-type(10) { view-timeline-name: --s10; }

  .kb-toc a {
    animation-timing-function: linear;
    animation-fill-mode: forwards;
    animation-range: entry 88% exit 8%;
  }

  .kb-toc li:nth-child(1)  a { animation-name: toc-read; animation-timeline: --s1; }
  .kb-toc li:nth-child(2)  a { animation-name: toc-read; animation-timeline: --s2; }
  .kb-toc li:nth-child(3)  a { animation-name: toc-read; animation-timeline: --s3; }
  .kb-toc li:nth-child(4)  a { animation-name: toc-read; animation-timeline: --s4; }
  .kb-toc li:nth-child(5)  a { animation-name: toc-read; animation-timeline: --s5; }
  .kb-toc li:nth-child(6)  a { animation-name: toc-read; animation-timeline: --s6; }
  .kb-toc li:nth-child(7)  a { animation-name: toc-read; animation-timeline: --s7; }
  .kb-toc li:nth-child(8)  a { animation-name: toc-read; animation-timeline: --s8; }
  .kb-toc li:nth-child(9)  a { animation-name: toc-read; animation-timeline: --s9; }
  .kb-toc li:nth-child(10) a { animation-name: toc-read; animation-timeline: --s10; }
}

/* ============================================================================
   СХЕМЫ В СТАТЬЯХ

   До этого их не было ни одной: на главной 24 схемы, в шестнадцати статьях
   ноль, а те 39 «svg», что там числились, оказались шевронами в карточках.
   У эталона схема стоит в каждой статье — 93 на 50 страниц.

   Язык взят с главной, а не из эталона: там своя пара словарей, и второй
   диалект на одном сайте читался бы как чужая вставка. Но идиома главной —
   «каждой схеме свой префикс» (sd-, tl-, pl-, mv-…) — на тридцать схем не
   тянется, поэтому здесь ОБЩИЙ компактный набор в той же интонации:
   инлайновый SVG, семантические классы, описание для экранного диктора.

   ЗАЛИВКА ЗАДАЁТСЯ КЛАССОМ, НЕ АТРИБУТОМ. Правило класса перебивает
   презентационный `fill=`, и схема, покрашенная атрибутом, молча уходит в
   серый при смене темы. Это же ловит `scripts/check-css-local.py`.
   ========================================================================= */
@property --viz-fade {
  syntax: '<length>';
  inherits: false;
  initial-value: 0px;
}


@keyframes viz-edge {
  from { --viz-fade: 40px; }
  to   { --viz-fade: 0px; }
}


.kb-viz {
  margin: var(--space-8) 0;
}


/* ---- растровый арт библиотеки сети ---- */

/* Пара тем живёт в DOM одновременно, как логотипы шапки (base.css,
   .brand-logo-*): тему выбирает CSS, скрипту выбирать нечего. Селектор
   скрытия — в две классовых ступени, иначе `.kb-art img { display: block }`
   перебивает одноступенчатое скрытие по специфичности. Обе копии ленивые:
   блок стоит второй секцией и в LCP не участвует, hero-приоритетов ему
   не положено. */
.kb-art { margin: var(--space-8) 0; }
.kb-art img { display: block; width: 100%; height: auto; border-radius: var(--radius-lg); }
.kb-art .kb-art-light { display: none; }
[data-theme="proof-light"] .kb-art .kb-art-dark { display: none; }
[data-theme="proof-light"] .kb-art .kb-art-light { display: block; }


/* Схема не обрезает собственные подписи. У `<svg>` в браузерном стиле стоит
   `overflow: hidden`, то есть он режет всё, что вышло за `viewBox`. При
   обычных настройках наружу не выходит ничего, а под интервалами из WCAG
   1.4.12 (межстрочный 1.5, межбуквенный 0.12em, межсловный 0.16em) подписи
   растут и упираются в край.

   Измерено: на четырёх страницах подпись выходила за коробку SVG на 6–23px и
   срезалась ПОСЕРЕДИНЕ СЛОВА — «not because of anything set on your s». Домотать
   до неё нельзя: полоса `.kb-viz` прокручивает сам SVG, а режет он внутри себя,
   до своей границы. Содержимое терялось безвозвратно, и это прямое
   несоответствие 1.4.12: критерий требует, чтобы при этих интервалах ничего не
   пропадало.

   `visible` вместо обрезания: подпись выходит за коробку и дочитывается. При
   обычных интервалах не меняется ничего — наружу нечему выходить (замерено 0px
   на 390 и 1440).

   `check-viz-box` от этого не слепнет: она разбирает РАЗМЕТКУ и сравнивает
   координаты с `viewBox`, а не смотрит, обрезал ли браузер. Рамка, вышедшая за
   поле, по-прежнему ловится — только теперь она была бы видна, а не съедена. */
.kb-viz svg {
  overflow: visible;
}


/* Схема прокручивается на узких экранах, а прокручиваемая область обязана
   доставаться с клавиатуры — иначе её содержимое недостижимо для тех, кто
   не пользуется указателем. Отсюда tabindex="0" на фигуре и видимая рамка
   при фокусе с клавиатуры (при щелчке мышью не показывается). */
.kb-viz:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: var(--radius-sm, 6px);
}


.kb-viz svg {
  display: block;
  width: 100%;
  height: auto;
}


/* Схемы нарисованы в полосе 720 и подписаны текстом в 12 единиц viewBox.
   Единицы масштабируются вместе с рамкой, поэтому на телефоне, где рейл
   статьи 342px, подпись выезжала в 5.7px — нечитаемо. Ни одна проверка не
   возражала: сжатая схема формально не обрезана, audit-browser ищет
   обрезку, а не читаемость.

   Уменьшать полосу нельзя (схемы держат по две-три коробки в ряд), а
   увеличивать шрифт в единицах — значит ломать раскладку: коробки
   размечены под текущий кегль. Остаётся дать схеме прокрутку: рисунок
   остаётся тем же, что на десктопе, и не тянет за собой тело страницы.

   680 — это ровно ширина рейла статьи на широком экране, и взято оно не на
   глаз: при 640 подпись выходила в 8.9px против 9.4px на десктопе, то есть
   телефон всё равно получал схему мельче. Проверка check-viz-legible
   сравнивает именно это и на 640 отказывала. */
@media (max-width: 660px) {
  .kb-viz {
    overflow-x: auto;
    overscroll-behavior-x: contain;
  }

  .kb-viz svg { min-width: 680px; }

  /* Подсказка, что схема прокручивается: правый край растворяется, пока
     справа ещё что-то есть, и сходит на нет, когда дочитано до конца.
     Статичное затухание врало бы в конце прокрутки, поэтому длина привязана
     к самой прокрутке — scroll(self inline), тот же приём, на котором
     держится движение по остальному сайту.

     @supports здесь нет намеренно: комплект сети запрещает вложенность
     глубже «медиазапрос → правило», а гарантия достигается иначе. Начальное
     значение --viz-fade — ноль, а сорок берётся из кадра from. Там, где
     прокруточной шкалы нет, анимация без длительности мгновенно доигрывает
     до to, то есть до нуля, и затухания не появляется вовсе. Ложной
     подсказки не будет ни в одном браузере. */
  .kb-viz {
    mask-image: linear-gradient(to right, #000 calc(100% - var(--viz-fade)), transparent);
    animation: viz-edge linear both;
    animation-timeline: scroll(self inline);
  }
}


/* Подпись выравнивается по РИСУНКУ, а не по прозе. У схем внутренний отступ
   в 8 единиц viewBox (нужен, чтобы штрих крайней рамки не срезался краем), и
   на широком экране это 8px: надзаголовок схемы стоял на 128, а подпись под
   ним на 120. Восемь пикселей достаточно, чтобы фигура читалась не как один
   блок, а как две неровно положенные вещи. Отступ задан долей ширины, а не
   пикселями, чтобы он оставался равен внутреннему при любой полосе. */
.kb-viz figcaption {
  margin-top: var(--space-2);
  padding-left: calc(100% * 8 / 720);
  color: var(--text-muted);
  font-size: var(--font-xs);
}


/* ---- примитивы ---- */

/* Контур обычной коробки — `--viz-line`, а не `--border-subtle`. Замер:
   subtle давал 1.06:1 в тёмной теме и 1.10:1 в светлой против настоящей
   подложки, при норме 3:1 для графики, несущей смысл (WCAG 1.4.11).
   Коробка держалась одной заливкой, а заливка против фона это 1.01:1: на
   снимке в масштабе 1 рамка пропадала совсем. Различают состояния теперь
   не яркость линии, а рисунок и тон: обычная — сплошная, открытая —
   пунктир, подсвеченная — акцент. Проверка check-viz-contrast, часть про
   штрихи. */
.kv-box       { fill: var(--bg-elevated); stroke: var(--viz-line); stroke-width: 1; }
.kv-box--on   { fill: var(--accent-soft); stroke: var(--accent); }
.kv-box--open { fill: none; stroke: var(--viz-line); stroke-dasharray: 4 4; }

.kv-label     { fill: var(--text-secondary); font-family: var(--font-family); font-size: 12px; }
.kv-label--on { fill: var(--accent-secondary); }
.kv-label--dim{ fill: var(--text-muted); }
.kv-label--kicker {
  fill: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
}

.kv-wire      { fill: none; stroke: var(--viz-line); stroke-width: 1.5; }
.kv-wire--on  { stroke: var(--accent); }

/* Неактивный провод отличается ЦВЕТОМ И ТОЛЩИНОЙ, а не пунктиром, и это
   не выбор вкуса. `kv-draw` занимает `stroke-dasharray` под длину линии —
   иначе прочерчивания не сделать, — и любой декоративный пунктир на том
   же элементе молча пропадает. Поймано на второй же схеме: серые провода
   рисовались сплошными, хотя правило просило пунктир. Пунктир остался
   там, где прочерчивания нет: у рамок `kv-box--open` и границы. */
.kv-wire--idle{ stroke-width: 1; }

.kv-dot       { fill: var(--accent); }

/* Граница ответственности: слева наша сторона, справа решает движок. Тот
   же приём, что у `.pl-boundary` на главной, — вертикальный пунктир. */
.kv-bound     { stroke: var(--viz-line); stroke-width: 1; stroke-dasharray: 3 4; }


/* ---- движение ----

   Два вида, и оба со смыслом, а не для оживления. `kv-draw` проводит линию
   по мере прокрутки: читатель видит, как связь возникает, ровно когда
   доходит до неё в тексте. `kv-lit` — короткий цикл на узле, который в
   тексте назван действующим.

   Прокруточная часть объявлена внутри `@supports`: без поддержки шкал
   `animation: … both` отыграла бы один раз при загрузке — все линии
   провелись бы разом, до того как читатель до них дошёл. */
@keyframes kv-draw { to { stroke-dashoffset: 0; } }
@keyframes kv-lit  { 0%, 100% { opacity: 0.5; } 20%, 44% { opacity: 1; } }

/* Классы задержки (kv-d1…) не заведены заранее: пока ни одна схема не
   держит несколько мигающих узлов сразу. Появятся вместе с той схемой,
   которой понадобятся, — правило без применения это правило, которое
   через месяц никто не решится тронуть. */
.kv-lit { animation: kv-lit var(--cycle, 4.4s) linear infinite; }

@supports (animation-timeline: view()) {
  /* Длина не пишется рукой: у каждого .kv-draw стоит pathLength="100",
     который нормирует настоящую длину пути к сотне, и штрих считается от
     неё. До этого --len задавалось на глаз, и на шести проводах оно было
     короче пути — линия не дорисовывалась до конца, а увидеть это можно
     было только рядом с исправной схемой. Проверка check-viz-len. */
  .kv-draw {
    stroke-dasharray: 100;
    stroke-dashoffset: 100;
    animation-name: kv-draw;
    animation-timing-function: linear;
    animation-fill-mode: both;
    animation-timeline: view();
    animation-range: entry 30% cover 45%;
  }
}


@media (prefers-reduced-motion: reduce) {
  .kv-lit { animation: none !important; opacity: 1; }
  .kv-draw { stroke-dashoffset: 0 !important; }
}


@media print {
  .kv-lit { animation: none !important; opacity: 1; }
  .kv-draw { stroke-dashoffset: 0 !important; }

  /* Заливка SVG — НЕ фон, и браузер её печатает. В тёмной теме
     `--bg-elevated` это #18181b, поэтому обычные коробки уходили на бумагу
     чёрными плашками с почти невидимым серым текстом поверх: на листе 2
     страницы /vs/ почти чёрных пикселей было 5.02% против 0.15% в светлой
     теме, и схема из шести коробок читалась как шесть клякс.

     Довод «браузер не печатает фоны», на котором стоит печатный блок в
     base.css, к SVG не относится вовсе — там это заливка фигуры. На бумаге
     коробку держит штрих, и его достаточно: подсвеченная отличается
     акцентным штрихом, открытая — пунктиром. */
  .kv-box,
  .kv-box--on,
  .kv-box--open { fill: none !important; }
}

/* ВНИМАНИЕ, ИСТОЧНИК ПРАВДЫ НЕ ЗДЕСЬ. Комплект держит это правило в
   `assets/css/components.css` (строка 235) с 2026-08-27, и там же его довод —
   B-66 закрыта им же. До наших копий правка не доехала: раздачу делает
   `bootstrap.py`, а он не запускался. B-66 это прямо и предсказывала:
   «indexnow и dns несут дефект до отдельной раскладки».

   Я нашёл дефект заново 2026-08-29, не посмотрев журнал, и починил ЗДЕСЬ —
   то есть завёл второе место для одного правила. Копию `components/` руками не
   патчил намеренно: она общая с сетью, и патчить её по кусочку значит получить
   полураскатанный файл, отличающийся и от комплекта, и от соседей. Решение —
   раскатать комплект целиком, и оно за владельцем (дополнение к B-66).

   Пока раскатки нет, правило нужно: без него обёртка не прокручивается.
   ---------------------------------------------------------------------------
   Обёртка таблицы наконец прокручивается. Она стоит в разметке трёх страниц,
   её ставит сборщик ровно ради этого — и правила к ней здесь не было ВОВСЕ:
   `overflow-x` вычислялся как `visible`. У всех трёх соседей по сети правило
   есть (`kb.css` одной строкой), у нас одного не доехало.

   Цена молчания мала и потому незаметна: на 320px таблица на /vs/sitemap/
   вылезала за обёртку на два пикселя и доскроллить до них было нельзя. Один
   из этих двух добавил я сам, задав подписям строк средний насыщенный
   шрифт; второй был там до меня. Дело не в двух пикселях, а в том, что при
   более широкой таблице или длинном слове обрезается сколько угодно.

   `margin-top` соседей НЕ переношу: у нас отступы между блоками задаёт
   `.kb-prose > * + *`, и второй источник их удвоил бы. `min-width: 520px`
   тоже нет — у соседей класс таблицы другой. */
.kb-table-wrap { overflow-x: auto; }

/* На 320px — самой узкой поддерживаемой ширине — из 288 доступных пикселей
   96 уходило во внутренние отступы ячеек: по 16 с каждой стороны трёх штук,
   треть ширины. `table-layout: auto` считает минимум по содержимому, и
   минимум выходил 290 против 288. Обёртка выше делает эти два пикселя
   достижимыми; здесь их просто не остаётся.

   Двенадцать, а не восемь: восемь убирают переполнение так же, но ячейка
   становится тесной. Выигрыш не в двух пикселях — таблица укорачивается с
   881px до 835, то есть переносов меньше и строка читается легче.

   Соседи по сети решают это иначе: у них `min-width: 520px`, и таблица на
   телефоне всегда прокручивается. У нас она ужимается, поэтому и отступы
   ужимаются вместе с ней — приём один, не два.

   Перелом 380px взят не с потолка: он уже используется в `base.css` для
   названия сайта в шапке. */
@media (max-width: 380px) {
  .kb-table-wrap th, .kb-table-wrap td { padding-inline: var(--space-3); }
}
