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

.landing-main {
  box-sizing: border-box;
  width: 100%;
  min-width: 0;
  padding: 0;
  overflow-x: clip;
}



/* ---- homepage module ---- */

.index-homepage {
  --index-page: min(100% - 80px, 1200px);
  /* Тон «зелёного» берёт роль ТЕКСТА, а не знака — та же правка, что в
     tokens.css. Здесь она нужна отдельно: этот блок переопределяет токен
     для всей главной, и на `:root` его значение до элементов не доходит.
     Токенная проверка контраста читает `:root` и потому молчала; поймал
     браузерный аудит, который меряет отрисованное. Пять подписей на схемах
     оставались знаком: 3.8–4.0:1 при норме 4.5 на 12 пикселях. */
  --index-tone-green-fg: var(--accent-secondary);
  --index-tone-green-soft: var(--accent-soft);
  --index-tone-amber-fg: var(--warning);
  --index-tone-amber-soft: var(--warning-soft);
  --index-tone-teal-fg: var(--accent-secondary);
  --index-tone-teal-soft: color-mix(in srgb, var(--index-tone-teal-fg) 18%, transparent);
  --index-tone-success-fg: var(--success);
  --index-tone-success-soft: var(--success-soft);
  background: var(--bg);
  color: var(--text-primary);
  /* `clip`, а не `hidden`. Разница не косметическая: `hidden` делает элемент
     прокруточным контейнером, и `position: sticky` внутри начинает считаться
     от него — то есть перестаёт липнуть вовсе. Именно это и происходило:
     десять заголовков секций объявлены `sticky; top: 80px`, и ни один не
     липнул. Проверено поведением, а не правилом: заголовок уезжал в −120,
     −320, −620 при прокрутке вместо того, чтобы замереть на 80.

     Замысел записан в этом же файле, у самого правила: «шапка уходит в узкую
     колонку и липнет при прокрутке — она работает указателем, где ты
     находишься». Он не исполнялся ни разу.

     `overflow: hidden` здесь из эталона, и у waf с ssl он такой же — но у них
     НЕТ правила `sticky` на заголовках секций, оно наше. Приём `clip` в этом
     коде уже применён этажом выше: у `main.landing-main` стоит `clip visible`
     ровно за тем же.

     Обрезание сохраняется: страница вбок не едет ни на одной ширине от 320 до
     1600 — измерено до и после. */
  overflow: clip;
}



/* Load-bearing reset: section rhythm comes from flex/grid gap, not element
   margins. Any margin added inside this module needs a two-class selector. */
.index-homepage h1,
.index-homepage h2,
.index-homepage h3,
.index-homepage p { margin: 0; }



.index-homepage h1,
.index-homepage h2,
.index-homepage h3 { letter-spacing: 0; }



.index-content-rail {
  max-width: 760px;
  margin-inline: 0;
  width: 100%;
}



.index-section {
  width: var(--index-page);
  margin: 0 auto;
  padding: calc(var(--space-12) + var(--space-6)) 0;
  border-bottom: 1px solid var(--border-subtle);
}



.index-section-header { margin-bottom: calc(var(--space-8) + var(--space-2)); }


.index-section-header .index-kicker { margin-bottom: var(--space-3); }



.index-section-header--center {
  margin-inline: auto;
  text-align: center;
}



.index-section-header--center .index-copy { margin-inline: auto; }



.index-section h2 {
  margin-bottom: var(--space-5);
  color: var(--text-primary);
  font-size: clamp(28px, 3vw, 38px);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.015em;
}



.index-section h3 {
  color: var(--text-primary);
  font-size: var(--font-lg);
  font-weight: 600;
}



/* --accent only reaches 3.3:1 on the dark background at 12px; --accent-secondary
   is the lighter indigo in dark and resolves to --accent in light. */
.index-kicker {
  color: var(--accent-secondary);
  font-size: var(--font-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}



.index-copy {
  max-width: 640px;
  color: var(--text-secondary);
  font-size: var(--font-md);
  line-height: 1.65;
}



/* ---- hero ---- */

.index-hero {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  padding: var(--space-6) var(--space-10) calc(var(--space-12) + var(--space-8));
  border-bottom: 1px solid var(--border-subtle);
  /* Герой себя НЕ красит: под ним фиксированные слои сети (`.site-bg` с
     сеткой и свечениями). Своя заливка накрыла бы их целиком — именно так
     и было до переноса. */
  isolation: isolate;
}



/* Shared grain overlay — the hero and the closing CTA are the two "panel" surfaces
   that carry it. One rule, one data URI; both hosts set isolation + overflow. */
.index-noise::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E");
  background-size: 180px 180px;
  pointer-events: none;
}



.index-hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(400px, 0.85fr);
  align-items: center;
  gap: 0;
  width: var(--index-page);
  margin: 0 auto;
  padding-top: calc(var(--space-16) + var(--space-8));
  padding-bottom: var(--space-12);
}



/* The title is sized off THIS box, not the viewport — the text column is a grid
   fraction of the page rail, so vw units over-ask and wrap the h1. container-type
   makes 8.6cqi the authoritative measure; the vw declaration above it is the
   fallback for engines without container queries. */
.index-hero-content {
  position: relative;
  z-index: 2;
  container-type: inline-size;
  container-name: hero;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  padding-inline-end: var(--space-8);
  animation: indexFadeUp 0.7s cubic-bezier(0.16, 1, 0.3, 1) both;
}



.index-title-line {
  display: block;
  white-space: nowrap;
  hyphens: none;
}



/* Акцентная строка красится ЗНАКОМ, а не янтарным. Янтарь в этой системе
   занят предупреждением (`--warning`), и обещание «is one button»,
   набранное им, читается как предостережение. Прежний заголовок кончался
   на «Skip the wait to», где янтарь ещё можно было оправдать ожиданием;
   новый — обещание, и цвет обязан быть акцентом. */
.index-title-accent { color: var(--accent-secondary); }


/* Вторая строка заголовка — тише, а не мельче ради экономии: приём эталона
   («вторая строка приглушённая, вес 400»). И она ОБЯЗАНА переноситься.

   `.index-title-line` несёт `white-space: nowrap`, и это было безопасно,
   пока заголовок состоял из трёх коротких строк. Новая строка длинная, и
   в неразрывном виде она выезжала из текстовой колонки прямо НА ПАНЕЛЬ
   отправки, накрывая её заголовок. Ни одна проверка этого не увидела:
   контраст в порядке, страница вбок не едет, обрезанного нет — просто два
   элемента наложились. Нашлось только когда я посмотрел на страницу. */
.index-title-second {
  margin-top: var(--space-3);
  color: var(--text-secondary);
  font-size: clamp(17px, 2.2cqi, 22px);
  font-weight: var(--weight-regular);
  letter-spacing: -0.01em;
  line-height: var(--leading-snug);
  white-space: normal;
  text-wrap: pretty;
}






.index-title {
  max-width: none;
  color: var(--text-primary);
  font-size: clamp(24px, 4.2vw, 58px);
  font-size: clamp(24px, 8.6cqi, 58px);
  font-weight: 600;
  line-height: 1.06;
  letter-spacing: -0.02em;
  text-wrap: balance;
}



.index-lead {
  max-width: 720px;
  color: var(--text-secondary);
  font-size: clamp(17px, 1.6vw, 20px);
  font-weight: var(--weight-regular);
  line-height: 1.55;
}



/* ---- icon tiles ---- */

.index-icon-tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  background: var(--bg-panel-soft);
  border: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  flex-shrink: 0;
}



.index-icon-tile svg { width: 20px; height: 20px; }









.index-icon-tile.tone-teal {
  background: var(--index-tone-teal-soft);
  border-color: color-mix(in srgb, var(--index-tone-teal-fg) 28%, var(--border-subtle));
  color: var(--index-tone-teal-fg);
}






/* ---- capability grid ---- */

.index-parity-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-10) calc(var(--space-12) + var(--space-4));
  max-width: 980px;
  margin: 0 auto;
  padding: 0;
  list-style: none;
}



/* ============================================================================
   АРТ ФИЧИ В ГЕРОЕ

   До 2026-09-02 здесь стоял знак сети — маска моста с bridge-cdn.com,
   один файл на обе темы, цвет задавал CSS (довод эталона: «единственная
   графика, по которой посетитель узнаёт, что перешёл внутри одной
   экосистемы»). Решением владельца знак заменён на арт собственной фичи
   из библиотеки сети (`media-assets/features/indexnow-hero-*`): маяки,
   вещающие с моста, — образ announcement, то есть самой страницы.

   Фон арта вырезан в альфу заранее (расключение от чёрного/белого,
   images/indexnow-hero-{dark,light}-alpha.webp, 88 и 93 КиБ) — точки
   лежат прямо на фоне страницы, у каждой темы своя копия.

   Композиция унаследована от маски: у waf справа свободно, здесь справа
   панель отправки, поэтому арт смещён ниже и левее, а градиент ::after
   по-прежнему гасит его под текстом — это условие читаемости, не
   украшение. */
.index-hero-art {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  background-image: url("/images/indexnow-hero-dark-alpha.webp");
  background-repeat: no-repeat;
  /* Правая колонка героя освободилась 09.09.2026 (панель отправки снята по
     решению владельца), и арт поднят в неё с нижнего края: раньше его
     резала полоса под героем, теперь он стоит рядом с текстом целиком. */
  background-position: 100% 42%;
  background-size: min(820px, 58%) auto;
  opacity: 0.9;
}


:root[data-theme="proof-light"] .index-hero-art {
  background-image: url("/images/indexnow-hero-light-alpha.webp");
  opacity: 0.85;
}


/* Текст не спорит с мостом: слева сплошная подложка, к правому краю она
   растворяется, и знак читается только там, где под ним ничего нет. */
.index-hero-art::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg,
    var(--bg) 24%,
    color-mix(in srgb, var(--bg) 90%, transparent) 48%,
    transparent 78%);
}


@media (max-width: 900px) {
  .index-hero-art {
    background-size: 150% auto;
    opacity: 0.3;
  }
}


/* ============================================================================
   СЕКЦИЯ МАРШРУТОВ — ОДНА ПОЛОСА

   Замер до правки: заголовок 760px слева, сетка карточек 980px по центру,
   проза 640px слева, таблица 1200px во всю ширину. Четыре блока — четыре
   разных выравнивания, и глаз читал это как «наполовину, потом по центру,
   потом снова наполовину». Владелец выбрал вариант «всё на одну полосу».

   Правка ОБЛАСТНАЯ, не глобальная: те же классы в соседних секциях держат
   свой ритм намеренно — узкая мера для чтения, широкий рельс для карточек.
   Здесь ритм ломался, там работает.

   Оговорка, сказанная владельцу при выборе, и замер после правки: строка
   прозы вышла ~152 знака при удобной для чтения мере 65–75. Для сравнения,
   в соседних секциях та же проза даёт ~38 знаков — там она стоит в узкой
   колонке. Выбор сделан с этим знанием; узкая мера возвращается снятием
   `#routes .index-copy` из правила ниже.
   ========================================================================= */
#routes .index-section-header,
#routes .index-copy {
  max-width: none;
  margin-inline: 0;
}


