/**
 * Типографика контентных страниц.
 *
 * Идентичность не изобретается здесь заново — она уже есть в
 * web/src/styles/tokens.css: «две комнаты, один прибор». Тёмная — корпус, где
 * светится только трасса; светлая — не инверсия, а бумага под самописцем.
 * Значения повторены, а не импортированы: эти файлы не проходят через сборку
 * Vite, и вторая копия рядом с оригиналом честнее сборочной зависимости ради
 * четырёх статических страниц.
 *
 * Два решения, которые здесь отличаются от приложения, и почему:
 *
 * 1. **Дисплейная гарнитура — Manrope 800, с 16.08.2026.** До этого заголовки
 *    набирались моноширинным: приборный софт печатает им, и заголовок читался
 *    как вывод прибора, а не как реклама. Дизайн сайта это решение отменил —
 *    витрина продаёт подписку, и голос у неё свой. Моноширинный остался там,
 *    где несёт смысл: надзаголовки, числа, имена файлов.
 *
 * 2. **Ровно шесть ступеней кегля и ни одной меньше 12px.** Замер интерфейса
 *    14.08.2026 нашёл девять размеров и около пятнадцати объявлений на
 *    10–11px; здесь эта история не повторяется. Тапабельные цели — от 44px,
 *    тем же замером найдено 78 элементов меньше 32px.
 */

/* Гарнитуры витрины лежат своими файлами, а не приезжают из Google Fonts, как
   в прототипе: CSP держит `font-src 'self'` и `default-src 'self'`
   (public/_headers), и внешняя ссылка молча не отрисовалась бы.
   Golos Text — тот же шрифт, которым набрано приложение: витрина и прибор
   говорят одним голосом, даже пока их палитры не сведены.

   Подмножества и `unicode-range` — 28.08.2026. До этой даты каждая гарнитура
   стояла ОДНИМ файлом (`manrope-800.woff2`, `golos-text.woff2`), и оба были
   побайтово равны КИРИЛЛИЧЕСКОМУ подмножеству из fontsource. Латиницы в них не
   было вовсе — кроме буквы `A`, попавшей туда составной частью `Á` и `Ă`.
   Значит на четырнадцати языках из пятнадцати витрина была набрана системным
   шрифтом, а каждая `A` в ней приезжала из Golos: разнобой в каждом слове.
   Имена файлов теперь такие, какими их отдаёт fontsource, — общее имя такую
   подмену прячет, имя подмножества называет её вслух.

   Греческого и `cyrillic-ext` нет намеренно: ни одного языка из
   `web/content/languages.json` они не обслуживают. Вьетнамского подмножества
   у Golos не существует вовсе — вьетнамские надстрочные в тексте витрины
   берутся из системного шрифта, и это ограничение самой гарнитуры, а не
   недосмотр; заголовки (Manrope) вьетнамский закрывают. */