#routes .index-parity-grid {
  max-width: none;
  margin-inline: 0;
}


/* Ритм после сетки маршрутов. У `#routes` нет обёртки
   `.index-section-body`, которая в остальных секциях раздаёт `gap`, —
   отступы держатся на полях самих элементов, а у сетки его не было.
   До правки вложенности проза лежала ВНУТРИ ячейки и отступ брала
   оттуда; когда она встала на своё место, между сеткой и абзацем
   оказался ноль. */
.index-parity-grid + .index-copy { margin-top: var(--space-8); }


.index-parity-item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  min-width: 0;
}



.index-parity-body {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
  padding-top: 2px;
}



.index-parity-title {
  color: var(--text-primary);
  font-size: var(--font-md);
  font-weight: var(--weight-semibold);
  line-height: 1.3;
}



.index-parity-desc {
  color: var(--text-secondary);
  font-size: var(--font-sm);
  line-height: 1.55;
}



.index-flagship .index-icon-tile { margin-bottom: var(--space-4); }



.index-homepage .index-flagship h2 {
  margin-bottom: var(--space-4);
  color: var(--accent-secondary);
  font-size: clamp(24px, 2.4vw, 32px);
}



.index-homepage .index-flagship .index-copy {
  margin-bottom: var(--space-8);
  max-width: 780px;
}



.index-homepage .index-migration h2 { margin-bottom: var(--space-4); }


.index-homepage .index-migration .index-copy { margin-bottom: var(--space-6); }



.index-homepage .index-migration .index-copy { max-width: none; }



/* ---- FAQ ---- */

.index-faq-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4);
}



.index-faq-item {
  display: grid;
  gap: var(--space-2);
  min-width: 0;
  padding: var(--space-6);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-panel-soft);
}



.index-faq-item h3 {
  color: var(--text-primary);
  font-size: var(--font-md);
  font-weight: 600;
  line-height: 1.3;
}



.index-faq-item p {
  color: var(--text-secondary);
  font-size: var(--font-sm);
  line-height: 1.6;
}



/* ---- final CTA ---- */

/* The hero's bookend: same surface colour, same grain, same accent wash — the
   old --bg-hero-on---bg pairing was a 2-value delta and read as an empty section. */
.index-final {
  position: relative;
  isolation: isolate;
  width: var(--index-page);
  margin: var(--space-16) auto var(--space-20);
  padding: calc(var(--space-16) + var(--space-4)) var(--space-12);
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--border-strong));
  border-radius: var(--radius-xl);
  /* Финальный блок остаётся карточкой и красится сам, но уже цветом
     приподнятой поверхности сети, а не прежним тёплым `--index-hero-bg`. */
  background-color: var(--bg-hero);
  background-image: radial-gradient(120% 110% at 50% 0%, var(--accent-soft), transparent 62%);
  text-align: center;
  overflow: hidden;
}



/* Ракета из реестра сети здесь ни к чему: блок про то, где живёт функция,
   и знак — монограмма моста, той же парой файлов и тем же переключением
   темы, что в шапке (`.brand-logo`). Владелец, 09.09.2026. */
.index-final-mark {
  position: relative;
  z-index: 2;
  display: block;
  margin: 0 auto var(--space-5);
}


.index-final-mark .brand-logo { width: 64px; height: 64px; margin: 0 auto; }



.index-homepage .index-final h2 {
  position: relative;
  z-index: 2;
  margin-bottom: var(--space-4);
  font-size: clamp(26px, 2.8vw, 38px);
  line-height: 1.1;
  letter-spacing: -0.015em;
}



.index-final p {
  position: relative;
  z-index: 2;
  max-width: 54ch;
  margin-inline: auto;
  color: var(--text-secondary);
  font-size: var(--font-md);
  line-height: 1.65;
}



.index-actions--center {
  position: relative;
  z-index: 2;
  justify-content: center;
  margin-top: var(--space-8);
}



/* Three coupled declarations: `.index-final p` caps every paragraph at 54ch and
   16px, which silently defeats the note's 100% flex-basis and keeps it on the
   button row. max-width + shrink restore the wrap; font-size restores the scale. */
.index-actions--center .index-actions-note {
  flex-shrink: 0;
  max-width: none;
  margin-top: var(--space-2);
  font-size: var(--font-sm);
  text-align: center;
}
@media (max-width: 1080px) {
  .index-homepage { --index-page: min(100% - 64px, 1180px); }



  .index-hero-grid {
    grid-template-columns: minmax(0, 1.25fr) minmax(300px, 0.75fr);
    padding-top: calc(var(--space-12) + var(--space-6));
  }



}

/* Печатный лист верстается как узкий экран. Лист A4 — 794 CSS-пикселя, а
   двухколоночные раскладки складываются ниже 760: бумага попадает ровно в
   зазор, узкая для двух колонок и широкая для складывания. Герой из-за
   этого печатался колонками 350px и 300px, вырастал до 1430px при листе в
   1123 и целиком уезжал со второго листа, оставляя первый пустым. Поэтому
   все девять блоков «сложить в одну колонку» распространены на `print`. */
@media (max-width: 760px), print {
  .index-homepage { --index-page: min(100% - 32px, 1180px); }



  .index-hero {
    min-height: auto;
    padding: var(--space-4) var(--space-4) var(--space-10);
  }



  .index-hero-grid {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-8);
    padding-top: var(--space-10);
    padding-bottom: 0;
  }






  .index-hero-content { order: 1; padding-inline-end: 0; }



  .index-section { padding-block: var(--space-10); }



  .index-faq-grid { grid-template-columns: 1fr; }


  .index-parity-grid { grid-template-columns: 1fr; }



  .index-final { margin: var(--space-10) auto var(--space-12); padding: var(--space-8) var(--space-6); }
}



/* --- Дельта сайта ssl (в эталоне этого блока нет) --------------------- */

/* Заголовок навигационной плитки — ссылка, но красится как заголовок:
   акцентный цвет на восьми плитках подряд читается как список ссылок,
   а не как сетка разделов. Подчёркивание появляется на наведении. */
.index-parity-title a {
  color: inherit;
  text-decoration: none;
}

.index-parity-title a:hover {
  color: var(--accent-secondary);
  text-decoration: underline;
  text-underline-offset: 3px;
}


/* ============================================================================
   Разделы главной: реестр
   ----------------------------------------------------------------------------
   До этого блока все разделы главной шли одной центрированной шапкой, и
   страница читалась как один блок, повторённый семь раз. Два самых важных
   раздела — область действия и файл ключа — не имели формы вообще: заголовок
   и слитый абзац на тысячу знаков.

   Здесь у каждого раздела своя фигура, а типографика несёт роль: МОНО — это
   факт, который можно предъявить (номер условия, ярлык ступени, путь к файлу),
   САНС — объяснение. Оба начертания уже лежат в /fonts, внешних запросов нет.
   ========================================================================= */

.index-homepage {
  --index-tone-danger-fg: var(--danger);
  --index-tone-danger-soft: color-mix(in srgb, var(--danger) 14%, transparent);
  /* muted берёт --text-secondary, а не --text-muted: последний даёт на тёмной
     земле 4.0:1 и не проходит порог 4.5:1 канона. */
  --index-tone-muted-fg: var(--text-secondary);
  --index-tone-muted-soft: color-mix(in srgb, var(--text-secondary) 10%, transparent);
  --index-rule: color-mix(in srgb, var(--border-strong) 55%, transparent);
}


/* ---- шапка раздела: левый режим ---- */

.index-section-header--start {
  margin-inline: 0;
  text-align: start;
}


/* Волосяная линия под кикером держит левый край: без неё левая шапка на
   широком экране повисает в пустоте и читается как случайно сдвинутая. */
.index-section-header--start .index-kicker {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}


.index-section-header--start .index-kicker::before {
  content: '';
  width: 18px;
  height: 1px;
  background: currentColor;
  opacity: 0.7;
}


/* ---- раздел-вердикт ---- */

/* Самый частый вопрос области — «участвует ли Google» — и ответ на него
   «нет». Ответ обязан читаться раньше, чем посетитель начнёт читать, иначе
   он уходит искать его заново. Поэтому это единственный раздел с заливкой. */


.index-verdict {
  display: grid;
  gap: var(--space-5);
  max-width: 900px;
}


/* Здесь стояла янтарная карточка со значком и тёплая полоса на всю ширину
   (`.index-section--verdict::before`). Снято 09.09.2026 по решению
   владельца: раздел читался как предупреждение и оттягивал внимание. Ответ
   несёт размер первой фразы, а не цвет. */
.index-verdict-body { display: grid; gap: var(--space-4); min-width: 0; }


/* Вердикт крупнее основного текста, но мельче H2: он ответ, а не заголовок. */
.index-verdict-claim {
  color: var(--text-primary);
  font-size: clamp(19px, 2vw, 24px);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.01em;
  text-wrap: balance;
}


.index-verdict-note {
  max-width: 62ch;
  color: var(--text-secondary);
  font-size: var(--font-md);
  line-height: 1.65;
}


/* Дословная формулировка области действия. Канон требует её почти слово в
   слово, поэтому она подана как цитата из документа, а не как обычный абзац. */
.index-ledger-statement {
  padding: var(--space-5) var(--space-6);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--bg-panel-soft);
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: var(--font-md);
  line-height: 1.6;
}


.index-ledger-note,
.index-chain-close,
.index-mech-note {
  max-width: 62ch;
  color: var(--text-secondary);
  font-size: var(--font-md);
  line-height: 1.65;
}


/* ---- ступени участия ---- */

.index-tier-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: var(--space-5);
  max-width: none;
  margin: 0;
  padding: 0;
  list-style: none;
}


.index-tier {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-6);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
}


.index-tier-icon {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: var(--radius-md);
  background: var(--index-tone-teal-soft);
  color: var(--index-tone-teal-fg);
}




.index-tier-icon svg { width: 20px; height: 20px; }


/* Ярлык ступени — моно: это статус в системе, а не фраза автора. */
.index-tier-label {
  color: var(--index-tone-teal-fg);
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}




.index-tier-title {
  color: var(--text-primary);
  font-size: var(--font-xl);
  font-weight: 600;
  line-height: 1.25;
}


.index-tier-desc {
  color: var(--text-secondary);
  font-size: var(--font-md);
  line-height: 1.6;
}


/* ---- кому подходит ---- */

.index-fit-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: var(--space-5);
  max-width: none;
  margin: 0;
  padding: 0;
  list-style: none;
}


/* Верхняя черта тоном — единственная разметка, отличающая «да» от «нет».
   Смысл при этом несёт сам текст заголовка, цвет только подтверждает: цвет
   в одиночку значение нести не должен. */
.index-fit {
  display: grid;
  gap: var(--space-3);
  align-content: start;
  padding: var(--space-6);
  border: 1px solid var(--border-subtle);
  border-block-start: 3px solid var(--index-tone-muted-fg);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
}


.index-fit--success { border-block-start-color: var(--index-tone-success-fg); }
.index-fit--danger { border-block-start-color: var(--index-tone-danger-fg); }
/* Визуально это ничего не меняет: база `.index-fit` уже стоит на
   `--index-tone-muted-fg`. Правило здесь ради набора — иначе из трёх
   модификаторов разметки в CSS названы два, и третий выглядит забытым, а
   не выбранным. Проверено измерением: до и после граница одна и та же. */
.index-fit--muted { border-block-start-color: var(--index-tone-muted-fg); }


.index-fit-title {
  color: var(--text-primary);
  font-size: var(--font-lg);
  font-weight: 600;
  line-height: 1.3;
}


.index-fit-desc {
  color: var(--text-secondary);
  font-size: var(--font-md);
  line-height: 1.6;
}


/* ---- механизм: файл ключа ---- */

.index-mech { display: grid; gap: var(--space-5); max-width: 900px; }


.index-mech-panel {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-5);
  align-items: start;
  padding: var(--space-6);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--bg-panel-soft);
}


.index-mech-icon {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  background: var(--index-tone-teal-soft);
  color: var(--index-tone-teal-fg);
}


.index-mech-icon svg { width: 22px; height: 22px; }


.index-mech-core {
  color: var(--text-primary);
  font-size: var(--font-lg);
  line-height: 1.6;
}


/* Путь к файлу — единственный зримый артефакт механизма; он и должен быть
   виден как артефакт, а не как слово в предложении. */
.index-mech-core code {
  padding: 2px 7px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--bg-elevated);
  color: var(--index-tone-teal-fg);
  font-family: var(--font-mono);
  font-size: 0.92em;
  white-space: nowrap;
}


@media (max-width: 760px), print {
  .index-chain-list,
  .index-tier-grid,
  .index-fit-grid { grid-template-columns: 1fr; }

  .index-verdict {
    grid-template-columns: 1fr;
    gap: var(--space-4);
    padding: var(--space-5);
  }

  .index-mech-panel {
    grid-template-columns: 1fr;
    gap: var(--space-4);
    padding: var(--space-5);
  }

  .index-ledger-statement { padding: var(--space-4) var(--space-5); }
}



/* Путь к файлу — единственное место с `nowrap`. На узком экране длинный
   хостнейм в нём уводит страницу в горизонтальную прокрутку, а её быть не
   должно ни на одной ширине. */
@media (max-width: 480px) {
  .index-mech-core code { white-space: normal; overflow-wrap: anywhere; }

  .index-tier,
  .index-fit,
  .index-step { padding: var(--space-5); }
}



/* ---- герой: схема сигнала ---- */

.index-signal {
  margin: 0;
  width: 100%;
}


.index-signal-svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}


.sd-card {
  fill: var(--bg-elevated);
  stroke: var(--border-strong);
  stroke-width: 1;
}


.sd-card--edge {
  fill: var(--accent-soft);
  stroke: color-mix(in srgb, var(--accent) 55%, var(--border-strong));
}


.sd-pill {
  fill: var(--bg-elevated);
  stroke: color-mix(in srgb, var(--accent-secondary) 45%, var(--border-subtle));
  stroke-width: 1;
}


.sd-pill--idle {
  fill: transparent;
  stroke: var(--border-strong);
  stroke-dasharray: 3 3;
}


/* Google стоит за чертой и не соединён ни с чем. Пустота справа от него —
   самая содержательная часть схемы, поэтому под него отведено место. */
.sd-pill--out {
  fill: transparent;
  stroke: color-mix(in srgb, var(--warning) 45%, var(--border-subtle));
}


.sd-label {
  fill: var(--text-primary);
  font-family: var(--font-family);
  font-size: 13px;
  font-weight: 500;
}


.sd-label--dim { fill: var(--text-secondary); font-weight: 400; }
.sd-label--out { fill: var(--text-secondary); }


.sd-sub {
  fill: var(--accent-secondary);
  font-family: var(--font-mono);
  font-size: 11px;
}


.sd-cap {
  fill: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}


.sd-cap--on { fill: var(--accent-secondary); }
.sd-cap--out { fill: var(--warning); text-anchor: end; }


.sd-wire {
  fill: none;
  stroke-width: 1.5;
  stroke-linecap: round;
}


/* Живой провод: бегущий штрих. Это единственная непрерывная анимация на
   странице — она показывает то, ради чего страница существует. */
.sd-wire--live {
  stroke: var(--accent-secondary);
  stroke-dasharray: 5 9;
  animation: sd-flow 1.5s linear infinite;
}


.sd-wire--idle {
  stroke: var(--border-strong);
  stroke-dasharray: 3 6;
}


.sd-dot--live { fill: var(--accent-secondary); }
.sd-dot--idle { fill: var(--text-muted); }


.sd-pulse {
  fill: var(--accent-secondary);
  animation: sd-pulse 2.4s ease-in-out infinite;
  /* Origin был задан числами (30px 140px) с прежней вёрстки схемы, а круг
     давно стоит на y=191: масштаб считался вокруг точки на 51px выше, и
     точка не пульсировала, а ездила вверх-вниз. fill-box привязывает
     origin к самому кругу и переживёт любую следующую перевёрстку. */
  transform-box: fill-box;
  transform-origin: center;
}


/* ---- переключатели схемы: только CSS ----
   Владелец просил дать пощёлкать движки, как в настройках продукта.
   JavaScript не добавляется (бюджет AGENTS §2, B-82): чекбоксы стоят
   ПЕРЕД svg в одной фигуре, и `:checked ~` красит провод, плашку и точку
   своей группы. Классы --live/--idle в разметке — состояние по умолчанию:
   без этих правил картинка остаётся прежней. Сам чекбокс спрятан клипом, а
   не display:none, чтобы оставаться в порядке табуляции; фокус и состояние
   рисуются на подписи. */
.sig-toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}


.sig-toggles {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-4);
}


.sig-label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 32px;
  padding: var(--space-1) var(--space-3) var(--space-1) var(--space-2);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill);
  background: var(--bg-elevated);
  color: var(--text-secondary);
  font-size: var(--font-sm);
  line-height: 1.2;
  cursor: pointer;
  user-select: none;
}


.sig-switch {
  position: relative;
  flex: none;
  width: 26px;
  height: 14px;
  border-radius: 7px;
  background: var(--border-strong);
  transition: background 0.15s var(--ease);
}


.sig-switch::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--bg);
  transition: transform 0.15s var(--ease);
}


#eng-bing:checked   ~ .sig-toggles [for="eng-bing"],
#eng-yandex:checked ~ .sig-toggles [for="eng-yandex"],
#eng-seznam:checked ~ .sig-toggles [for="eng-seznam"],
#eng-naver:checked  ~ .sig-toggles [for="eng-naver"],
#eng-yep:checked    ~ .sig-toggles [for="eng-yep"] {
  border-color: color-mix(in srgb, var(--accent-secondary) 40%, var(--border-subtle));
  color: var(--text-primary);
}


#eng-bing:checked   ~ .sig-toggles [for="eng-bing"] .sig-switch,
#eng-yandex:checked ~ .sig-toggles [for="eng-yandex"] .sig-switch,
#eng-seznam:checked ~ .sig-toggles [for="eng-seznam"] .sig-switch,
#eng-naver:checked  ~ .sig-toggles [for="eng-naver"] .sig-switch,
#eng-yep:checked    ~ .sig-toggles [for="eng-yep"] .sig-switch { background: var(--accent-secondary); }


#eng-bing:checked   ~ .sig-toggles [for="eng-bing"] .sig-switch::after,
#eng-yandex:checked ~ .sig-toggles [for="eng-yandex"] .sig-switch::after,
#eng-seznam:checked ~ .sig-toggles [for="eng-seznam"] .sig-switch::after,
#eng-naver:checked  ~ .sig-toggles [for="eng-naver"] .sig-switch::after,
#eng-yep:checked    ~ .sig-toggles [for="eng-yep"] .sig-switch::after { transform: translateX(12px); }


#eng-bing:focus-visible   ~ .sig-toggles [for="eng-bing"],
#eng-yandex:focus-visible ~ .sig-toggles [for="eng-yandex"],
#eng-seznam:focus-visible ~ .sig-toggles [for="eng-seznam"],
#eng-naver:focus-visible  ~ .sig-toggles [for="eng-naver"],
#eng-yep:focus-visible    ~ .sig-toggles [for="eng-yep"] {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}


/* Включён: провод живой, плашка и точка акцентные — как у Bing по умолчанию. */
#eng-bing:checked   ~ .index-signal-svg .sd-engine--bing .sd-wire,
#eng-yandex:checked ~ .index-signal-svg .sd-engine--yandex .sd-wire,
#eng-seznam:checked ~ .index-signal-svg .sd-engine--seznam .sd-wire,
#eng-naver:checked  ~ .index-signal-svg .sd-engine--naver .sd-wire,
#eng-yep:checked    ~ .index-signal-svg .sd-engine--yep .sd-wire {
  stroke: var(--accent-secondary);
  stroke-dasharray: 6 8;
  animation: sd-flow 1.5s linear infinite;
}
#eng-bing:checked   ~ .index-signal-svg .sd-engine--bing .sd-pill,
#eng-yandex:checked ~ .index-signal-svg .sd-engine--yandex .sd-pill,
#eng-seznam:checked ~ .index-signal-svg .sd-engine--seznam .sd-pill,
#eng-naver:checked  ~ .index-signal-svg .sd-engine--naver .sd-pill,
#eng-yep:checked    ~ .index-signal-svg .sd-engine--yep .sd-pill {
  fill: var(--bg-elevated);
  stroke: var(--accent-secondary);
  stroke-dasharray: none;
}
#eng-bing:checked   ~ .index-signal-svg .sd-engine--bing .sd-dot,
#eng-yandex:checked ~ .index-signal-svg .sd-engine--yandex .sd-dot,
#eng-seznam:checked ~ .index-signal-svg .sd-engine--seznam .sd-dot,
#eng-naver:checked  ~ .index-signal-svg .sd-engine--naver .sd-dot,
#eng-yep:checked    ~ .index-signal-svg .sd-engine--yep .sd-dot { fill: var(--accent-secondary); }
#eng-bing:checked   ~ .index-signal-svg .sd-engine--bing .sd-label,
#eng-yandex:checked ~ .index-signal-svg .sd-engine--yandex .sd-label,
#eng-seznam:checked ~ .index-signal-svg .sd-engine--seznam .sd-label,
#eng-naver:checked  ~ .index-signal-svg .sd-engine--naver .sd-label,
#eng-yep:checked    ~ .index-signal-svg .sd-engine--yep .sd-label { fill: var(--text-primary); font-weight: 600; }