@font-face {
  font-family: 'Manrope';
  src: url('/fonts/manrope-latin-800-normal.woff2') format('woff2');
  font-weight: 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Manrope';
  src: url('/fonts/manrope-latin-ext-800-normal.woff2') format('woff2');
  font-weight: 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
    U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
    U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Manrope';
  src: url('/fonts/manrope-vietnamese-800-normal.woff2') format('woff2');
  font-weight: 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169,
    U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323,
    U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: 'Manrope';
  src: url('/fonts/manrope-cyrillic-800-normal.woff2') format('woff2');
  font-weight: 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

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

:root {
  color-scheme: light dark;

  /* Палитра сайта, 16.08.2026. Синий технический — отдельная идентичность от
     палитры прибора (src/styles/tokens.css, зелёно-серая). Две палитры в одном
     проекте — осознанное состояние на время полигона, а не недосмотр: решение
     свести их принимается после того, как обе видны рядом.

     Имена оставлены прежними — те, на которых уже написаны пять страниц.
     Хендофф называет токены по-приборному (`--ink-900`, `--type-100`); здесь
     они ложатся на местный словарь, а не привозят второй.

     Значения проверены `node scripts/contrast-check.mjs`: обычный текст от
     4.5:1, граница от 3:1. Менять цвет здесь — значит менять его и в списке
     PAIRS того скрипта. */
  --ground:      light-dark(#f7f9fb, #0a0e13);
  --panel:       light-dark(#eef2f7, #0c1116);
  --panel-alt:   light-dark(#f1f5f9, #141c26);
  --raised:      light-dark(#ffffff, #10161e);
  /* Как в макете. 1.41:1 и 1.59:1 — ниже порога 3:1, и это записанное решение
     Веры от 16.08.2026, а не недосмотр: витрина идёт по теме сайта. Прибор при
     этом остаётся при своём — в src/styles/tokens.css `--rule` держит 3.04:1,
     потому что там линия несёт разметку.
     СЛЕДСТВИЕ, которое надо помнить при вёрстке: раз линия не разделяет,
     разделяет фон. Не ставить границу между полосами одного уровня — она
     ничего не покажет и останется грязью. */
  --rule:        light-dark(#c9d5e2, #2a3744);
  --rule-soft:   light-dark(#dfe6ee, #1e2833);
  --ink:         light-dark(#0e1720, #e8eef4);
  --ink-mid:     light-dark(#33455a, #c8d6e2);
  --ink-soft:    light-dark(#56697d, #9aa9b8);
  /* Макетные #7d8fa1 / #6b7b8a давали 3.15:1 и 4.45:1 — ниже AA. Первая
     поправка (#627588 / #6c7c8b) целилась в `--ground` и прошла, но подписи
     подвала стоят на `--panel`: замер 21.08.2026 по отрисованной странице —
     4.23:1 светлая, 4.42:1 тёмная. Сдвинуто ещё раз, теперь до 4.5 на ХУДШЕЙ
     из подложек (панель светлой, приподнятая тёмной), тон сохранён. */
  --ink-faint:   light-dark(#5b6e81, #75859a);

  /* Акцент сайта. Не «хорошо» и не «плохо» — «нажми». Поэтому он синий, а не
     `--signal`: teal в этом продукте означает «файл в порядке», и кнопка того
     же цвета торговала бы вердиктом. */
  --brand:       light-dark(#0b6ea8, #6ec8f5);
  --brand-hover: light-dark(#08587f, #9adaf9);
  --brand-on:    light-dark(#ffffff, #06121c);
  --brand-edge:  light-dark(rgba(11,110,168,.5), rgba(110,200,245,.55));
  --brand-wash:  light-dark(rgba(11,110,168,.1), rgba(110,200,245,.16));

  /* Три марки вердикта — словарь протокола приёмки, а не наша выдумка:
     обычная строка, отмеченная в пределах 0,1 дБ от нормы, превышение.
     Четвёртой не заводить. Пережили смену палитры без правок: они означают
     результат измерения, а не принадлежность к оформлению. */
  --ok:        light-dark(#1c7a42, #57c97a);
  /* Граница «это работает». Приглушённый `--ok`, как `okA35` в макете: рамка
     карточки не должна кричать тем же голосом, что марка внутри неё. Порог
     границы 3:1 к ней не применяется — она не разделяет содержимое, а
     повторяет то, что уже сказано словом «РАБОТАЕТ СЕГОДНЯ». */
  --ok-edge:   light-dark(rgba(28,122,66,.4), rgba(87,201,122,.35));
  --near:      light-dark(#1f5f9e, #7ab8f0);
  --near-wash: light-dark(rgba(31,95,158,.07), rgba(122,184,240,.08));
  --over:      light-dark(#bd261e, #ff6259);
  --over-wash: light-dark(rgba(189,38,30,.07), rgba(255,98,89,.08));

  --signal:      light-dark(#0e6b5c, #a9f0df);
  --signal-wash: light-dark(rgba(14,107,92,.08), rgba(169,240,223,.07));

  /* Янтарный — предупреждение, которое не читается как отказ (`--over` уже
     занят «выше нормы»). Первым его попросило руководство (16.08.2026): там
     это и цвет `.note--warn` про журнал правок, и цвет метки «есть только у
     прибора» в разборе источника события. Значение унаследовано от
     собственной палитры страницы (была `--warn` там же), контраст пересчитан
     заново и внесён в contrast-check.mjs — 5.46:1 и 5.12:1, оба выше 4.5. */
  --warn:      light-dark(#9a5408, #f2a03d);
  --warn-wash: light-dark(rgba(154,84,8,.08), rgba(242,160,61,.09));

  /* Тонируется цвет, а не переключается тень целиком. `light-dark()` принимает
     только `<color>`; завёрнутый в него весь `box-shadow` — невалидный CSS, и
     свойство молча падает в `none`: тени нет ни в одной комнате, и об этом не
     скажет ни сборка, ни консоль. Ровно так написано в хендоффе
     (`site-tokens.css:34`) — ошибка приехала оттуда.
     Геометрия у обеих комнат одна. В макете тёмная была шире (0 30px 70px
     -30px), но разница в несколько пикселей размытия не стоит второго способа
     объявлять токен. */
  --shadow-card: 0 24px 60px -34px light-dark(rgba(20,40,60,.12), rgba(0,0,0,.8));

  --sans: 'Golos Text Variable', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --display: 'Manrope', var(--sans);
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* Шкала. Шесть ступеней, больше не заводить. */
  --t-xs: 12px;
  --t-sm: 14px;
  --t-md: 16px;
  --t-lg: 20px;
  --t-xl: 28px;
  --t-xxl: 44px;

  /* Минимальная тапабельная цель. */
  --tap: 44px;

  /* Подложка графика: в макете отдельный уровень (--chart #0b1017), темнее
     карточки. Нужен свой токен — `--raised` здесь читался бы как «кривая
     лежит на том же листе, что и рамка вокруг». */
  --chart:     light-dark(#ffffff, #0b1017);

  /* Сетка сайта. Прибор её не использует — у него свои размеры бухт. */
  --radius-card: 14px;
  --radius-control: 8px;
  --radius-chip: 7px;
  --page-max: 1340px;
  --page-pad: 32px;
  --section-pad: 80px;
}
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"]  { color-scheme: dark; }

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font: var(--t-md)/1.62 var(--sans);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

.wrap { max-width: 68ch; margin: 0 auto; padding: 0 24px 96px; }

/* Шапка: мера ширины страницы её не ограничивает — навигация идёт по всей. */
.nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 4px;
  border-bottom: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: var(--t-xs);
}
.nav__name {
  font-size: var(--t-sm);
  letter-spacing: .08em;
  font-weight: 700;
  color: inherit;
  text-decoration: none;
  padding-block: 14px;
  padding-inline: 0 10px;
  margin-inline-end: auto;
}
.nav a:not(.nav__name) {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  min-width: var(--tap);
  justify-content: center;
  padding: 0 10px;
  color: var(--ink-mid);
  text-decoration: none;
  letter-spacing: .04em;
}
.nav a:not(.nav__name):hover { color: var(--signal); }

/* Приборной гарнитурой остаётся только надзаголовок — h1–h3 ниже дисплейные. */
.eyebrow {
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 40px 0 0;
}
h1 {
  font-family: var(--display);
  font-size: clamp(var(--t-xl), 5.5vw, var(--t-xxl));
  line-height: 1.06;
  letter-spacing: -0.02em;
  font-weight: 800;
  margin: 14px 0 0;
  text-wrap: balance;
}
h2 {
  font-family: var(--display);
  font-size: var(--t-lg);
  line-height: 1.25;
  letter-spacing: -0.02em;
  font-weight: 800;
  margin: 52px 0 0;
  text-wrap: balance;
}
h3 {
  font-family: var(--display);
  font-size: var(--t-md);
  letter-spacing: -0.02em;
  font-weight: 800;
  margin: 30px 0 0;
}

/* Надзаголовок прямо перед h2 — не в шапке страницы (там дальше идёт h1), а
   внутри статьи, где у каждого раздела своя метка. Обычный отступ h2 (52px)
   рассчитан на разрыв между разделами; когда перед ним стоит его же eyebrow,
   разрыв уже держит сам eyebrow (40px), а h2 здесь нужно только прижаться —
   тем же приёмом, каким h1 прижимается к eyebrow в шапке (14px). Впервые
   понадобилось руководству, 16.08.2026. */
.eyebrow + h2 { margin-top: 14px; }

p, ul, ol { margin: 16px 0 0; }
ul, ol { padding-inline-start: 22px; }
li { margin-top: 7px; }
li::marker { color: var(--ink-soft); }
/* Мера набора: без неё лид идёт во всю ширину `.row` (1340px) — на 1440px это
   на глаз около 120 знаков в строке, вдвое больше читаемых 66-75. 68ch — не
   новое число, а то же самое, что уже держат `.wrap` и `.qa__a` ниже; здесь
   оно применено к бегущему тексту широких полос, а не изобретено заново. */
.lede { max-width: 68ch; font-size: var(--t-lg); line-height: 1.45; color: var(--ink-mid); margin-top: 18px; }
/* Моноширинный набор кажется крупнее санса того же кегля, отсюда .88em. Но
   `<code>` встречается и внутри 12-пиксельных контекстов — шапки, подписи,
   подвала, — где .88em дало бы 10,56px: ниже пола, который этот файл и заведён
   держать. `max()` оставляет уменьшение там, где есть запас, и упирается в
   нижнюю ступень шкалы там, где запаса нет. */
/* Размер не задаётся намеренно. Оптическая компенсация `.88em` выглядела
   безобидно, но замер отрисованных страниц 14.08 дал девять кеглей вместо
   шести: 12,32 в ячейке таблицы, 14,08 в тексте, 17,6 в лиде. Правило «ровно
   шесть ступеней» я требовал соблюдать буквально от других — значит и здесь.
   Наследование заодно само держит пол в 12px, и `max()` больше не нужен. */
code { font-family: var(--mono); }

a { color: var(--signal); text-underline-offset: 3px; }
a:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 3px;
  border-radius: 2px;
}

/* Двери: одна строка — один пришедший. Высота задана целью нажатия. */
.doors { margin-top: 24px; border-top: 1px solid var(--rule-soft); }
.door {
  display: flex;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
  min-height: 56px;
  padding: 12px 12px 12px 0;
  border-bottom: 1px solid var(--rule-soft);
  color: inherit;
  text-decoration: none;
}
/* Сдвиг — transform на заголовке, а не padding на строке: тот же жест
   (метка уезжает вправо, стрелка стоит у правого края), но без рефлоу на
   каждом кадре — padding-left в transition пересчитывал раскладку строки. */
.door:hover { background: var(--signal-wash); }
.door:hover b { transform: translateX(12px); }
/* Строка того же ряда, которая никуда не ведёт. Нужна отдельная марка, потому
   что `.door:hover` подсвечивает и подвигает строку — на некликабельном
   утверждении это обещание перехода, которого не будет. */
.door--flat { cursor: default; }
.door--flat:hover { background: none; }
.door--flat:hover b { transform: none; }
.door b { font-weight: 600; font-size: var(--t-md); }
.door span {
  color: var(--signal);
  font-family: var(--mono);
  font-size: var(--t-xs);
  white-space: nowrap;
}
@media (prefers-reduced-motion: no-preference) {
  .door { transition: background-color .12s ease; }
  .door b { transition: transform .12s ease; }
}

/* Таблицы. Широкие прокручиваются внутри себя — body не едет вбок никогда. */
.tblwrap {
  overflow-x: auto;
  margin-top: 22px;
  border: 1px solid var(--rule);
  background: var(--raised);
}
/* Мера набора таблице не указ. Замерено 14.08 на 1280px: сравнение шире
   68ch, и обрезалась крайняя правая колонка — наша собственная, «да, без
   регистрации» превращалось в «да, без регистраци». Прокрутка внутри рамки
   есть, но её не ищут. Текст остаётся в своей мере, широкий артефакт выходит
   за неё симметрично. Вычет 36px с каждой стороны — запас под полосу
   прокрутки, иначе `100vw` вылезает за окно. */
@media (min-width: 900px) {
  .tblwrap {
    width: min(100vw - 72px, 1040px);
    margin-inline: calc(50% - min(50vw - 36px, 520px));
  }
}
.tbl { border-collapse: collapse; width: 100%; font-size: var(--t-sm); }
.tbl th, .tbl td {
  text-align: start;
  padding: 11px 14px;
  border-bottom: 1px solid var(--rule-soft);
  font-variant-numeric: tabular-nums;
}
.tbl thead th {
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  font-weight: 600;
  background: var(--panel);
  border-bottom: 1px solid var(--rule);
  white-space: nowrap;
}
.tbl tbody tr:last-child td { border-bottom: 0; }
.tbl td:first-child { font-weight: 600; }

/* Три марки вердикта. Единственная система акцентов на этих страницах. */
.v-ok   { color: var(--ok); }
.v-near { color: var(--near); background: var(--near-wash); font-weight: 600; }
.v-over { color: var(--over); background: var(--over-wash); font-weight: 700; }
.v-none { color: var(--ink-soft); }

/* Подпись под таблицей или рисунком: говорит, откуда взялись числа. */
.cap {
  font-size: var(--t-sm);
  line-height: 1.5;
  color: var(--ink-soft);
  margin-top: 12px;
}

/* Заголовок таблицы для скринридера: зрячий читает шапку колонок, незрячему
   нужна одна фраза о том, что это за таблица, до того как начнутся ячейки. */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.note {
  border-inline-start: 3px solid var(--rule);
  background: var(--panel);
  padding: 16px 20px;
  margin-top: 22px;
}
.note--signal { border-inline-start-color: var(--signal); background: var(--signal-wash); }
.note--warn { border-inline-start-color: var(--warn); background: var(--warn-wash); }
.note > :first-child { margin-top: 0; }

.foot {
  margin-top: 64px;
  padding-top: 8px;
  border-top: 1px solid var(--rule-soft);
  font-family: var(--mono);
  font-size: var(--t-xs);
  color: var(--ink-soft);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* Промежуток мал, потому что ширину цели набирают отступы самой ссылки —
     как в `.nav`. Иначе между ссылками получилось бы 16 + 20 пикселей. */
  gap: 0 4px;
}
/* Обещание — не ссылка, и не должно выглядеть выключенной ссылкой. До этой
   правки оно было набрано тише соседних ссылок, то есть центральное
   утверждение продукта читалось как то, на что не нажимается. Утверждение
   громче навигации, а не тише. */
.foot__claim { color: var(--ink); padding-inline-end: 10px; }
/* Отступы здесь не косметика: `min-height` закрывает только высоту, а у
   короткой ссылки в подвале меньшая сторона — ширина. Без горизонтальных
   отступов «44 пикселя по меньшей стороне» держались бы на длине слова. */
.foot a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  min-width: var(--tap);
  justify-content: center;
  padding: 0 10px;
  color: var(--ink-mid);
  text-decoration: none;
}
.foot a:hover { color: var(--signal); }

/* --- Каркас сайта, 16.08.2026 -----------------------------------------------
 *
 * До этого дня витрина была набором документов: `.wrap` шириной 68ch, текст в
 * одну колонку. Дизайн сайта — другой жанр: полосы во всю ширину, карточки,
 * сетки. `.wrap` остаётся для страниц, которые читают абзацами (руководство,
 * гарантии); `.page` и `.band` — для тех, которые смотрят. */

.page { max-width: none; margin: 0; padding: 0; }

/* Полоса — горизонтальный слой страницы. Фон полосы во всю ширину окна,
   содержимое ограничено `--page-max`: так секции разделяются сменой уровня,
   а не линиями, ровно как панели в приборе. */
.band { padding: var(--section-pad) var(--page-pad); }
.band--panel { background: var(--panel); }
.band--alt { background: var(--panel-alt); }
.row { max-width: var(--page-max); margin: 0 auto; }
/* Та же мера, что у `.lede` чуть выше, и по той же причине — но здесь для
   обычного абзаца, стоящего в полосе прямо, не в карточке и не в сетке.
   Селектор нарочно берёт только ПРЯМЫХ детей `.row`: текст внутри `.card` и
   `.grid` уже сужен своим контейнером, трогать его нельзя (I3, ревью
   16.08.2026) — им тут взяться неоткуда, `.card` и `.grid` не бывают прямыми
   детьми `.row`, только внуками через них самих. */
.row > p { max-width: 68ch; }

.grid { display: grid; gap: 20px; }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }

.card {
  background: var(--raised);
  border: 1px solid var(--rule-soft);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: 24px;
}
/* Первый заголовок в карточке не должен нести верхний отступ h2/h3 (30–52px) —
   тот отступ существует для разрыва между абзацами страницы, а не между
   краем карточки и её же заголовком. Тот же приём, что у `.note`. */
.card > :first-child { margin-top: 0; }

/* Шапка липкая: на длинных маркетинговых полосах навигация, уехавшая вверх,
   заставляет скроллить обратно ради одного клика.
   Фон — `--panel`, на ступень выше полос под ней, и это следствие решения от
   16.08 оставить границу макетной: линия на 1,41:1 сама ничего не разделит, а
   липкая шапка на том же `--ground`, что и полоса под ней, при прокрутке
   слилась бы с содержимым. Разделяет уровень, линия остаётся подсказкой. */
.site-head {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 24px;
  padding: 0 var(--page-pad);
  min-height: 64px;
  background: var(--panel);
  border-bottom: 1px solid var(--rule);
}
/* Имя продукта — тоже ссылка, и пол тапабельной цели на неё распространяется.
   Прежний `.nav__name` набирал 44 пикселя отступами, потому что при
   `align-items: center` флекс-элемент сжимается до высоты своей строки.
   Приём перенесён, а не потерян. */
/* Вывеска набирается ТЕМ ЖЕ, чем в приложении (`.app__header h1` в
   `App.css`): Manrope 800, 15px, разрядка .06em. До 28.08.2026 витрина
   носила её системным моноширинным (`--mono`), и на одном экране с `/app`
   это читалось как два разных продукта — Вера увидела это первым же
   сравнением шапок. Имя продукта — одно, значит и гарнитура одна; пара к
   `.app__header h1` — менять только вместе. Сторожит
   `scripts/font-check.mjs`: он спрашивает у браузера, какими гарнитурами узел
   фактически отрисован, и требует ровно одну — Manrope. */
.site-head__name {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  min-height: var(--tap);
  font: 800 15px/1.2 var(--display);
  letter-spacing: .06em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}

/* Знак: изумрудный ромб — решение Веры 21.08.2026, единый для витрины и
   приложения (до этого витрина носила сине-бирюзовый, приложение — свой, и
   это были два бренда). Переход `--signal` → `--ok`: оба уже в палитре, оба
   про одно — «файл цел» и «в норме», то есть ромб говорит цветом то, ради
   чего продукт открывают. Пара к `.app__header h1::before` в `App.css` —
   менять только вместе. `favicon.svg` несёт те же два цвета зашитыми: в нём
   токены недоступны.

   Рисуется псевдоэлементом, а не тегом: имя продукта уже ссылка, и вложенный
   ради украшения узел читалка объявила бы вслух отдельной строкой. Поворот
   не меняет места, которое элемент занимает в потоке, поэтому ромб вылезает
   за свои 18px примерно на 4px с каждой стороны — эти четыре пикселя
   съедаются `gap` и `--page-pad`, отдельного запаса не нужно. */
.site-head__name::before,
.site-foot__brand::before {
  content: '';
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  border-radius: 4px;
  background: linear-gradient(135deg, var(--signal), var(--ok));
  transform: rotate(45deg);
}
.site-foot__brand {
  display: flex;
  align-items: center;
  gap: 11px;
}
.site-foot__brand::before { width: 16px; height: 16px; }
/* Правый край шапки держит НЕ навигация, а первый же сосед названия.
   До 21.08.2026 отступ висел на `.site-head__nav` — и это работало ровно до
   тех пор, пока навигация была на каждой странице. Со снятием двери просмотра
   (ADR-004) её не стало ни на `404.html`, ни в сборке `free`, где все
   остальные пункты — контентные страницы, отвечающие 404: кнопка съезжала
   вплотную к названию продукта. Соседний селектор верен в обоих случаях —
   когда сосед навигация, отступ оказывается ровно там же, где был. */
.site-head__name + * { margin-inline-start: auto; }

.site-head__nav { display: flex; gap: 4px; margin-inline-start: auto; }
.site-head__nav a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0 12px;
  border-radius: var(--radius-control);
  color: var(--ink-soft);
  font-size: var(--t-sm);
  text-decoration: none;
}
.site-head__nav a:hover { color: var(--ink); background: var(--brand-wash); }
.site-head__nav a[aria-current="page"] { color: var(--ink); }

/* --- Сторона чтения ---------------------------------------------------------
 *
 * Правила ниже и выше, задающие СТОРОНУ ЧТЕНИЯ, записаны логическими
 * свойствами (`margin-inline-start`, `padding-inline-end`, `text-align: start`,
 * `border-inline-start`, `inset-inline-end`), а не левым и правым: арабская
 * витрина (`/ar`, `dir="rtl"` из реестра) обязана зеркалить отступ списка,
 * кант выноски и прижим навигации, и делать это без второго набора правил.
 *
 * Физические `left`/`right` остались там, где сторона не читательская, а
 * геометрическая. Их не переводить механически: `padding: 0 10px` симметричен и
 * в переводе не нуждается, а размеры канвы и графика к направлению письма
 * отношения не имеют вовсе — см. правило `.chart { direction: ltr }` в
 * `src/App.css` и раздел 8 спеки. */

/* Переключатель языка. Полоса ячеек → выпадающий список, 21.08.2026.
   Прежняя редакция стояла корпусом рокера: две ячейки в одной рамке, текущая
   под заливкой. Довод был записан там же и был верен для двух языков; языков
   стало четырнадцать (решение Веры), и четырнадцать ячеек в строку заняли бы
   шапку целиком. Теперь это <details>, как мобильное меню строкой ниже:
   раскрытие без единого скрипта, содержимое лежит ВНУТРИ.

   Подписи — имена языков на них самих, а не коды: коды помещались в строку,
   пока их было два, а `VI` вместо `Tiếng Việt` не говорит ничего тому, кто
   ищет свой язык глазами. Ячейка текущего языка — <span>, не ссылка: дверь в
   саму себя читалка объявила бы переходом, за которым ничего нет.

   Ячейка-ссылка ведёт на двойника страницы с `?hl=`; куку ставит воркер.
   Пара к этому блоку — `.site-lang` в `src/site/site.css` (React-шапка) и в
   `src/App.css` (шапка приложения): три реализации одного вида, менять
   только вместе. */
.site-lang {
  position: relative;
  flex-shrink: 0;
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: .08em;
}
.site-lang__now {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  /* Корпус в сумме держит пол тапа: 42 + 2px рамки = var(--tap). */
  min-height: calc(var(--tap) - 2px);
  padding: 0 11px;
  color: var(--ink-soft);
  border: 1px solid var(--rule);
  border-radius: var(--radius-control);
  cursor: pointer;
  /* Треугольник раскрытия рисует ОС, и ни один токен на него не действует —
     та же причина, по которой отсюда когда-то ушёл нативный <select>. */
  list-style: none;
}
.site-lang__now::-webkit-details-marker { display: none; }
.site-lang__now:hover { color: var(--ink); background: var(--brand-wash); }
.site-lang[open] .site-lang__now { color: var(--ink); background: var(--brand-wash); }
/* Список ложится ПОВЕРХ страницы, а не раздвигает шапку: шапка липкая, и
   прыжок её высоты сдвинул бы под курсором всё, что читатель разглядывал. */
.site-lang__menu {
  position: absolute;
  inset-inline-end: 0;
  top: calc(100% + 4px);
  z-index: 20;
  display: flex;
  flex-direction: column;
  min-width: 190px;
  max-height: 70vh;
  overflow-y: auto;
  padding: 4px;
  background: var(--raised);
  border: 1px solid var(--rule);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-card);
}
.site-lang__cell {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: var(--tap);
  padding: 0 11px;
  color: var(--ink-soft);
  text-decoration: none;
  border-radius: var(--radius-control);
  /* Кнопка в React-шапке и ссылка на витрине — один вид. */
  background: none;
  border: 0;
  font: inherit;
  letter-spacing: inherit;
  text-align: start;
  cursor: pointer;
}

/* Флаг рядом с именем языка (решение Веры 21.08.2026; пара к `.site-lang__flag`
   в site.css и App.css — менять только вместе). Инлайн-SVG, не эмодзи: Windows
   не рисует флаги-эмодзи вовсе, а это основная ОС аудитории. Рамка токеном
   обязательна: белая полоса триколора на светлой панели без неё растворяется
   в фоне. */
.site-lang__flag {
  display: block;
  flex: 0 0 auto;
  width: 15px;
  height: 10px;
  border: 1px solid var(--rule);
  border-radius: 2px;
}
/* Языки без узнаваемого флага (арабский) несут буквенную плашку того же
   размера — флаг называет страну, а не язык, и для них это было бы враньём. */
.site-lang__glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 10px;
  font-size: 9px;
  line-height: 1;
}
.site-menu__lang .site-lang__flag { margin-inline-end: 7px; }
a.site-lang__cell:hover,
button.site-lang__cell:hover { color: var(--ink); background: var(--brand-wash); }
.site-lang__cell[aria-current] { color: var(--ink); background: var(--brand-wash); }

/* Полоса машинного перевода: язык, который никто не вычитывал, обязан
   сказать это сам — и дать адрес, по которому напишут об ошибке. */
.site-mtnote {
  margin: 0;
  padding: 6px var(--page-pad);
  background: var(--panel-alt);
  border-bottom: 1px solid var(--rule-soft);
  color: var(--ink-soft);
  font-size: var(--t-xs);
}

/* Мобильное меню — <details> без единого скрипта; на десктопе его нет.
   Пункты продублированы из `.site-head__nav` сознательно: раскрытие без
   скрипта требует, чтобы они жили ВНУТРИ <details> (содержимое закрытого
   элемента не достаётся никаким CSS), а прежняя полоса с невидимой
   прокруткой прятала половину навигации без единого намёка — замер
   21.08.2026 на 390px: «Тарифы», «База знаний», «О нас» и «Контакты»
   существовали только для того, кто догадается потянуть строку вбок. */
.site-menu { display: none; }

/* Кнопка. Это ЗАМЕНА прежнего блока `.cta` / `.cta--solid`, а не добавка к
   нему. Два правила одного класса с одинаковым весом селектора каскад
   разрешает ПОСВОЙСТВЕННО: всё, чего новое правило не назовёт заново, доживает
   от старого — `margin: 24px 10px 0 0` и бирюзовая рамка на синей заливке.
   Это не «старый стиль против нового», это гибрид, которого никто не
   проектировал. Поэтому набор свойств здесь полный. */
.cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  min-width: var(--tap);
  /* Замер 16.08.2026 на 380px: без этих двух строк флекс сжимал кнопку в
     `.site-head` до 53px, а её подписи «Попробовать» нужно 71px — надпись
     выезжала за край на ~18px, потому что `min-width: var(--tap)` держит
     только пол в 44px, а не собственный контент. `flex-shrink: 0` запрещает
     сжимать кнопку ниже её содержимого, `white-space: nowrap` не даёт
     надписи перенестись и раздвинуть кнопку в высоту. Кнопка, сжатая тоньше
     своей надписи, хуже, чем шапка, которая на 380px скроллится вбок сама —
     на это и рассчитан `.site-head__nav` рядом. */
  flex-shrink: 0;
  white-space: nowrap;
  padding: 0 20px;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  font-size: var(--t-sm);
  font-weight: 600;
  text-decoration: none;
}
.cta--solid { background: var(--brand); color: var(--brand-on); }
.cta--solid:hover { background: var(--brand-hover); color: var(--brand-on); }
.cta--ghost { border-color: var(--brand-edge); color: var(--brand); }
.cta--ghost:hover { background: var(--brand-wash); }

.site-foot {
  background: var(--panel);
  border-top: 1px solid var(--rule);
  padding: 56px var(--page-pad) 40px;
}
.site-foot__row {
  max-width: var(--page-max);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1.4fr repeat(3, 1fr);
  gap: 32px;
}
.site-foot__col h4 {
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: .1em;
  color: var(--ink-faint);
  margin: 0 0 12px;
}
/* Вывеска подвала — то же имя продукта, что в шапке, поэтому и гарнитура та
   же, а не заголовок колонки. Селектор с тегом (`h4.site-foot__brand`), чтобы
   перебить `.site-foot__col h4` выше весом, а не порядком: в `404.html`
   разметка подвала своя, и на порядок опираться нельзя. */
h4.site-foot__brand {
  font: 800 15px/1.2 var(--display);
  letter-spacing: .06em;
  color: var(--ink);
}
/* Пол тапабельной цели держится и здесь. Отступы не косметика: `min-height`
   закрывает только высоту, а у короткой ссылки в подвале меньшая сторона —
   ширина; без горизонтальных отступов «44 по меньшей стороне» держались бы на
   длине слова. Ровно это записано у `.foot a` замером 14.08.2026, и колонки
   футера от этого выше, чем в макете. Пол выигрывает у макета. */
.site-foot__col a {
  /* `flex`, а не `inline-flex`: ссылки в колонке стоят одна под другой.
     `inline-flex` пустил бы их в строку — замерено, три ссылки делили одну
     верхнюю границу и налезали друг на друга на 6 пикселей. `fit-content`
     возвращает ширину цели к тексту с отступами, иначе кликабельной стала бы
     вся ширина колонки. */
  display: flex;
  width: fit-content;
  align-items: center;
  min-height: var(--tap);
  padding: 0 10px;
  margin-inline-start: -10px;
  color: var(--ink-soft);
  font-size: var(--t-sm);
  text-decoration: none;
}
.site-foot__col a:hover { color: var(--brand); }

@media (max-width: 900px) {
  :root { --page-pad: 20px; --section-pad: 48px; }
  .grid--2, .grid--3 { grid-template-columns: 1fr; }
  .site-foot__row { grid-template-columns: 1fr 1fr; }
  /* Строка «источник события» в руководстве: термин слева, объяснение
     справа, 11rem на термин — на телефоне под объяснение остаётся меньше
     половины экрана. Один и тот же брейкпоинт на весь файл, не второй. */
  .kb-sources li { grid-template-columns: minmax(0, 1fr); }

  /* Навигация уходит под «Меню» — <details> без единого скрипта.

     Прежде полоса прокручивалась вбок с невидимой полосой прокрутки: бургер
     считался требующим скрипта, а витрина без скриптов — принятым
     ограничением. Оба основания кончились. Раскрытие на <details> скрипта не
     требует вовсе; ограничение «без скриптов» снято решением Веры 21.08.2026
     о зоне дропа на главной. Чем платила полоса, замерено на 390px: за краем
     без единого намёка жили «Тарифы», «База знаний», «О нас» и «Контакты» —
     то есть половина сайта существовала для того, кто догадается потянуть
     строку пальцем вбок. Подсказка «край пункта виден» на первой строке с
     именем и кнопкой не помещалась и не работала.

     Порядок документа сохранён: имя → меню → кнопка, без `order` (урок
     WCAG 2.4.3 из прежней редакции этого блока в силе — фокус идёт как DOM).
     Кнопка больше не занимает вторую строку целиком: шапка снова один ряд. */
  .site-head { gap: 10px; }
  .site-head__nav { display: none; }

  .site-menu { display: block; position: relative; margin-inline-start: auto; }
  .site-menu > summary {
    list-style: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    min-height: var(--tap);
    padding: 0 14px;
    border: 1px solid var(--rule);
    border-radius: var(--radius-control);
    color: var(--ink-mid);
    font-size: var(--t-sm);
    user-select: none;
  }
  .site-menu > summary::-webkit-details-marker { display: none; }
  .site-menu > summary:hover { color: var(--ink); background: var(--brand-wash); }
  .site-menu[open] > summary { color: var(--ink); background: var(--brand-wash); }
  .site-menu__nav {
    position: absolute;
    inset-inline-end: 0;
    top: calc(100% + 8px);
    z-index: 30;
    display: flex;
    flex-direction: column;
    min-width: 224px;
    padding: 8px;
    background: var(--raised);
    border: 1px solid var(--rule);
    border-radius: 12px;
    box-shadow: var(--shadow-card);
  }
  .site-menu__nav a {
    display: flex;
    align-items: center;
    min-height: var(--tap);
    padding: 0 12px;
    border-radius: 8px;
    color: var(--ink-mid);
    text-decoration: none;
  }
  .site-menu__nav a:hover { color: var(--ink); background: var(--brand-wash); }
  .site-head .cta { padding: 0 14px; }

  /* На телефоне корпус переключателя в один ряд с именем, меню и кнопкой не
     помещается (замер арифметикой на 390px: имя ~130 + меню ~70 + рокер ~90 +
     кнопка ~110 + зазоры > 390). Язык уезжает пунктом в то же меню — той
     самой строкой `site-menu__lang`, которая лежит в каждом <details>. */
  .site-lang { display: none; }
  .site-menu__nav .site-menu__lang {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--rule);
    font-family: var(--mono);
    font-size: var(--t-xs);
    letter-spacing: .08em;
  }
}

/* --- Главная, 16.08.2026 -----------------------------------------------
 *
 * Прототип (docs/design/site-2026-08-16) кладёт в герой карточку с трассой и
 * тремя цифрами (ДЛИНА / ПОТЕРИ / СОБЫТИЙ). Здесь на этом месте стоит реестр
 * волокон барабана — трассу рисуют все конкуренты, реестр, сверенный с
 * паспортом, не рисует никто, и это причина, по которой продукт вообще
 * существует. Таблица реестра не встаёт вторым столбцом рядом с текстом
 * героя: `.tblwrap` уже умеет выходить за меру страницы по формуле от
 * ширины окна (строка 280 выше), а не от своей колонки грид-контейнера —
 * посади её в `grid-template-columns:1fr 1fr`, и формула бы считала не то. */

.hero-cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }

/* Зона дропа героя (эскиз Веры, 21.08.2026): ссылка, оформленная целью.
   Пунктир — тот же язык, что у пустого экрана /app: человек, увидевший зону
   здесь, узнаёт её там. Без скрипта это обычная ссылка в /app; с landing.js
   клик открывает выбор файла, а целью перетаскивания становится весь экран —
   подсветку несёт класс `dropping` на <body>, зона лишь отвечает. Кайма — от
   токенов через color-mix, а не новый цвет: рамка должна быть заметнее
   разделительной линии (--rule здесь сознательно слабая), но тише кнопки. */
.drop {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 18px;
  max-width: 560px;
  padding: 14px 18px;
  border: 1.5px dashed color-mix(in srgb, var(--ink-faint) 55%, var(--ground));
  border-radius: 12px;
  background: color-mix(in srgb, var(--raised) 55%, transparent);
  color: var(--ink-mid);
  text-decoration: none;
  transition: border-color 0.15s, background 0.15s;
}
.drop:hover, .drop:focus-visible { border-color: var(--brand); }
.drop svg { flex: 0 0 auto; color: var(--ink-soft); }
.drop__t1 { display: block; font-size: var(--t-md); font-weight: 500; }
.drop__t2 {
  display: block;
  margin-top: 3px;
  font-family: var(--mono);
  font-size: var(--t-xs);
  color: var(--ink-soft);
}
.drop__active { display: none; }
body.dropping .drop {
  border-style: solid;
  border-color: var(--brand);
  background: var(--brand-wash);
}
body.dropping .drop .drop__idle { display: none; }
body.dropping .drop .drop__active { display: block; }

/* Строка аудиторий (`.audience`) удалена вместе с правилами. Она стояла в
   герое пятым текстовым элементом после надзаголовка, заголовка, лида и
   кнопок, набранная моноширинным капслоком, — то есть ровно тем приёмом,
   которым страница показывает служебные пометки. Кому продукт адресован,
   теперь сказано обычной фразой в разделе ниже, где это читают, а не
   пробегают глазами. */

/* Марка состояния функции — словарь другой, чем у вердикта таблицы
   (`v-ok`/`v-near`/`v-over`): та говорит про измерение, эта — про то, что уже
   написано в коде. Смешивать их нельзя, поэтому и токены разные, хотя `--ok`
   переиспользован: смысл «работает, можно полагаться» у обеих совпадает.
   Третьей марки («ЧАСТИЧНО» из прототипа) здесь нет — на странице ни одна
   возможность не описана как частичная, а придумывать такую ради полноты
   набора значило бы смягчать формулировку в другую сторону. */
.mark {
  display: inline-block;
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: .1em;
  border: 1px solid currentColor;
  border-radius: var(--radius-chip);
  padding: 2px 8px;
}
.mark--now { color: var(--ok); }
.mark--wip { color: var(--ink-soft); }
/* Третья марка, из макета. «Частично» — не смягчённое «в разработке», а
   отдельное состояние: часть работы уже делается, часть ещё нет, и слить их
   в две марки значит соврать в одну из двух сторон. */
.mark--part { color: var(--warn); }

/* Раздел «Что закрывает платформа»: четыре узких места, у каждого свой номер
   и своё состояние. Номер здесь несёт смысл — это порядок, в котором работа
   встречается между измерением и сдачей, а не украшение перечня.
   Марка стоит рядом с номером, потому что состояние относится к узкому месту
   целиком, а не к заголовку карточки. */
/* `.h1-sub` удалён: второй половины заголовка («Документация — в тот же
   день») больше нет, обещание снято как несбывшееся. */

/* Перечень без маркеров: строки списка «работает / в разработке» — это пункты
   перечисления, а не проза, и `<ul>` здесь ради того, чтобы читалка объявила
   их количество. Точки при этом лишние: строка уже отбита от соседней. */
.plain {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.plain li { color: var(--ink-mid); }

/* Моноширинная подпись под карточкой: перечень форматов и имён приборов.
   Набрана как данные, а не как проза, потому что человек ищет здесь глазами
   своё — «AFL», «MSOR» — а не читает подряд. Интерлиньяж крупный: три строки
   через `<br>` иначе слипаются в блок. */
.specs {
  font-family: var(--mono);
  font-size: var(--t-xs);
  line-height: 1.9;
  color: var(--ink-faint);
  margin-top: 14px;
}

.stage__top {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}
.stage__num {
  font-family: var(--mono);
  font-size: var(--t-lg);
  letter-spacing: .04em;
  color: var(--brand);
  font-variant-numeric: tabular-nums;
}

/* --- Тарифы, 16.08.2026 -------------------------------------------------
 *
 * Прототип (docs/design/site-2026-08-16) рисует в этом месте числовой
 * ценник под каждой платной карточкой и тумблер месяц/год, который между
 * двумя ценами переключает. Решение Веры 16.08.2026: цен на витрине нет,
 * «по запросу» — ни ценник, ни тумблер сюда не перенесены, и сами цифры не
 * выписаны здесь даже примером: этот файл отдаётся посетителю байт в байт
 * (view-source, вкладка «Сеть»), и запрещённое число в CSS-комментарии
 * ушло бы в эфир так же, как в видимом тексте страницы. Тумблер существовал
 * только затем, чтобы переключать две цифры; без цифр он переключает
 * пустоту. `.plan__price` держит и «Бесплатно», и «Цена по запросу» одним
 * начертанием — там, где в прототипе стояло число, стоит текст той же
 * роли, а не заглушка меньшего веса. */
.grid--3 .plan {
  display: flex;
  flex-direction: column;
}
.plan__price {
  font-family: var(--display);
  font-size: var(--t-xl);
  font-weight: 800;
  letter-spacing: -0.02em;
  margin-top: 18px;
}
.plan__note {
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: .06em;
  color: var(--ink-soft);
  margin-top: 6px;
}
/* `flex: 1` растягивает список на всё, что осталось в карточке, и прижимает
   кнопку к нижнему краю — три карточки грид уже выравнял по высоте строки
   (`align-items: stretch` по умолчанию), это довершает работу внутри каждой. */
.plan__has {
  flex: 1;
  margin-top: 18px;
  padding-inline-start: 20px;
}
.plan__has li {
  font-size: var(--t-sm);
  color: var(--ink-mid);
}
.plan .cta {
  margin-top: 24px;
  width: 100%;
}
/* Средняя карточка — не потому что дороже (цены нет), а потому что на неё чаще
   отвечают триалом. Рамка и тень берут акцентный токен кнопки, а не заводят
   свой: третьего оттенка синего на странице не появляется. */
.plan--lead {
  border-color: var(--brand-edge);
  box-shadow: 0 24px 60px -34px var(--brand-edge);
}

/* --- Руководство (guide.html), 16.08.2026 --------------------------------
 *
 * До этой правки у страницы был свой <style> на 424 строки и 51 собственный
 * токен — вторая палитра рядом с этой, и палитра сайта из задачи 1 сюда не
 * доходила. Дальше — только то, чего в общем словаре ещё не было и что нужно
 * именно длинной статье: карточки оглавления, лента отсчёта прибора, схемы
 * 2P/LSA и разметка источника события. Сама статья в этой разметке не
 * нуждается — она в `.wrap`, как любой другой текст на этих страницах. */

/* Компактная надпись без отступа `.eyebrow`: категория в карточке оглавления
   и подпись поля в ленте отсчёта ниже. Не замена `.eyebrow` — та отбивает
   40px сверху, потому что открывает страницу или раздел; этой отбивать
   нечего, она стоит внутри карточки или строки. */
.silk {
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* Якорь не должен прятаться под липкую шапку (64px) — переход по карточке
   оглавления обязан показать и метку раздела, не только первую строку под
   ней. */
section[id] { scroll-margin-top: 84px; }

/* Карточка оглавления — ссылка на якорь той же страницы, не на отдельную
   статью: у руководства пока одна большая статья, а не библиотека заметок,
   поэтому подписи вида «Читать →» нет — переходом служит вся карточка. */
.kb-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  color: inherit;
  text-decoration: none;
}
.kb-card:hover h3 { color: var(--signal); }

/* Числа читаются друг против друга, поэтому — моноширинный шрифт и табличные
   цифры, где бы они ни стояли: во фразе, в клавише, в ленте отсчёта. */
.n,
kbd {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}
kbd {
  padding: 1px 6px;
  border: 1px solid var(--rule);
  border-bottom-width: 2px;
  border-radius: 4px;
  background: var(--raised);
  font-size: var(--t-xs);
  white-space: nowrap;
}

/* Лента отсчёта — как в приложении под графиком после того, как поставлены
   курсоры A и B: где курсор, какой там уровень, длина участка и оба способа
   посчитать потери с разбросом между ними. */
.kb-readout {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 22px;
  padding: 12px 14px;
  margin-top: 18px;
  border: 1px solid var(--rule);
  background: var(--panel);
  overflow-x: auto;
}
.kb-cell { display: flex; flex-direction: column; gap: 4px; }
.kb-cell .v {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-xs);
  white-space: nowrap;
}
.kb-cell .v .rate { color: var(--ink-faint); }
.kb-cell--marker .silk { color: var(--brand); }

/* Схемы 2P/LSA нарисованы по посчитанным точкам, а не на глаз (см. комментарий
   в guide.html) — плашка узнаваемо обрамляет такую иллюстрацию. Цвет линии
   волокна — `--signal`: это тот же смысл, «сигнал/трасса», что и везде на
   сайте, не отдельный оттенок для одной статьи. */
figure { margin-top: 18px; display: flex; flex-direction: column; gap: 10px; }
.kb-plate {
  padding: 10px;
  border: 1px solid var(--rule);
  background: var(--panel);
  overflow-x: auto;
}
.kb-plate svg { display: block; width: 100%; height: auto; color: var(--ink-soft); }
figcaption { color: var(--ink-soft); font-size: var(--t-sm); line-height: 1.5; }

/* Источник события: наш поиск и таблица прибора сходятся не всегда, и в
   статье это разбор трёх исходов — совпало, есть только у прибора, есть
   только у нас. Зелёный переиспользует `--ok` (то же «в порядке»,
   какой смысл — тот же токен), синий и янтарь — `--signal`/`--warn`. */
.kb-sources { display: flex; flex-direction: column; gap: 12px; padding: 0; margin-top: 16px; list-style: none; }
.kb-sources li { display: grid; grid-template-columns: 11rem minmax(0, 1fr); gap: 4px 14px; align-items: baseline; }
.kb-tag { display: inline-flex; align-items: center; gap: 8px; font-family: var(--mono); font-size: var(--t-xs); }
.kb-tag::before { content: ""; width: 3px; height: 13px; background: currentcolor; }
.kb-tag--both { color: var(--ok); }
.kb-tag--instrument { color: var(--warn); }
.kb-tag--detected { color: var(--signal); }

/* Пронумерованные шаги — счётчик CSS вместо `<ol>` по умолчанию, потому что
   номер здесь набран моноширинным и с ведущим нулём, как на приборной
   панели, а не обычной точкой после цифры. */
ol.kb-steps { counter-reset: step; list-style: none; padding: 0; }
ol.kb-steps > li {
  counter-increment: step;
  display: grid;
  grid-template-columns: 2rem minmax(0, 1fr);
  gap: 12px;
  align-items: baseline;
}
ol.kb-steps > li::before {
  content: counter(step, decimal-leading-zero);
  font: 500 var(--t-xs)/1.6 var(--mono);
  letter-spacing: .1em;
  color: var(--brand);
}

/* --- Вопросы и ответы (faq.html), 16.08.2026 -----------------------------
 *
 * Семь вопросов, открыт один за раз. Родного HTML на «один за раз» хватает:
 * `<details name="faq">` делает группу взаимоисключающей без единой строки
 * скрипта (Baseline 2024, Safari 17.2+, Chrome 120+, Firefox 130+). Там, где
 * атрибут ещё не поддержан, открывается несколько ответов сразу — это мягче,
 * чем сломаться, и потому приемлемо: витрина без скриптов не может себе
 * позволить полифил. */
.qa { border-bottom: 1px solid var(--rule-soft); }
.qa__q {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  padding: 14px 0;
  font-size: var(--t-md);
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
  list-style: none;
}
/* `<summary>` рисует свой треугольник в WebKit по умолчанию — плюс/минус
   ниже его заменяет, второй маркер был бы дублем. */
.qa__q::-webkit-details-marker { display: none; }
.qa__q::after {
  content: "+";
  margin-inline-start: auto;
  font-family: var(--mono);
  color: var(--ink-faint);
}
.qa[open] .qa__q::after { content: "−"; }
.qa__a { padding-bottom: 18px; color: var(--ink-mid); max-width: 68ch; }
.qa__q:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* ОГОВОРКА К ПРАВИЛУ ШЕСТИ СТУПЕНЕЙ (шапка этого файла, пункт 2). Ниже
   встречаются 10, 11, 13, 15, 17, 18, 19, 32, 36 и 40 пикселей — не в шкале.
   Это не возврат к найденному 14.08 разнобою из девяти размеров: у макета своя
   шкала, и решение «сначала сделай главную 1 в 1 как в макете» (Вера,
   16.08.2026) означает и её тоже. Правило шести ступеней продолжает держать
   остальные восемь страниц; здесь оно уступает макету осознанно, и ни один
   размер по-прежнему не мельче 10px в марке и 13px в тексте.

/* === Главная: раскладка макета один в один ==============================
   Собрано по `docs/design/site-2026-08-16/OTDR Master Site.dc.html`, значения
   сняты с прототипа, а не подобраны на глаз: 1240px контейнер, 88/72 у героя,
   80 у середины, 72 у закрывающего, gap 64 / 56 / 16, радиусы 16 / 14 / 12 / 9.

   Токены макета легли на наши без второй палитры:
     --surface #10161e → --raised   --line  #1e2833 → --rule-soft
     --bg2     #0c1116 → --panel    --line3 #2a3744 → --rule
     --muted   #9aa9b8 → --ink-soft --text2 #c8d6e2 → --ink-mid
     --dim     #6b7b8a → --ink-faint  --accent → --brand, --ok → --ok
   Поэтому светлая тема получается сама: у каждого имени уже есть вторая
   половина `light-dark()`, чего у прототипа не было вовсе. ==================*/

.sheet { --sheet-max: 1240px; }

/* Раздел отбивается линией сверху, а не полосой фона. У первого линии нет:
   над ним шапка со своей границей, две подряд читались бы как рамка. */
.sec { padding: 80px var(--page-pad); border-top: 1px solid var(--rule-soft); }
.sec:first-child { border-top: 0; }
.sec--hero { padding: 88px var(--page-pad) 72px; }
.sec--tint { background: var(--panel); }
.sec--close { padding: 72px var(--page-pad); background: linear-gradient(180deg, var(--panel), var(--ground)); }
.sec__in { max-width: var(--sheet-max); margin: 0 auto; }

.kicker {
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--brand);
  margin: 0;
}
.kicker--ok { color: var(--ok); }

.sec__h {
  font-family: var(--display);
  font-weight: 800;
  font-size: 40px;
  line-height: 1.1;
  letter-spacing: -.02em;
  max-width: 640px;
  margin: 12px 0 40px;
}
.sec__h--sm { font-size: 36px; line-height: 1.12; margin-bottom: 16px; }
.sec__h--xs { font-size: 32px; margin: 0 0 10px; max-width: none; }
.sec__lede { font-size: var(--t-md); line-height: 1.6; color: var(--ink-soft); max-width: 60ch; margin: 0 0 26px; }

/* Герой: текст и снимок приложения. Снимок получил КОЛОНКУ ШИРЕ текста
   (1fr к 1.15fr, было 1.05fr к 1fr): нарисованную карточку можно было
   ужимать сколько угодно, у настоящего снимка есть мера читаемости. При
   1240px меры страницы это 633px на снимок против 551px на текст, то есть
   836px снятой области показываются в масштабе 0.76 — подписи в 11px
   доходят до читателя примерно как 8px, чего хватает, чтобы прочесть числа
   и опознать экран как настоящий. Уже — и снимок превращается в текстуру. */
.hero { display: grid; grid-template-columns: 1fr 1.15fr; gap: 56px; align-items: center; }
/* Кегль опущен с 60px до 52px не ради вкуса, а под меру: в 551px колонки
   «Рефлектограммы в браузере.» при 60px ложится в три строки, при 52px — в
   две. Заголовок в четыре строки — всегда ошибка кегля, а не длины фразы. */
.hero h1 {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(34px, 3.6vw, 52px);
  line-height: 1.04;
  letter-spacing: -.03em;
  margin: 20px 0 22px;
}
.hero__lede { font-size: 18px; line-height: 1.6; color: var(--ink-soft); max-width: 520px; margin: 0 0 32px; }
.hero .hero-cta { margin: 0; }

/* Здесь стояли правила `.trace`, `.trace__top`, `.trace__name`,
   `.trace__verdict`, `.trace__plot`, `.trace__stats` и `.stat` — оформление
   нарисованной карточки трассы: сетка под кривой рисовалась фоном шагами
   42px и 60px, числа набирались как `.stat__v`. Разметки, которую они
   оформляли, больше нет: в герое стоит снимок работающего приложения
   (снят с `/view` до того, как дверь сняли 21.08.2026 — ADR-004; см.
   комментарий в `landing.html`), поэтому правила удалены, а не
   оставлены висеть. Ни один другой документ витрины этих классов не
   использовал — проверено по `public/*.html` перед удалением. */

/* `min-width: 0` на элементах сеток — не украшение и не «на всякий случай».
   Элемент grid по умолчанию не сжимается ниже своего минимального размера, а у
   колоночного флекса (наш `.dashed`) минимум по ПОПЕРЕЧНОЙ оси считается по
   max-content строк, то есть по самой длинной фразе, набранной в одну строку.
   Замерено на 390px: список требовал 421px, колонка раздувалась до 475px и
   страница уезжала вбок на 105px. Ноль возвращает право переносить. */
.cols > *, .split > *, .steps, .step > div, .hero > * { min-width: 0; }

.cols { display: grid; gap: 16px; }
/* Было `repeat(4, 1fr)` — четыре одинаковые плитки в ряд, из которых
   четвёртая, «Журнал внутри файла», единственная называет то, чего нет ни у
   одного конкурента, и весила ровно столько же, сколько «Проекты вместо
   папок». Стало три в ряд и четвёртая на всю меру: порядок номеров 01→04
   сохранён (он — последовательность работ, см. выше), а вес наконец
   соответствует содержанию. */
.cols--4 { grid-template-columns: repeat(3, 1fr); }
.cols--4 > :nth-child(4) {
  grid-column: 1 / -1;
  background: var(--brand-wash);
  border-color: var(--brand-edge, var(--rule-soft));
}
/* Кегль заголовка широкой плитки НЕ поднят. Вес ей дают мера и подложка, а
   лишний кегль стоил бы шестнадцатого размера в наборе страницы — их и так
   пятнадцать при шести объявленных. */
.cols--4 > :nth-child(4) p { max-width: 68ch; }
/* Верхняя строка плитки разложена `space-between`, и на всю меру страницы это
   уносило марку состояния к правому краю — за метр от номера, к которому она
   относится. На широкой плитке строка прижимается влево. */
.cols--4 > :nth-child(4) .tile__top { justify-content: flex-start; gap: 14px; }
.cols--2 { grid-template-columns: repeat(2, 1fr); }
/* Форматная стена главной (21.08.2026): шесть карточек 3×2. Без своего
   правила они складывались колонкой во всю ширину — то самое «спека с
   линейкой под каждой строкой», от которого стена и уходит. */
.cols--3 { grid-template-columns: repeat(3, 1fr); }

.tile {
  background: var(--raised);
  border: 1px solid var(--rule-soft);
  border-radius: var(--radius-card);
  padding: 24px;
}
.tile--ok { border-color: var(--ok-edge); padding: 26px; }
.tile h3 { font-family: var(--display); font-weight: 800; font-size: 19px; margin: 14px 0 10px; }
.tile p { font-size: var(--t-sm); line-height: 1.6; color: var(--ink-soft); margin: 0; }
.tile__top { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 0; }
.tile__num { font-family: var(--mono); font-size: var(--t-xs); color: var(--brand); }
.tile__top .mark { font-size: 10px; letter-spacing: .08em; border-radius: 4px; padding: 2px 6px; }
.tile__num--ok { color: var(--ok); }
.tile__label { font-family: var(--mono); font-size: 11px; letter-spacing: .1em; margin: 0 0 18px; }
.tile__label--ok { color: var(--ok); }
.tile__label--wip { color: var(--warn); }
.tile__foot { font-size: var(--t-sm); line-height: 1.6; color: var(--ink-faint); margin: 20px 0 0; }

.split { display: grid; align-items: start; }
.split--steps { grid-template-columns: .9fr 1.1fr; gap: 64px; }

.steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.step {
  display: flex;
  gap: 18px;
  background: var(--raised);
  border: 1px solid var(--rule-soft);
  border-radius: 12px;
  padding: 20px 22px;
}
.step--ok { border-color: var(--ok-edge); }
.step__num { font-family: var(--mono); font-size: 13px; color: var(--brand); padding-top: 2px; }
.step__num--ok { color: var(--ok); }
.step h4 { font-family: var(--display); font-weight: 800; font-size: 17px; margin: 0 0 6px; }
/* Марка внутри заголовка шага: тот же чип, что у плиток выше, но заголовок
   набран жирным дисплейным, а марка обязана остаться служебной — поэтому
   вес сбрасывается явно. */
.step h4 .mark { margin-inline-start: 10px; font-weight: 400; vertical-align: 2px; }
.step p { font-size: var(--t-sm); line-height: 1.6; color: var(--ink-soft); margin: 0; }


/* Снимок экрана на странице. Рамка и радиус те же, что у карточек, — чтобы он
   читался как окно продукта, а не как приклеенная картинка. Тёмный снимок на
   светлой странице оставлен как есть: это и есть вид приложения, и осветлять
   его значило бы показывать то, чего человек не увидит. */
.shot {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--rule-soft);
  border-radius: var(--radius-card);
}
/* Снимок в герое встал на место карточки и берёт её тень: без неё он лежит
   в плоскости страницы и читается как иллюстрация, а не как окно. */
.shot--hero { box-shadow: var(--shadow-card); }

/* Перечень с тире. Тире рисуется маркером `::before`, а не символом в тексте:
   иначе читалка проговаривает его перед каждой строкой. */
.dashed { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
/* Ни флекс, ни сетка — обычный блок с вынесенным маркером.
   Обе раскладки пробовались и обе врут на этом содержимом: у флекс-строки
   текст становится анонимным элементом и на 390px отказывался переноситься
   (замерено: вылезал из плитки на 125px), а в сетке КАЖДЫЙ элемент-потомок
   становится ячейкой — `<code>.sor</code>` посреди фразы уезжал на свою
   строку и рвал предложение на четыре куска.
   Блок с `position: absolute` у маркера оставляет текст сплошным потоком:
   он переносится там, где положено, и `<code>` внутри остаётся строчным. */
.dashed li {
  position: relative;
  padding-inline-start: 20px;
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink-mid);
}
.dashed li::before { position: absolute; inset-inline-start: 0; top: 0; }
.dashed li::before { content: '—'; color: var(--ok); }
.dashed--wip li { color: var(--ink-soft); }
.dashed--wip li::before { color: var(--warn); }

.closer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 40px;
  background: var(--raised);
  border: 1px solid var(--rule-soft);
  border-radius: 16px;
  padding: 44px;
}
.closer .hero-cta { flex-shrink: 0; margin: 0; }
.closer .sec__lede { margin: 0; }

/* Узкие экраны: сетки схлопываются по очереди, а не все разом на одной
   ширине — четыре плитки терпят два столбца дольше, чем герой. */
@media (max-width: 1100px) {
  .cols--4, .cols--3 { grid-template-columns: repeat(2, 1fr); }
  /* Широкая плитка остаётся широкой и на двух колонках: `1 / -1` считает по
     текущему числу колонок, поэтому отдельного правила ей не нужно. */
  .split--steps { grid-template-columns: 1fr; gap: 40px; }
}
@media (max-width: 860px) {
  .hero { grid-template-columns: 1fr; gap: 40px; }
  .sec__h { font-size: 32px; }
  .closer { flex-direction: column; align-items: flex-start; padding: 32px; }
}
@media (max-width: 620px) {
  .cols--4, .cols--3, .cols--2 { grid-template-columns: 1fr; }
}