/* Выключен: провод и плашка гаснут — как у Seznam по умолчанию. */
#eng-bing:not(:checked)   ~ .index-signal-svg .sd-engine--bing .sd-wire,
#eng-yandex:not(:checked) ~ .index-signal-svg .sd-engine--yandex .sd-wire,
#eng-seznam:not(:checked) ~ .index-signal-svg .sd-engine--seznam .sd-wire,
#eng-naver:not(:checked)  ~ .index-signal-svg .sd-engine--naver .sd-wire,
#eng-yep:not(:checked)    ~ .index-signal-svg .sd-engine--yep .sd-wire {
  stroke: var(--border-strong);
  stroke-dasharray: 3 6;
  animation: none;
}
#eng-bing:not(:checked)   ~ .index-signal-svg .sd-engine--bing .sd-pill,
#eng-yandex:not(:checked) ~ .index-signal-svg .sd-engine--yandex .sd-pill,
#eng-seznam:not(:checked) ~ .index-signal-svg .sd-engine--seznam .sd-pill,
#eng-naver:not(:checked)  ~ .index-signal-svg .sd-engine--naver .sd-pill,
#eng-yep:not(:checked)    ~ .index-signal-svg .sd-engine--yep .sd-pill {
  fill: none;
  stroke: var(--border-subtle);
  stroke-dasharray: 3 4;
}
#eng-bing:not(:checked)   ~ .index-signal-svg .sd-engine--bing .sd-dot,
#eng-yandex:not(:checked) ~ .index-signal-svg .sd-engine--yandex .sd-dot,
#eng-seznam:not(:checked) ~ .index-signal-svg .sd-engine--seznam .sd-dot,
#eng-naver:not(:checked)  ~ .index-signal-svg .sd-engine--naver .sd-dot,
#eng-yep:not(:checked)    ~ .index-signal-svg .sd-engine--yep .sd-dot { fill: var(--text-muted); }
#eng-bing:not(:checked)   ~ .index-signal-svg .sd-engine--bing .sd-label,
#eng-yandex:not(:checked) ~ .index-signal-svg .sd-engine--yandex .sd-label,
#eng-seznam:not(:checked) ~ .index-signal-svg .sd-engine--seznam .sd-label,
#eng-naver:not(:checked)  ~ .index-signal-svg .sd-engine--naver .sd-label,
#eng-yep:not(:checked)    ~ .index-signal-svg .sd-engine--yep .sd-label { fill: var(--text-secondary); font-weight: 400; }


@media (prefers-reduced-motion: reduce) {
  /* Правила выше специфичнее общего `.sd-wire--live { animation: none }`
     и без этой строки вернули бы бегущий штрих тем, кто просил меньше
     движения (`check-viz-motion`). */
  .index-signal .sd-wire { animation: none !important; stroke-dasharray: none; }
  .sig-switch, .sig-switch::after { transition: none; }
}


.sd-divider {
  stroke: var(--border-subtle);
  stroke-width: 1;
  stroke-dasharray: 2 4;
}


.sd-strike {
  stroke: var(--warning);
  stroke-width: 1.5;
  stroke-linecap: round;
}


/* ---- полоса знаков движков ---- */

/* Здесь стояла полоса чисел «5 · 2 · 3 · 0». Снята по разбору владельца
   09.09.2026: число «5» не различало участников протокола и адресатов
   платформы (B-127, реестр фактов F1), и полоса резала арт героя. Вместо
   чисел — знаки того, кому платформа отправляет, как в настройках продукта:
   пять движков и общий эндпоинт отдельно, через разделитель, потому что
   `api.indexnow.org` ничего не индексирует, а пересылает (решение В-3).

   Знаки однотонные и в одну коробку 22×22 (`preserveAspectRatio` символа
   вписывает каждый), цвет — `--text-secondary`, как у подписи: полоса
   перечисляет, а не рекламирует. Источники знаков — официальные векторы
   (Bing: Wikimedia «Bing Fluent Logo»; Yandex: Wikimedia «Yandex icon»;
   Seznam: росчерк «S» из `seznam.cz/media/img/logo_v2.svg`; Naver:
   Simple Icons; Yep: `cdn.yep.com/static/meta/safari-pinned-tab.svg`),
   у IndexNow вектора не публикует никто — силуэт обведён с растра иконки
   официального плагина Microsoft для WordPress (`ps.w.org/indexnow`). */
.index-marks {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-8);
  width: var(--index-page);
  margin: var(--space-10) auto 0;
  padding-top: var(--space-6);
  border-top: 1px solid var(--border-subtle);
}


.index-marks-title {
  flex: none;
  margin: 0;
  color: var(--text-muted);
  font-size: var(--font-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}


.index-marks-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-6);
  margin: 0;
  padding: 0;
  list-style: none;
}


.index-mark {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-secondary);
  font-size: var(--font-sm);
  font-weight: var(--weight-medium);
  line-height: 1.2;
}


.index-mark-svg {
  flex: none;
  width: 22px;
  height: 22px;
  fill: currentColor;
}


.index-mark--endpoint {
  padding-inline-start: var(--space-6);
  border-inline-start: 1px solid var(--border-subtle);
}


.index-mark--endpoint small {
  display: block;
  margin-top: 2px;
  color: var(--text-muted);
  font-size: var(--font-xs);
  font-weight: var(--weight-regular);
}


/* Вторая строка — то, что несли снятые чипы героя: кто по умолчанию, кто по
   выбору. Полоса это перечисляет, секция движков объясняет. */
.index-marks-note {
  flex-basis: 100%;
  margin: 0;
  color: var(--text-muted);
  font-size: var(--font-sm);
  line-height: 1.4;
}


/* ---- шкала области действия ---- */

.index-timeline {
  display: grid;
  gap: var(--space-8);
  margin-top: var(--space-8);
}


.tl-axis {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1.35fr);
  align-items: stretch;
  gap: 0;
}


.tl-zone {
  position: relative;
  min-height: 92px;
  padding: var(--space-5);
  border: 1px solid var(--border-subtle);
}


/* Прошлое штриховкой и приглушено: «история не импортируется» — это не
   строчка мелким шрифтом, а половина шкалы, которая остаётся тёмной. */
.tl-zone--past {
  border-radius: var(--radius-lg) 0 0 var(--radius-lg);
  border-inline-end: 0;
  background:
    repeating-linear-gradient(135deg,
      transparent 0 6px,
      color-mix(in srgb, var(--text-muted) 12%, transparent) 6px 7px);
}


.tl-zone--future {
  display: flex;
  align-items: flex-end;
  gap: var(--space-4);
  border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
  border-inline-start: 0;
  background: linear-gradient(90deg, var(--accent-soft), transparent 85%);
}


.tl-zone-label {
  position: absolute;
  top: var(--space-4);
  inset-inline-start: var(--space-5);
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}


.tl-zone--future .tl-zone-label { color: var(--index-tone-green-fg); }


.tl-switch {
  position: relative;
  display: grid;
  place-items: center;
  width: 2px;
  background: var(--accent);
}


/* Точка сидит НА оси, а не рядом с ней. `place-items: center` у родителя
   не центрирует потомка, который ШИРЕ дорожки: браузер прижимает такой
   элемент к началу, и тринадцатипиксельная точка на двухпиксельной оси
   уезжала на одиннадцать пикселей вправо — маркер момента включения
   указывал мимо момента.

   Отрицательные поля центруют её вручную и не зависят от того, как
   браузер трактует выравнивание при переполнении. Нашла это проверка
   «потомок вылезает за родителя», написанная по итогам просмотра
   страницы: симметричный вылет она пропускает, односторонний — нет. */
.tl-switch-dot {
  margin-inline: -5.5px;
  width: 13px;
  height: 13px;
  border: 2px solid var(--bg);
  border-radius: 50%;
  background: var(--accent);
}


.tl-switch-label {
  position: absolute;
  bottom: -26px;
  white-space: nowrap;
  color: var(--index-tone-green-fg);
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  font-weight: 500;
}


/* Засечки будущих изменений: каждая зажигается по очереди — то, что
   происходит после включения, и есть единственное, что происходит. */
.tl-tick {
  width: 3px;
  height: 26px;
  transform-origin: bottom;
  border-radius: 2px;
  background: var(--index-tone-green-fg);
  opacity: 0.25;
  animation: tl-tick 3s ease-in-out infinite;
}


.tl-tick:nth-child(3) { animation-delay: 0.45s; }
.tl-tick:nth-child(4) { animation-delay: 0.9s; }


.tl-manual {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding: var(--space-4) var(--space-5);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  font-size: var(--font-base);
}


.tl-manual-mark {
  flex: none;
  width: 9px;
  height: 9px;
  border: 2px solid var(--text-muted);
  border-radius: 2px;
}


.tl-clauses {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: var(--space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}


.tl-clause {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-3);
  align-content: start;
  padding: var(--space-5);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
}


.tl-clause-num {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: var(--radius-sm);
  background: var(--index-tone-teal-soft);
  color: var(--index-tone-teal-fg);
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}


.tl-clause-title {
  margin-bottom: var(--space-2);
  color: var(--text-primary);
  font-size: var(--font-md);
  font-weight: 600;
  line-height: 1.3;
}


.tl-clause-desc {
  color: var(--text-secondary);
  font-size: var(--font-base);
  line-height: 1.55;
}


/* ---- конвейер с границей ответственности ---- */

.index-pipeline {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 2.2fr);
  gap: var(--space-6);
  align-items: stretch;
  margin-top: var(--space-8);
}


.pl-side { display: grid; gap: var(--space-4); align-content: start; }


.pl-side-label {
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}


.pl-side--mine .pl-side-label { color: var(--index-tone-green-fg); }


.pl-list {
  display: grid;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}


.pl-list--multi { grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr)); }


.pl-node {
  display: grid;
  gap: var(--space-2);
  align-content: start;
  padding: var(--space-5);
  border-radius: var(--radius-lg);
}


/* Наша сторона плотная, чужая — пунктиром: это не оформление, а само
   содержание раздела. Мы отправляем; решает движок. */
.pl-node--you {
  border: 1px solid color-mix(in srgb, var(--accent) 50%, var(--border-subtle));
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm);
}


.pl-node--engine {
  border: 1px dashed var(--border-strong);
  background: transparent;
}


.pl-num {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: var(--radius-pill);
  background: var(--index-tone-muted-soft);
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  font-variant-numeric: tabular-nums;
}


.pl-node--you .pl-num {
  background: var(--index-tone-green-soft);
  color: var(--index-tone-green-fg);
}


.pl-title { color: var(--text-primary); font-size: var(--font-lg); font-weight: 600; }
.pl-desc { color: var(--text-secondary); font-size: var(--font-base); line-height: 1.55; }


.pl-boundary { display: grid; place-items: center; }


.pl-boundary span {
  display: block;
  width: 1px;
  height: 100%;
  background: repeating-linear-gradient(180deg,
    var(--border-strong) 0 5px, transparent 5px 11px);
}


/* ---- обмен при проверке ключа ---- */

.index-sequence {
  display: grid;
  gap: 0;
  margin: var(--space-6) 0 0;
  padding: 0;
  list-style: none;
  max-width: 900px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
  overflow: hidden;
}


.sq-step {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-4);
  padding: var(--space-4) var(--space-6);
}


.sq-step + .sq-step { border-top: 1px solid var(--border-subtle); }


.sq-idx {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: var(--radius-pill);
  background: var(--index-tone-teal-soft);
  color: var(--index-tone-teal-fg);
  font-family: var(--font-mono);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}


.sq-body { display: grid; gap: 2px; min-width: 0; }


.sq-from {
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  letter-spacing: 0.04em;
}


.sq-arrow { color: var(--accent-secondary); padding: 0 2px; }


.sq-msg {
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: var(--font-sm);
  line-height: 1.5;
  overflow-wrap: anywhere;
}


/* ---- адаптив инфографики ---- */

@media (max-width: 1080px) {
  /* Конвейер разворачивается вертикально: граница из вертикальной черты
     становится горизонтальной, но остаётся — она и есть смысл раздела. */
  .index-pipeline { grid-template-columns: 1fr; gap: var(--space-5); }
  .pl-boundary { height: 1px; }
  .pl-boundary span {
    width: 100%;
    height: 1px;
    background: repeating-linear-gradient(90deg,
      var(--border-strong) 0 5px, transparent 5px 11px);
  }
}



@media (max-width: 900px) {
  .index-marks { gap: var(--space-3) var(--space-5); }
  .index-marks-list { gap: var(--space-3) var(--space-5); }
  /* Ниже 900 ряд переносится, и общий эндпоинт оказывается на своей строке:
     разделитель слева тогда читается как обрубок, а не как граница. Замечено
     на 768. Пункт занимает строку целиком и теряет разделитель. */
  .index-mark--endpoint { flex-basis: 100%; padding-inline-start: 0; border-inline-start: 0; }
}



@media (max-width: 760px), print {
  .tl-axis { grid-template-columns: 1fr; }
  .tl-zone--past { border-radius: var(--radius-lg) var(--radius-lg) 0 0; border-inline-end: 1px solid var(--border-subtle); border-block-end: 0; }
  .tl-zone--future { border-radius: 0 0 var(--radius-lg) var(--radius-lg); border-inline-start: 1px solid var(--border-subtle); border-block-start: 0; }
  .tl-switch { width: 100%; height: 2px; }
  .tl-switch-label { bottom: auto; inset-inline-start: var(--space-5); top: 10px; }
  .sq-step { padding: var(--space-4) var(--space-5); }
}



/* Схема героя ниже этой ширины сжимается так, что подписи перестают читаться.
   Ей дан минимум и своя горизонтальная прокрутка — прокручивается схема,
   страница не едет. */
@media (max-width: 620px) {
  .index-signal { overflow-x: auto; overscroll-behavior-x: contain; }
  .index-signal-svg { min-width: 520px; }
}

@media (prefers-reduced-motion: reduce) {
  .sd-wire--live { animation: none; stroke-dasharray: none; }
  .sd-pulse { animation: none; }
  .tl-tick { animation: none; opacity: 0.55; }
}



/* ============================================================================
   Двухколоночный раздел
   ----------------------------------------------------------------------------
   Левая шапка при ширине страницы 1200 оставляла справа мёртвую половину:
   текст жался к левому краю, а половина полосы пустовала. Здесь шапка уходит
   в узкую колонку и липнет при прокрутке — она работает указателем, где ты
   находишься, — а содержимое занимает всю оставшуюся ширину.
   ========================================================================= */

.index-section--split {
  display: grid;
  grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
  gap: var(--space-16);
  align-items: start;
}


.index-section--split > .index-section-header {
  position: sticky;
  top: calc(var(--space-16) + var(--space-4));
  margin-bottom: 0;
  max-width: none;
}


.index-section--split .index-copy { font-size: var(--font-base); }


.index-section-body { display: grid; gap: var(--space-6); min-width: 0; }


/* Внутри правой колонки читаемая мера уже не нужна: колонка сама её задаёт. */
.index-section--split .index-verdict,
.index-section--split .index-ledger,
.index-section--split .index-mech,
.index-section--split .index-sequence { max-width: none; }


.index-section--split .index-content-rail { max-width: none; }


/* Схеме нужна вся ширина колонки, а тексту — нет: длинная строка не читается.
   Поэтому мера остаётся только у абзацев. */
.index-section--split .index-verdict-note,
.index-section--split .index-ledger-note,
.index-section--split .index-chain-close,
.index-section--split .index-mech-note { max-width: 68ch; }


@media (max-width: 1080px) {
  .index-section--split { grid-template-columns: 1fr; gap: var(--space-8); }
  .index-section--split > .index-section-header {
    position: static;
    margin-bottom: 0;
    max-width: 760px;
  }
}



/* ---- поправки схемы сигнала ---- */

/* Подпись «не участвует» встала к левому краю схемы, под общую черту:
   прижатая вправо, она читалась подписью к плашке Google, а она относится
   ко всей полосе под чертой. */
.sd-cap--out { text-anchor: start; }


.sd-divider { stroke: var(--border-strong); stroke-dasharray: 2 5; }


/* ---- плотность схемы и героя ---- */

/* Схема на первом экране конкурирует с заголовком 58px. При 13px подписях и
   волосяных проводах она читалась намёком, а не утверждением. */
.sd-label { font-size: 14.5px; }
.sd-label--dim { font-size: 14px; }
.sd-sub { font-size: 11.5px; }
.sd-cap { font-size: 11px; }
.sd-wire { stroke-width: 2; }
.sd-wire--live { stroke-dasharray: 6 8; }


/* Низ героя пустовал: между чипами и полосой чисел стоял блок воздуха выше
   самих чипов. */
.index-hero-grid { padding-bottom: var(--space-8); }
.index-marks { margin-top: var(--space-8); }


/* ---- плотность карточек ---- */

/* Иконка висела отдельно от заголовка на высоту строки: сетка раздавала
   одинаковый зазор всем детям, включая её. */
.index-tier { gap: var(--space-2); }
.index-tier-icon { margin-bottom: var(--space-2); }

/* Строки карточки не растягиваются. У сетки `align-content` по умолчанию
   ведёт себя как `stretch`, и лишнюю высоту получают САМИ СТРОКИ: в
   карточке, где текста меньше, всё расползается. Карточки стоят рядом и
   одной высоты, а их надзаголовки оказывались на 92px и 79px от верха,
   описания — на 174 и 136. Расхождение до 38px между вещами, которые
   читаются как параллельные. */
.index-tier { align-content: start; }


/* Три условия — это три условия, а не два и один под ними. */
@media (min-width: 1081px) {
  .index-fit-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .index-fit-grid > * { min-width: 0; }
}



/* ---- пропорции конвейера ---- */

/* Левая сторона — одна плитка, правая — три. Прежние доли 1 : 2.2 отдавали
   одной плитке треть ширины, а трём — остаток, и три вставали 2+1. */
.index-pipeline { grid-template-columns: minmax(0, 0.85fr) auto minmax(0, 2.6fr); gap: var(--space-5); }
.pl-list--multi { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.pl-list--multi > * { min-width: 0; }


@media (max-width: 1320px) {
  .index-pipeline { grid-template-columns: 1fr; }
  .pl-list--multi { grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr)); }
}



/* ---- поправки после просмотра в тёмной теме ---- */

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


/* Граница ответственности пропадала: в сетке с `align-items: start` колонка
   схлопывалась по высоте содержимого, а её содержимое — полоска height:100%
   от нулевой высоты. */
.index-pipeline { align-items: stretch; }
.pl-boundary { align-self: stretch; }
.pl-boundary span { min-height: 100%; height: auto; align-self: stretch; }


/* Шкала: прошлое должно ЧИТАТЬСЯ вычеркнутым, а не просто быть бледнее. */
.tl-zone { min-height: 104px; }


.tl-zone--past {
  background:
    repeating-linear-gradient(135deg,
      transparent 0 5px,
      color-mix(in srgb, var(--text-muted) 20%, transparent) 5px 6px);
}


.tl-zone--past .tl-zone-label { color: var(--text-muted); }


.tl-zone--future {
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--accent) 20%, transparent), transparent 88%);
}


.tl-tick { width: 4px; opacity: 0.4; }


/* ---- схема на узком экране ---- */

/* Своя прокрутка у схемы не работала: элемент грид-колонки по умолчанию не
   ужимается ниже содержимого (`min-width: auto`), поэтому контейнер просто
   раздувался и схему срезало краем экрана вместо прокрутки. */
.index-hero-grid > * { min-width: 0; }
.index-signal { min-width: 0; max-width: 100%; }


@media (max-width: 620px) {
  .index-signal-svg { min-width: 460px; }
  /* Край подсказывает, что схему можно потянуть.

     Было статическим градиентом на 88% ширины, и он висел ВСЕГДА — в том
     числе домотанным до конца, где гасил последние 12% схемы и обещал
     продолжение, которого уже нет. У полосы меню в шапке та же статика
     оправдана: там стоит `padding-inline-end` ровно в ширину затухания, и
     градиент ложится на пустоту. Здесь такой компенсации не было.

     Теперь тот же привязанный к прокрутке приём, что у остальных четырёх
     полос: 40px в начале, ноль домотанным до конца. Перелом остаётся 620 —
     он общий с `min-width` схемы выше, и разводить их нельзя.

     `-webkit-mask-image` сохранён ради старых движков; довод про него у меня
     сперва был НЕВЕРНЫЙ, и это стоит оставить записанным. Я писал, что движок
     без `@property` отбросит объявление целиком и затухания не будет. Замер
     опроверг: копия сайта без `@property` даёт `--rail-fade` те же 40px —
     кадр `from` присваивает величину и без типизации, типизация нужна лишь
     для плавной интерполяции.

     Безопасность держится на другом, и это проверено воспроизведением
     настоящего случая. Движок без прокруточных шкал отбрасывает не
     `@property`, а строку `animation-timeline`; тогда остаётся `animation:
     rail-edge linear both` без длительности, и она мгновенно доигрывает до
     `to`, то есть до нуля. Копия сайта без `animation-timeline`: `--rail-fade`
     = 0px на всех трёх полосах, ложной подсказки нет ни одной. */
  .index-signal {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - var(--rail-fade)), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - var(--rail-fade)), transparent);
    animation: rail-edge linear both;
    animation-timeline: scroll(self inline);
  }
}



/* ПРАВИЛО ПЕРЕСМОТРЕНО НА И6, и прежнее было бы теперь вредным.

   Раньше здесь пряталось и то и другое: схема сигнала стояла в правом
   столбце героя, её композиция горизонтальна — источник, край, колонка
   движков, — и в 390 пикселей она требовала прокрутки, то есть переставала
   быть тем, что схватывается взглядом на первом экране.

   (История до 09.09.2026: панель отправки и её обёртка `.index-bridge-wrap`
   сняты с героя по решению владельца; довод ниже остаётся только про схему.)
   Изменилось два обстоятельства. В обёртке `.index-bridge-wrap` теперь
   ПАНЕЛЬ ОТПРАВКИ, а не схема, и прятать её нельзя ни при какой ширине:
   это главный интерактив страницы и предмет самого заголовка. Композиция
   у неё вертикальная — вкладки над журналом, — и на 390 пикселях она
   работает без прокрутки.

   А схема переехала в секцию движков, то есть перестала быть первым
   экраном. К середине страницы довод «схватывается взглядом» не
   относится, и конвенция схем действует обычная: на узком экране схема
   либо перестраивается, либо получает СВОЮ горизонтальную прокрутку.
   Прятать содержимое от мобильного читателя — последнее средство. */
@media (max-width: 620px) {
  .index-signal {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .index-signal .index-signal-svg { min-width: 560px; }
}



/* ============================================================================
   Боль: где читатель находится сейчас
   ----------------------------------------------------------------------------
   Единственный блок страницы, который рисует не механизм, а положение
   человека. Верхняя дорожка длинная и пустая — это интервал без сигнала, в
   котором он живёт. Нижняя короткая и зажжённая. Разница длин и есть
   содержание: обещать скорость нельзя, а показать, что интервал перестаёт
   быть безответным, — можно и правда.
   ========================================================================= */

.index-waitline {
  display: grid;
  gap: var(--space-5);
  padding: var(--space-6);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-panel-soft);
}


.wl-track { display: grid; gap: var(--space-3); }


.wl-name {
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}


.wl-name--live { color: var(--index-tone-green-fg); }


.wl-run { display: flex; align-items: stretch; gap: var(--space-3); flex-wrap: wrap; }


.wl-node {
  display: flex;
  align-items: center;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-size: var(--font-base);
  line-height: 1.35;
}


.wl-node--dim {
  border-style: dashed;
  background: transparent;
  color: var(--text-secondary);
}


.wl-node--live {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--border-subtle));
  box-shadow: var(--shadow-sm);
}


/* Пропасть тянется на весь остаток строки: она должна быть ДЛИННОЙ. */
.wl-gap {
  position: relative;
  flex: 1 1 220px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  min-height: 46px;
  border-block: 1px dashed var(--border-strong);
  border-inline: 0;
}


.wl-gap-mark {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  background: var(--bg);
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: var(--font-sm);
}


.wl-gap-text {
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  letter-spacing: 0.06em;
}


/* Короткая связка второй дорожки — противовес пропасти первой. */
.wl-link {
  align-self: center;
  flex: 0 0 34px;
  height: 2px;
  border-radius: 2px;
  background: repeating-linear-gradient(90deg,
    var(--accent-secondary) 0 6px, transparent 6px 11px);
  animation: sd-flow 1.5s linear infinite;
}


.wl-caveat {
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  font-size: var(--font-base);
  line-height: 1.6;
}


/* ---- что уже пробовали ---- */

.index-tried {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}


.wt-card {
  display: grid;
  gap: var(--space-2);
  align-content: start;
  padding: var(--space-5);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: transparent;
}


/* Косой крест — не иконка, а отметка «пробовал, не сработало». Значение несёт
   текст карточки; крест только подтверждает, поэтому он и скрыт от озвучки. */
.wt-cross {
  position: relative;
  width: 18px;
  height: 18px;
  opacity: 0.75;
}


.wt-cross::before,
.wt-cross::after {
  content: '';
  position: absolute;
  inset-inline-start: 1px;
  top: 8px;
  width: 16px;
  height: 1.5px;
  border-radius: 2px;
  background: var(--index-tone-muted-fg);
}


.wt-cross::before { transform: rotate(45deg); }
.wt-cross::after { transform: rotate(-45deg); }


.wt-title { color: var(--text-primary); font-size: var(--font-md); font-weight: 600; }
.wt-desc { color: var(--text-secondary); font-size: var(--font-base); line-height: 1.55; }


/* ---- поворот от боли к решению ---- */

/* Одна строка, на которой держится вся страница. Она не абзац и не заголовок,
   и набрана размером между ними — чтобы её прочли даже те, кто листает. */
.index-turn {
  max-width: 62ch;
  padding-inline-start: var(--space-5);
  border-inline-start: 3px solid var(--accent);
  color: var(--text-primary);
  font-size: clamp(18px, 1.7vw, 22px);
  font-weight: 500;
  line-height: 1.45;
  text-wrap: pretty;
}


/* ---- три вопроса ---- */

.index-triad {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
  overflow: hidden;
}


.td-col {
  display: grid;
  gap: var(--space-3);
  align-content: start;
  padding: var(--space-6);
  border-inline-start: 1px solid var(--border-subtle);
}


.td-col:first-child { border-inline-start: 0; }


/* Вопрос крупнее ответа: у трёх механизмов разные вопросы, и это и есть
   единственное, что нужно унести из раздела. */
.td-q {
  color: var(--index-tone-teal-fg);
  font-family: var(--font-mono);
  font-size: var(--font-md);
  line-height: 1.3;
}


.td-subject {
  color: var(--text-primary);
  font-size: var(--font-lg);
  font-weight: 600;
}


.td-desc { color: var(--text-secondary); font-size: var(--font-base); line-height: 1.55; }


@media (max-width: 760px), print {
  .td-col { border-inline-start: 0; border-block-start: 1px solid var(--border-subtle); }
  .td-col:first-child { border-block-start: 0; }
  .wl-gap { flex-basis: 100%; }
  .index-waitline { padding: var(--space-5); }
}



/* Между дорожками нужен воздух: подпись второй читалась подписью к первой. */
.index-waitline { gap: var(--space-6); }
.wl-track + .wl-track { padding-top: var(--space-5); border-top: 1px solid var(--border-subtle); }


/* ============================================================================
   Ручной путь: аргумент несёт длина ряда
   ----------------------------------------------------------------------------
   Приём взят с `bridge-ssl.com`, где установка сертификата показана как
   девять пронумерованных шагов против одного. Убеждает счёт, а не эпитет:
   слово «муторно» читатель пропускает, ряд из семи ячеек — нет.

   Компонента с таким именем в этом репозитории не было, он написан здесь.

   Шаги — настоящий `<ol>`, а не картинка. Поэтому у блока нет `role="img"`:
   он был бы вреден, спрятав от чтения с экрана единственную копию смысла.
   Заодно ряд остаётся извлекаемым для машинного ответа.

   Числа в шагах взяты у первоисточников и только у них: суточная квота и
   сброс в полночь UTC — документация Bing, ключ 8–128 шестнадцатеричных
   знаков и потолок десять тысяч адресов на запрос — indexnow.org. Лимит
   Яндекса на странице НЕ назван: вторичные источники дают 20, 30, 150 и
   210, а сам Яндекс показывает его в интерфейсе рядом с полем. Числа без
   первоисточника здесь не место.
   ========================================================================= */

.tracks {
  display: grid;
  gap: var(--space-6);
}


.tk-name {
  margin: 0 0 var(--space-3);
  color: var(--text-muted);
  font-size: var(--font-xs);
  font-weight: var(--weight-medium);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}


.tk-name--live { color: var(--accent-secondary); }


.tk-steps {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: tk;
}


.tk-step {
  counter-increment: tk;
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  max-width: 100%;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  color: var(--text-secondary);
  font-size: var(--font-sm);
  line-height: var(--leading-snug);
}


/* Номер рисует счётчик CSS, а не текст в разметке. Причина не
   косметическая: `verify.py` → `check_fidelity` сверяет ПОСЛЕДОВАТЕЛЬНОСТЬ
   СЛОВ страницы с абзацем исходника, и цифра, стоящая текстовым узлом
   внутри шага, разрывала эту последовательность — проверка падала на
   обоих рядах. Счётчик даёт ту же нумерацию, не попадая в текст. */
.tk-step::before {
  content: counter(tk);
  flex-shrink: 0;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  font-weight: var(--weight-semibold);
}


/* Наша строка отличается не украшением, а длиной: одна ячейка против семи
   и шести. Акцент только подтверждает то, что уже видно по ряду. */
.tk-row--ours .tk-step--live {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--text-primary);
}

.tk-row--ours .tk-step::before { color: var(--accent-secondary); }


/* Ряд заполняется по мере прокрутки, шаг за шагом: читатель проходит его
   ровно так же долго, как проходил бы вживую. Ступень задаётся КЛАССАМИ
   `.d1`–`.d7`, а не `nth-of-type`: последний считает всё подряд и
   ломается от любой правки разметки. */
@keyframes step-lit {
  from { opacity: 0.32; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}


@supports (animation-timeline: view()) {
  .tk-step {
    animation-name: step-lit;
    animation-timeline: view();
    animation-fill-mode: both;
    animation-timing-function: linear;
  }

  .tk-step.d1 { animation-range: entry 4%  entry 20%; }
  .tk-step.d2 { animation-range: entry 10% entry 26%; }
  .tk-step.d3 { animation-range: entry 16% entry 32%; }
  .tk-step.d4 { animation-range: entry 22% entry 38%; }
  .tk-step.d5 { animation-range: entry 28% entry 44%; }
  .tk-step.d6 { animation-range: entry 34% entry 50%; }
  .tk-step.d7 { animation-range: entry 40% entry 56%; }
}


@media (max-width: 760px), print {
  .tk-steps { flex-direction: column; }
  .tk-step { width: 100%; }
}


@media print {
  .tk-step { animation: none !important; opacity: 1 !important; transform: none !important; }
}


/* ---- шкала времени на бумаге ---- */

/* Прошлое рисуется штриховкой, а засечки будущего — заливкой, и браузер
   по умолчанию не печатает ни то ни другое: на листе оставалась пустая
   коробка с двумя подписями по краям. Смысл несли подписи, но выглядело
   это сломанной вёрсткой.

   На печати то же различие даётся КОНТУРОМ: у прошлого пунктирная рамка
   и приглушённый тон, у засечек — сплошная. Найдено в настоящем PDF. */
@media print {
  .tl-zone--past {
    border: 1px dashed var(--border-strong) !important;
    color: var(--text-muted) !important;
  }

  .tl-zone--future { border: 1px solid var(--border-strong) !important; }

  .tl-tick {
    background: none !important;
    border-inline-start: 3px solid var(--text-primary) !important;
    width: 0 !important;
  }

  .tl-switch { background: var(--text-primary) !important; }
  .tl-switch-dot { border-color: var(--text-primary) !important; }
}


@media (prefers-reduced-motion: reduce) {
  .tk-step { animation: none !important; opacity: 1 !important; transform: none !important; }
}


@media print {
  /* Фоновые слои с листа убраны, как в эталоне. Без фоновой графики они
     всё равно не рисуются, но остаются слоями — а слой поверх содержимого
     умеет его съедать (см. историю `.index-noise` ниже). */
  .site-bg,
  .site-noise { display: none !important; }

  /* Зернистая накладка с листа убрана — и это не косметика, а причина,
     по которой панель отправки НЕ ПЕЧАТАЛАСЬ ВОВСЕ. `.index-noise::after`
     лежит поверх героя (`position: absolute; inset: 0; z-index: 1`) с
     шумовой текстурой в `background-image`. Когда браузер печатает без
     фоновой графики — а это положение по умолчанию и в Chrome, и в
     `page.pdf()`, — текстура не рисуется, но САМ СЛОЙ остаётся и съедает
     то, что под ним: панель уходила с листа целиком, оставляя треть
     страницы пустой бумаги.

     Найдено перебором: при `display: none` у псевдоэлементов доля чернил
     в нижней трети листа выросла с 0.21% до 17%. Ни один замер в браузере
     этого не показывал — панель там на месте, с верным цветом и без
     обрезания. Только настоящий PDF. */
  .index-noise::before,
  .index-noise::after { display: none !important; }

}


/* ============================================================================
   Журнал отправок — доказательство действия
   ----------------------------------------------------------------------------
   Самая широкая незанятая клетка ниши: из семи разобранных конкурентов
   шестеро не показывают, что именно ушло, а седьмой покупает ответ
   ежечасной проверкой и возвратом денег. Вопрос «а сработало ли» AIOSEO
   сам вынес в свой FAQ — значит его задают достаточно часто, чтобы
   отвечать публично. Отвечают все текстом. Здесь на него отвечает экран.

   ПОЧЕМУ ЭТО ТАБЛИЦА, А НЕ СПИСОК СТРОК, как в панели героя. В панели
   журнал — выдержка, три-четыре строки под заголовком; там достаточно
   грида. Здесь у записи пять измерений — время, адрес, движок, режим,
   исход, — и у них есть заголовки столбцов. Читатель с экранной читалкой
   должен слышать «Engine: Yandex», а не четвёртое значение подряд.
   Поэтому `<table>` с `<th scope="col">` и подписью.

   ПЕЧАТИ СТРОК И МИГАЮЩЕГО КУРСОРА ЗДЕСЬ НЕТ, хотя у эталона есть. Их
   ведёт отдельный `js/home.js`, а наш канон (`AGENTS.md` §2) разрешает
   только комплектный `site.js`. Это не потеря: журнал ценен как ЗАПИСЬ, а
   не как зрелище, и напечатанная по буквам строка не делает её
   достовернее. Движение здесь было бы украшением поверх довода.

   Строка собрана только из подтверждённого. Снимка вкладки `Logs` не
   будет (решение по В-2), поэтому измерений ровно пять и ни одного
   выдуманного столбца.
   ========================================================================= */

.logbook {
  margin: 0;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
  overflow: hidden;
}


/* Своя горизонтальная прокрутка, а не прокрутка страницы: пять столбцов
   на 390 пикселях не помещаются, и страница вбок ехать не должна никогда. */
.lb-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }


.lb-table {
  width: 100%;
  min-width: 520px;
  border-collapse: collapse;
  font-size: var(--font-xs);
  line-height: 1.5;
}


.lb-table th {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
  background: var(--control-bg);
  color: var(--text-muted);
  font-weight: var(--weight-medium);
  letter-spacing: 0.04em;
  text-align: start;
  text-transform: uppercase;
}


.lb-table td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
  vertical-align: baseline;
}

.lb-table tbody tr:last-child td { border-bottom: 0; }


.lb-t { color: var(--text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.lb-u { color: var(--text-primary); }
.lb-e { color: var(--text-secondary); white-space: nowrap; }
.lb-m { color: var(--text-muted); white-space: nowrap; }

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

   НО ЦВЕТ НЕ МОЖЕТ БЫТЬ ЕДИНСТВЕННЫМ КАНАЛОМ, и здесь он им был. Замер:
   в тёмной теме зелёный `#689f6e` и приглушённый `#92929a` имеют
   ОДИНАКОВУЮ светлоту — контраст между ними 1.00. Они различаются только
   тоном, то есть для читателя с дальтонизмом и на монохромной печати —
   а без фоновой графики печатает большинство — колонка исхода не несёт
   различия вовсе. Журнал, который «отвечает, случилось ли то, о чём вы
   просили», переставал отвечать.

   Починено вторым каналом, а не сменой палитры: принятая запись получает
   вес. Вес переживает и дальтонизм, и монохром, и не спорит с решением
   выше про красный. */
.lb-r { white-space: nowrap; }
.lb-r--ok { color: var(--accent-secondary); font-weight: var(--weight-medium); }
.lb-r--warn { color: var(--text-secondary); }
.lb-r--muted { color: var(--text-muted); }


/* ============================================================================
   Три режима — сердце страницы
   ----------------------------------------------------------------------------
   Одни и те же пять адресов, три поведения. Это невозможно объяснить
   абзацем и мгновенно понятно рисунком, поэтому здесь не иллюстрация к
   тексту, а сам довод.

   ГЕОМЕТРИЯ У ТРЁХ СХЕМ ОДНА, И ЭТО НЕ ЭКОНОМИЯ. Адреса слева, движки
   справа, координаты совпадают до пикселя. Различаются только дуги: шесть,
   пять и двадцать пять. Если сдвинуть колонки в одной из схем, сравнение
   развалится — читатель перестанет видеть, что список тот же самый.

   ТРЁХ ЦВЕТОВ РЕЖИМОВ ТАК И НЕ ПОНАДОБИЛОСЬ. План предписывал завести их
   на И3, я отложил до И9 с доводом, что это лестница количества, а не
   строгости. Теперь видно, что довод был верен вдвойне: разницу между
   шестью дугами и двадцатью пятью несёт ФОРМА, и красить её тремя цветами
   значило бы дублировать то, что уже сказано, а заодно намекать, будто
   «все движки» опасно. Цвет остался один — акцент на живой дуге.

   Дуги рисуются по мере входа секции в кадр: `stroke-dashoffset` на
   прокруточной шкале, без единого бесконечного лупа. Бюджет движения (не
   больше одного лупа на секцию) соблюдён тем, что лупов нет вовсе.
   ========================================================================= */

.mv-grid {
  display: grid;
  gap: var(--space-6);
}


/* `min-width: 0` обязателен и куплен дефектом. У элемента грида
   `min-width` по умолчанию `auto`, то есть он раздаётся под содержимое:
   схема с `min-width: 460px` растягивала карточку до 502px при экране в
   390, и прокручивалась не схема, а карточка. Причём страница вбок при
   этом НЕ ехала — `overflow: hidden` у `.index-homepage` просто обрезал
   лишнее, и проверка «горизонтальной прокрутки нет» показывала зелёный,
   пока часть схемы была недостижима. */
.mv-card {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
}


.mv-title { margin: 0; font-size: var(--font-md); font-weight: var(--weight-semibold); letter-spacing: -0.01em; }
.mv-desc  { margin: 0; font-size: var(--font-sm); color: var(--text-secondary); max-width: 62ch; }


.mv { margin: 0; }

/* Своя горизонтальная прокрутка на узком экране: композиция схемы
   горизонтальна — адреса, дуги, движки, — и ужать её без потери подписей
   нельзя. Страница вбок не едет никогда. */
.mv-svg { display: block; width: 100%; min-width: 460px; height: auto; }
.mv { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.viz-cap {
  margin-top: var(--space-2);
  color: var(--text-muted);
  font-size: var(--font-xs);
}


/* ---- словарь схемы: цвет ТОЛЬКО классом, никогда атрибутом ---- */

.mv-box,
.mv-pill {
  fill: none;
  stroke: var(--viz-line);
  stroke-width: 1;
}

.mv-pill--idle { stroke-dasharray: 3 3; }

.mv-label {
  fill: var(--text-secondary);
  font-family: var(--font-family);
  font-size: 11px;
}

.mv-label--dim { fill: var(--text-muted); }

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

.mv-wire--live  { stroke: var(--accent); }
.mv-wire--thin  { stroke-width: 1; opacity: 0.55; }
/* Отказ — не авария, а нормальная запись: пунктир и приглушённый тон, а
   не тревожный цвет. Та же логика, что в столбце исхода журнала. */
.mv-wire--fail  { stroke: var(--text-muted); stroke-dasharray: 4 3; }
.mv-wire--retry { stroke: var(--accent); stroke-dasharray: 4 3; }


/* ---- дуги прорисовываются при входе секции в кадр ---- */

@keyframes wire-draw {
  from { stroke-dashoffset: 320; }
  to   { stroke-dashoffset: 0; }
}

@supports (animation-timeline: view()) {
  .mv-wire {
    stroke-dasharray: 320;
    animation-name: wire-draw;
    animation-timeline: view();
    animation-fill-mode: both;
    animation-timing-function: linear;
  }
  /* Ступень классами `.d1`–`.d6`, а не `nth-of-type`: последний считает
     подряд всё, включая рамки и подписи, и ломается от любой правки
     рисунка. Правило §4.7 плана. */
  .mv-wire.d1 { animation-range: entry 6%  entry 30%; }
  .mv-wire.d2 { animation-range: entry 11% entry 35%; }
  .mv-wire.d3 { animation-range: entry 16% entry 40%; }
  .mv-wire.d4 { animation-range: entry 21% entry 45%; }
  .mv-wire.d5 { animation-range: entry 26% entry 50%; }
  /* Повторная дуга приходит ПОСЛЕ отказа — иначе не видно, что это ответ
     на него, а не ещё одна первичная отправка. */
  .mv-wire.d6 { animation-range: entry 40% entry 62%; }

  /* Пунктир нельзя рисовать пунктиром: `stroke-dasharray` занят прорисовкой.
     Поэтому отказ и повтор отличаются не штрихом, а тоном и толщиной. */
  .mv-wire--fail,
  .mv-wire--retry { stroke-dasharray: 320; }
  .mv-wire--fail { opacity: 0.7; }
  .mv-wire--retry { stroke-width: 1.2; }
}


@media (min-width: 1080px) {
  /* Карточки тянутся до общей высоты, а схема прижата к низу. Иначе
     карточка с более короткой подписью оказывается ниже, и три схемы —
     то единственное, что читатель тут СРАВНИВАЕТ, — стоят не на одной
     линии: на 1440 они были на 150, 130 и 150 от верха карточки. Ровный
     зазор под подписью честнее ровных схем не делает; сравнивают схемы. */
  .mv-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: stretch; }
  .mv-card .mv { margin-top: auto; }
  .mv-svg { min-width: 0; }
  .mv { overflow-x: visible; }
}


@media print {
  .mv-wire { animation: none !important; stroke-dasharray: none !important; stroke-dashoffset: 0 !important; }
}

@media (prefers-reduced-motion: reduce) {
  .mv-wire { animation: none !important; stroke-dasharray: none !important; stroke-dashoffset: 0 !important; }
  .mv-wire--fail, .mv-wire--retry { stroke-dasharray: 4 3 !important; }
}


/* ============================================================================
   Ёмкость — правило, а не число
   ----------------------------------------------------------------------------
   Решение владельца по В-2: на странице стоит ПРАВИЛО без абсолютных чисел.
   Канон разрешает это целиком (`AGENTS.md`: тарифы на спутнике не
   изобретаются), а в нише ёмкость не объясняет никто — шесть конкурентов
   из семи молчат про лимиты вовсе, седьмой упоминает код ошибки 429. То
   есть отличие даёт само правило, а не величина, и правило не устареет
   при смене тарифной сетки.

   ПОЧЕМУ СХЕМА ЗДЕСЬ ДРУГАЯ, ЧЕМ В СЕКЦИИ РЕЖИМОВ. Там показан МАРШРУТ:
   какой адрес в какой движок. Здесь РАСХОД: сколько ёмкости каждый режим
   тратит на одну и ту же работу. Повторять дуги значило бы сказать то же
   самое второй раз; полосы говорят новое — «покрытие одинаковое, цена
   разная».

   Ни одной цифры в разметке схемы нет намеренно: доли заданы шириной
   прямоугольника, и при смене тарифа рисунок останется верным.
   ========================================================================= */

.cp { margin: 0 0 var(--space-6); overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* Потолок ширины обязателен. Схема лежит в ОДНОКОЛОНОЧНОЙ секции, и
   `width: 100%` растягивал её до полосы страницы: подписи движков,
   набранные 10px, вырастали до 23px, полосы становились гигантскими, и
   блок начинал спорить с заголовком. Схемы режимов такой беды не знали,
   потому что стоят в трёх колонках. Найдено просмотром страницы: ни одна
   проверка «слишком крупно» не ловит. */
.cp-svg {
  display: block;
  width: 100%;
  max-width: 640px;
  min-width: 460px;
  height: auto;
}

.cp-name {
  fill: var(--text-secondary);
  font-family: var(--font-family);
  font-size: 12px;
  font-weight: 500;
}

.cp-eng {
  fill: var(--text-muted);
  font-family: var(--font-family);
  font-size: 10px;
}

.cp-track { fill: none; stroke: var(--viz-line); stroke-width: 1; }

/* Расход красится акцентом, а не тревожным цветом: потратить ёмкость —
   это работа, а не авария. Разницу несёт ДЛИНА, и она уже говорит всё. */
.cp-fill { fill: var(--accent-soft); stroke: var(--accent); stroke-width: 1; }


@keyframes cp-grow {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

@supports (animation-timeline: view()) {
  .cp-fill {
    /* Без `transform-box: fill-box` начало координат считается от вьюпорта,
       и полоса растёт не из своего левого края, а из угла экрана. Правило
       §4.7 плана, и оно куплено чужой ошибкой. */
    transform-box: fill-box;
    transform-origin: left center;
    animation-name: cp-grow;
    animation-timeline: view();
    animation-fill-mode: both;
    animation-timing-function: linear;
  }
  .cp-fill.d1 { animation-range: entry 8%  entry 34%; }
  .cp-fill.d2 { animation-range: entry 12% entry 38%; }
  .cp-fill.d3 { animation-range: entry 16% entry 42%; }
  .cp-fill.d4 { animation-range: entry 20% entry 46%; }
  .cp-fill.d5 { animation-range: entry 24% entry 50%; }
}


.cp-list {
  display: grid;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.cp-item {
  min-width: 0;
  padding-inline-start: var(--space-4);
  border-inline-start: 2px solid var(--border-subtle);
}

.cp-item-title { margin: 0 0 var(--space-1); font-size: var(--font-sm); font-weight: var(--weight-semibold); }
.cp-item-desc  { margin: 0; font-size: var(--font-sm); color: var(--text-secondary); max-width: 62ch; }


@media (min-width: 1080px) {
  .cp-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .cp-svg { min-width: 0; }
  .cp { overflow-x: visible; }
}


@media print {
  .cp-fill { animation: none !important; transform: none !important; }
}

@media (prefers-reduced-motion: reduce) {
  .cp-fill { animation: none !important; transform: none !important; }
}


/* ============================================================================
   Сетка страниц — пропорция, которой не даёт шкала времени
   ----------------------------------------------------------------------------
   Шкала времени рядом отвечает на «КОГДА»: с момента включения и вперёд.
   Она не отвечает на «СКОЛЬКО», а первая оговорка области — «discovered and
   changed URLs only» — именно про количество. Сорок клеток, четыре
   зажжённых: видно, что уезжает не сайт, а изменения.

   Клетка — `<span>` в гриде, а не SVG: рисунок из сорока одинаковых
   квадратов разметкой короче и переключает тему вместе со страницей.
   `role="img"` с осмысленной подписью стоит на контейнере, потому что
   сорок пустых span по отдельности читалке не нужны.
   ========================================================================= */

.sg { margin: 0 0 var(--space-6); }

.sg-grid {
  display: grid;
  grid-template-columns: repeat(10, minmax(0, 1fr));
  gap: var(--space-2);
  max-width: 420px;
}

.sg-tile {
  aspect-ratio: 1;
  border: 1px solid var(--viz-line);
  border-radius: 3px;
}

/* Зажжённая клетка отличается заливкой и рамкой, а не только цветом:
   при монохромной печати и у читателя с нарушением цветовосприятия
   разница обязана остаться видимой. */
.sg-tile--lit {
  border-color: var(--accent);
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent);
}


@keyframes sg-lit {
  from { opacity: 0.25; transform: scale(0.82); }
  to   { opacity: 1; transform: none; }
}

@supports (animation-timeline: view()) {
  .sg-tile--lit {
    animation-name: sg-lit;
    animation-timeline: view();
    animation-fill-mode: both;
    animation-timing-function: linear;
  }
  .sg-tile--lit.d1 { animation-range: entry 10% entry 34%; }
  .sg-tile--lit.d2 { animation-range: entry 16% entry 40%; }
  .sg-tile--lit.d3 { animation-range: entry 22% entry 46%; }
  .sg-tile--lit.d4 { animation-range: entry 28% entry 52%; }
}

@media (max-width: 620px) { .sg-grid { grid-template-columns: repeat(8, minmax(0, 1fr)); } }

@media print { .sg-tile--lit { animation: none !important; opacity: 1 !important; transform: none !important; } }
@media (prefers-reduced-motion: reduce) { .sg-tile--lit { animation: none !important; opacity: 1 !important; transform: none !important; } }


/* ============================================================================
   Маршруты: чем они отличаются по существу
   ----------------------------------------------------------------------------
   Секция перечисляла четыре способа и честно говорила, что ни один не
   «правильнее» остальных. Это верно и этого мало: читатель, у которого уже
   есть плагин или CDN, не получал ответа, чем наш способ отличается.

   Две оси выбраны так, чтобы отличие было МЕХАНИЧЕСКИМ, а не оценочным:
   что запускает отправку и что остаётся после неё. Эвристика по промаху
   кэша срабатывает на догадке и не оставляет читаемого следа; явная
   отправка срабатывает на обнаруженном изменении или на кнопке и
   оставляет журнал. Это разбор устройства, а не сравнение скорости или
   цены — последнее канон запрещает.

   Никто не назван по имени: решение владельца по В-4. Способ узнаётся тем,
   кому адресован, и не устареет, когда чужая витрина изменится.
   ========================================================================= */

.rt { margin: var(--space-5) 0 0; border: 1px solid var(--border-subtle); border-radius: var(--radius-lg); background: var(--bg-elevated); overflow: hidden; }
/* Таблица маршрутов прокручивается на телефоне ПО ЗАМЫСЛУ — у `.rt-table`
   стоит `min-width: 520px`, то есть колонки не ужимаются, а уезжают за край.
   Знака об этом не было: на 320px из 520 пикселей таблицы видно 286, скрыто
   234 — сорок пять процентов, — и текст просто обрывался посреди слова
   («because you press…», «on a detected chan…»). Замер этого не показывал:
   развёртка узких ширин ищет `overflow: hidden`, а прокручиваемое
   переполнение к обрезам не относит. Нашлось снимком.

   Приём взят у схем в `kb.css` (`--viz-fade` / `viz-edge`), а не выдуман
   заново; имена свои, потому что главная не подключает `kb.css`.

   Порог применения — тот же, по которому я час назад ОТКАЗАЛ в затухании
   таблице статьи: там скрыто два пикселя, и подсказка обещала бы содержимое,
   которого нет. Здесь скрыта почти половина.

   @supports нет намеренно: комплект запрещает вложенность глубже
   «медиазапрос → правило», а гарантия достигается иначе. Начальное значение
   `--rail-fade` — ноль, сорок берётся из кадра `from`. Там, где прокруточной
   шкалы нет — движок её не умеет либо прокручивать нечего, — анимация без
   длительности мгновенно доигрывает до `to`, то есть до нуля. Ложной
   подсказки не будет ни в одном браузере и ни на одной ширине. */
@property --rail-fade {
  syntax: '<length>';
  inherits: false;
  initial-value: 0px;
}


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


.rt-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* Полос оказалось не одна. Опись всех прокручиваемых областей на 320 и 390
   показала семь, и знак был у четырёх: у схем статей, у `.index-signal`, у
   полосы меню в шапке и у таблицы маршрутов. Три выпали, все на главной:

     figure.viz.mv   скрыто 214px (47%)
     div.lb-scroll   скрыто 234px (45%)
     figure.viz.cp   скрыто 172px (37%)

   Найти это взглядом было нельзя — я и не нашёл, увидел одну таблицу из
   четырёх. Нашлось описью.

   Поэтому имя приёма перестало быть маршрутным: `--rail-fade` вместо
   `--rt-fade`. Селектор `.viz` покрывает обе схемы главной разом — до сих пор
   этот класс не имел ни одного правила и числился крючком в
   `unstyled-known.json`; запись снята, и восьмая проверка `check-css-local`
   потребовала этого сама, ровно за тем список и падает в обе стороны.

   Заодно не теряется наблюдение из той записи: `id="viz-fallback"` на этой же
   фигуре не упомянут ни в CSS, ни в `js/site.js` — запасной путь, похоже,
   задумывался и не был подключён.

   Все три перестают переполняться между 480 и 560, так что перелом 660
   покрывает их с запасом, и на десктопе маски не появляется вовсе. Это важно
   не из аккуратности: маска заводит слой композиции, а производительность
   главной — открытый вопрос (B-79).

   Вторая идиома на сайте — статический градиент у `.index-signal` и полосы
   меню — НЕ трогается: она висит всегда, в том числе домотанной до конца, и
   это отдельный разговор, а не попутная правка. */
@media (max-width: 660px) {
  .rt-scroll, .lb-scroll, .viz {
    mask-image: linear-gradient(to right, #000 calc(100% - var(--rail-fade)), transparent);
    animation: rail-edge linear both;
    animation-timeline: scroll(self inline);
  }
}

.rt-table { width: 100%; min-width: 520px; border-collapse: collapse; font-size: var(--font-sm); }

.rt-table th[scope="col"] {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
  background: var(--control-bg);
  color: var(--text-muted);
  font-size: var(--font-xs);
  font-weight: var(--weight-medium);
  letter-spacing: 0.04em;
  text-align: start;
  text-transform: uppercase;
}

.rt-table th[scope="row"] {
  color: var(--text-primary);
  font-weight: var(--weight-medium);
  text-align: start;
}

.rt-table th[scope="row"],
.rt-table td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
  vertical-align: baseline;
}

.rt-table td { color: var(--text-secondary); }

/* Наша строка последняя и подсвечена фоном, а не цветом текста: подсветка
   говорит «вот эта», не утверждая, что остальные хуже. */
.rt-table tbody tr:last-child th[scope="row"],
.rt-table tbody tr:last-child td { border-bottom: 0; background: var(--accent-soft); }

/* Ссылка внутри абзаца различается НЕ ОДНИМ цветом. В статьях это правило
   уже есть (`patterns/kb-article.css`: `.kb-prose a` подчёркнута), а на
   главной и в строке копирайта его не было: ссылка на Bridge CDN шла тем
   же весом, без подчёркивания, и отличалась только оттенком — #818cf8
   против #a1a1aa вокруг, то есть 1.16:1 по яркости при норме 3:1, когда
   цвет остаётся единственным различием (WCAG 1.4.1).

   Двадцать шесть проверок молчали: контраст самого текста в норме, ссылка
   не битая, фокус виден. Нашёл Lighthouse правилом link-in-text-block — по
   одному узлу на каждой из семнадцати страниц (строка копирайта) и три
   на главной.

   `:not([class])` бьёт ровно по ссылкам из текста: у кнопок, карточек и
   пунктов навигации класс есть, и подчёркивание их не касается.

   Подвал сквозной, поэтому его правило лежит в `base.css`: статьи грузят
   `kb.css`, а не этот слой, и правило отсюда до них не доехало бы. Поймано
   тем же Lighthouse: главная стала 100, статья осталась 93. */
.index-homepage p a:not([class]) {
  text-decoration: underline;
  text-underline-offset: 2px;
}
