/* Главная страница: то, что инлайновым атрибутом выразить НЕЛЬЗЯ.

   Разметка лендинга перенесена с макета дословно, вместе с её инлайновыми
   стилями — CSP сайта разрешает атрибут `style=`, но запрещает блок стилей на
   странице (`style-src 'self'; style-src-attr 'unsafe-inline'`). Значит здесь
   лежит ровно остаток: кадры анимаций, состояния :hover и :focus-visible,
   узкий экран и метрики общей шапки, подогнанные под макет. Ничего, что можно
   было бы написать атрибутом, сюда не переносится — иначе появится второе
   место, где страница решает, как ей выглядеть.

   Палитра НЕ дублируется: цвета макета совпадают с токенами `site.css`
   один в один, и разметка несёт их в атрибутах. */

/* ── кадры ──────────────────────────────────────────────────────────────── */
@keyframes lineIn {
  from { opacity: 0; clip-path: inset(0 0 110% 0); transform: translateY(14px); }
  to   { opacity: 1; clip-path: inset(-20% -20% -20% -20%); transform: none; }
}
@keyframes swapIn   { from { opacity: 0; transform: translate(-7px, 7px); } to { opacity: 1; transform: none; } }
@keyframes flashBad { 0%, 62% { color: var(--dim-2); } 70% { color: var(--pink); } 78% { color: var(--dim-2); } 86%, 100% { color: var(--pink); } }
@keyframes markPulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
@keyframes blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* ФОН — ФОНОМ, СОДЕРЖИМОЕ — СВЕРХУ. Сетка и виньетка лежат в фоне рамки и
   body, то есть под содержимым по определению; здесь остаётся поднять сам
   контент героя, чтобы ни один будущий слой не лёг поверх заголовка.
   (Частиц на холсте больше нет — их убрали как неуместные: держать правило
   под удалённый узел значит оставить в файле объяснение того, чего нет.) */
#top > div { position: relative; z-index: 1; }

/* ── мигающий курсор у `$`-промпта — терминал, а не «командная строка» ────── */
.caret {
  display: inline-block; width: 7px; height: 14px; margin: 0 8px 0 10px;
  background: var(--accent); vertical-align: -2px; animation: blink 1.1s steps(1) infinite;
}

/* ── появление при прокрутке ────────────────────────────────────────────── */
[data-reveal] {
  opacity: 0; transform: translateY(18px);
  transition: opacity .8s cubic-bezier(.2,.7,.2,1), transform .8s cubic-bezier(.2,.7,.2,1);
}
[data-reveal].is-in { opacity: 1; transform: none; }

/* БЕЗ СКРИПТОВ СТРАНИЦА ОСТАЁТСЯ ЧИТАЕМОЙ. Начальная прозрачность — это ставка
   на то, что скрипт снимет её; если скриптов нет, ставка проигрывает и половина
   страницы становится невидимой. `scripting: none` закрывает случай выключенного
   JS, а `landing.js` дополнительно показывает всё сразу, если браузер не знает
   IntersectionObserver. Две разных причины — две разных страховки. */
@media (scripting: none) {
  [data-reveal] { opacity: 1; transform: none; transition: none; }
}
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; transition: none; }
  body.v2 *, body.v2 *::before, body.v2 *::after { animation: none !important; }
}

/* ── состояния, которых у атрибута нет ──────────────────────────────────── */
.hv-text:hover      { color: var(--text); }
.hv-muted:hover     { color: var(--text-3); }
.hv-tint:hover      { background: var(--panel); }
.hv-btn:hover       { background: var(--accent-bg); }
.hv-btn-ghost:hover { color: var(--text); border-color: var(--edge); }
.hv-btn-glow:hover  { background: var(--accent-bg); }
/* У <button> свой серый фон, поэтому прозрачный задаётся здесь, а не в style="":
   инлайновый фон перебивает любой :hover выше, и кнопка не подсвечивалась. */
button.hv-btn,
button.hv-btn-glow  { background: transparent; }
.hv-row:hover       { background: var(--panel); box-shadow: inset 2px 0 0 var(--accent); }
.hv-cell:hover      { background: var(--panel); box-shadow: inset 2px 0 0 var(--accent), 1px 0 0 var(--line-3), 0 1px 0 var(--line-3); }
.fc-accent:focus    { border-color: var(--accent); }

/* Клавиатурный фокус виден ВЕЗДЕ. Инлайновые стили макета гасят рамку у кнопок
   и ссылок, и без этого правила страницу нельзя пройти с клавиатуры. */
body.v2 a:focus-visible,
body.v2 button:focus-visible,
body.v2 summary:focus-visible,
body.v2 input:focus-visible,
body.v2 select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── вкладки: видимое состояние и есть aria-состояние ─────────────────────
   ОБА состояния живут здесь, а не в атрибуте разметки. Инлайновый `style`
   сильнее любого селектора, поэтому, пока «невыбранный» вид стоял атрибутом,
   правило для выбранной вкладки не срабатывало никогда: все пять выглядели
   одинаково, и переключение было не видно вовсе. */
/* Сами правила переехали в site.css: те же вкладки провайдеров (_setup.html)
   стоят и в кабинете, куда landing.css не подключается, — там они были серыми
   системными кнопками без видимого выбора. */

/* ── вопросы ────────────────────────────────────────────────────────────── */
body.v2 summary::-webkit-details-marker { display: none; }
body.v2 .faq-mark::after { content: "+"; }
body.v2 details[open] .faq-mark::after { content: "−"; color: var(--accent); }

/* Ответ раскрывается плавно, а не рывком. `<details>` сам переключает
   `display` мгновенно — анимировать тут нечего, поэтому высоту по
   `scrollHeight` считает и меняет landing.js, а здесь только сам переход.
   Правило `[open]` — резерв на случай без JS: тогда ответ просто открывается
   целиком, без анимации, но не остаётся обрезанным нулевой высотой. */
body.v2 .faq-a {
  overflow: hidden;
  max-height: 0;
  transition: max-height .35s cubic-bezier(.2,.7,.2,1);
}
body.v2 details[open] .faq-a { max-height: none; }

/* ПОСЛЕ базового правила, а не до него. Специфичность у обоих одинаковая, и
   при равной специфичности выигрывает то, что НИЖЕ: стоя выше, это правило не
   применялось вовсе — проверено в браузере, вычисленный transition оставался
   0.35s. Мёртвым оно при этом ничего не ломало только потому, что закрытие
   ответа ждёт `transitionend`; оживив его, мы бы получили ответ, который
   нельзя закрыть. Поэтому landing.js переключает состояние сам. */
@media (prefers-reduced-motion: reduce) {
  body.v2 .faq-a { transition: none; }
}

/* ── общая шапка и подвал под метрики макета ────────────────────────────── */
/* The shared frame has no decorative grid, including on the landing page. */
body.v2 .frame      { max-width: 1600px; overflow-x: clip; }
/* `min-height`, А НЕ `height`. Высота 72 px была жёсткой, и на телефоне, где ряд
   ссылок переезжает на вторую строку, он оказывался ВНЕ коробки шапки — вылезал
   вниз и наезжал на первый блок страницы. Это правило специфичнее `header.top`
   (0,2,1 против 0,1,1), поэтому мобильное правило в site.css его не перебивало. */
body.v2 header.top  { padding: 0 36px; min-height: 72px; background: var(--header-bg);
                      backdrop-filter: blur(14px); z-index: 30; }
body.v2 .brand svg  { width: 24px; height: 24px; }
body.v2 .brand b    { font-size: 19px; }
/* Своп-анимация логотипа переехала в site.css: шапка общая для всего сайта, и
   на подстраницах (кабинет, документы) знак обязан жить так же. Здесь её быть
   не должно — две копии одного движения разъедутся. */

/* Полоса прочитанного. Узел создаёт landing.js: в разметке общей шапки его нет,
   а шапка общая для всего сайта, где полосе делать нечего.
   БЕЗ `body.v2` — потому что landing.js теперь подключается и на /detection
   (там конфигуратор), а незаstyled узел в flex-шапке не «просто невидим»: он
   становится flex-элементом и ломает шапку. */
.scroll-line {
  position: absolute; left: 0; bottom: -1px; height: 1px; width: 0;
  background: var(--accent); transition: width .12s linear;
}

/* ── конфигуратор: строки вердиктов создаёт скрипт ──────────────────────── */
body.v2 .cfg-verdict {
  display: grid; grid-template-columns: 92px minmax(0,220px) minmax(0,1fr); gap: 16px;
  align-items: baseline; padding: 14px 0; border-top: 1px solid var(--line-3);
  font-size: 14px; line-height: 1.6;
}
body.v2 .cfg-verdict b     { color: var(--text-2); }
body.v2 .cfg-verdict span:last-child { color: var(--dim); }
body.v2 .cfg-mark {
  font-family: 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: .14em;
}
body.v2 .cfg-mark.yes { color: var(--green); }
body.v2 .cfg-mark.no  { color: var(--amber); }

/* ── узкий экран ────────────────────────────────────────────────────────── */
/* Сетки макета заданы атрибутом и фиксированы в колонках, поэтому здесь
   единственное место на странице, где `!important` уместен: перебить инлайн
   иначе нечем. */
@media (max-width: 760px) {
  body.v2 .gap-row     { grid-template-columns: minmax(0,1fr) 88px 88px !important; }
  body.v2 .demo-panes  { grid-template-columns: minmax(0,1fr) !important; }
  body.v2 .demo-panes > div:first-child { border-right: 0 !important;
                                          border-bottom: 1px solid var(--line); }
  body.v2 .faq-grid    { grid-template-columns: minmax(0,1fr) !important; }
  body.v2 #signup-form { grid-template-columns: minmax(0,1fr) !important; }
  body.v2 .cfg-verdict { grid-template-columns: minmax(0,1fr); gap: 6px; }
}
@media (max-width: 700px) {
  body.v2 section     { padding-left: 20px !important; padding-right: 20px !important; }
  body.v2 header.top,
  body.v2 footer      { padding-left: 20px; padding-right: 20px; }
  body.v2 .frame      { border-left: 0; border-right: 0; }
}

/* ШАПКА НА ТЕЛЕФОНЕ. Эти строки обязаны жить ЗДЕСЬ, а не в `site.css`: правила
   шапки витрины заданы через `body.v2 header.top` (0,2,1) и специфичнее общих
   (0,1,1), поэтому из `site.css` мобильные правила шапки не доходили вовсе —
   ни высота, ни перенос строки.

   ДВЕ СТРОКИ, И ШАПКА НЕ ЛИПНЕТ. В одну строку не встают ни знак, ни ряд ссылок,
   ни три кнопки: на 390 px это 112 + 198 px без навигации. Ссылки убирать
   нельзя — до этого с телефона нечем было попасть на другую страницу. Поэтому
   ссылки переезжают на вторую строку, а `position: static` снимает липкость:
   105 px липкой шапки на 844-px экране — это восьмая часть вьюпорта, отданная
   под то, что человек уже прочитал. */
@media (max-width: 760px) {
  body.v2 header.top { height: auto; min-height: 0; padding: 8px 18px 0;
                       flex-wrap: wrap; position: static; row-gap: 6px; }
  body.v2 header.top nav { flex: 1 1 100%; width: 100%; }
  /* КНОПКИ ВИТРИНЫ — КРУПНЫЕ, И ЭТО ЛОМАЛО ШАПКУ. `hv-btn-glow`/`hv-btn-ghost`
     несут паддинг 14×24 px: втроём со знаком они не влезали в 354 px и
     переносились на СВОЮ строку — знак, кнопки и ссылки занимали три ряда и
     152 px, пятая часть экрана. С паддингом 9×11 они делят строку со знаком,
     а шапка возвращается к двум рядам. */
  /* ИНЛАЙН, А НЕ СЕЛЕКТОР. Кнопки шапки на витрине несут
     `style="padding:10px 15px;font-size:11.5px"` прямо в разметке, и ни один
     селектор этого не перебьёт — предыдущие три подхода к шапке не сработали
     именно поэтому. Три кнопки по 76/75/83 px со знаком не влезали в 354 px,
     переносились на свою строку, и шапка занимала ТРИ ряда (152 px, пятая часть
     экрана). `!important` здесь — единственный способ дотянуться до инлайна;
     расплата — эти значения придётся держать в согласии с разметкой. */
  body.v2 header.top .head-cta a,
  body.v2 header.top .head-cta button {
    padding: 8px 8px !important; font-size: 11px !important;
  }
  body.v2 header.top .head-cta { gap: 6px !important; }
  body.v2 header.top .brand b { font-size: 17px; }
}

/* ПАНЕЛЬ ДЕМО: СЛУЖЕБНАЯ СТРОКА ВЛЕЗАЕТ В ДВЕ. Заголовок «один заказ, целиком»
   и счётчик шага с кнопками делили 352 px и упирались друг в друга без зазора.
   Пусть переносятся: это подпись, а не содержание диалога. */
@media (max-width: 760px) {
  #hero-panel > div:first-child { flex-wrap: wrap; gap: 6px 14px; padding: 8px 14px; }
  #hero-panel > div:first-child > div:first-child,
  #hero-phase { font-size: 9.5px; letter-spacing: .14em; }
  .hero-ctl button { width: 34px; height: 30px; }
}

/* ── герой: узлы создаёт landing.js, поэтому их оформление живёт здесь ───── */
.hero-dialog { display: flex; flex-direction: column; gap: 12px; }

.hero-bubble {
  opacity: 0; transform: translateY(10px);
  transition: opacity .75s cubic-bezier(.2,.7,.2,1), transform .75s cubic-bezier(.2,.7,.2,1),
              border-color .75s;
  border-left: 1px solid var(--line); padding-left: 14px;
}
.hero-bubble.is-shown { opacity: 1; transform: none; }
.hero-bubble--muted.is-lit,
.hero-bubble--accent.is-lit { border-left-color: var(--accent); }
.hero-bubble--green.is-lit  { border-left-color: var(--green); }

.hero-bubble-label {
  font-family: 'JetBrains Mono', monospace; font-size: 9.5px; letter-spacing: .18em;
  margin-bottom: 5px;
}
.hero-bubble--muted  .hero-bubble-label { color: var(--dim-2); }
.hero-bubble--accent .hero-bubble-label { color: var(--accent); }
.hero-bubble--green  .hero-bubble-label { color: var(--green); }

.hero-bubble-body {
  font-family: 'JetBrains Mono', monospace; font-size: 13.5px; line-height: 1.65; color: var(--text-2);
}
.hero-prose { font-family: Inter, system-ui, sans-serif; font-size: 14.5px; line-height: 1.6; color: var(--text-2); }
.hero-prose--dim { font-size: 14px; color: var(--dim); }

/* Обе версии значения лежат в одной ячейке grid: ширина берётся по длинной,
   поэтому при подмене строка не дёргается. */
.hero-token { display: inline-grid; vertical-align: baseline; text-align: left; }
.hero-token > span {
  grid-area: 1 / 1; padding: 2px 4px; border-radius: 2px; white-space: pre-wrap;
  transition: opacity .8s cubic-bezier(.4,0,.2,1), background .8s, color .8s;
}
.hero-token-real { opacity: 1; color: var(--text-2); background: transparent; }
.hero-token-fake { opacity: 0; color: var(--accent-2); background: rgba(179,160,234,.18); }
.hero-token.is-found   .hero-token-real { color: var(--pink-2); background: rgba(226,147,180,.16); }
.hero-token.is-swapped .hero-token-real { opacity: 0; }
.hero-token.is-swapped .hero-token-fake { opacity: 1; }

.hero-record { display: grid; gap: 9px; }
.hero-record-row {
  display: grid; grid-template-columns: minmax(0,88px) minmax(0,1fr); gap: 12px;
  align-items: baseline; opacity: 0; transform: translateY(6px);
  transition: opacity .6s cubic-bezier(.2,.7,.2,1), transform .6s cubic-bezier(.2,.7,.2,1);
}
.hero-dialog.is-filed .hero-record-row { opacity: 1; transform: none; }
.hero-record-label {
  font-family: 'JetBrains Mono', monospace; font-size: 9.5px; letter-spacing: .16em;
  color: var(--dim-3); text-transform: uppercase;
}
.hero-record-value {
  font-family: 'JetBrains Mono', monospace; font-size: 13px; color: var(--green); line-height: 1.5;
}

/* ── таймлайн и сканирование панели героя ────────────────────────────────────
   Шкалу из шести сегментов и полосу сканирования строит landing.js: их нет в
   разметке макета, поэтому оформление живёт здесь, а не в шаблоне. */
/* ШАГИ НАЗАД И ВПЕРЁД. Показ идёт сам, но тот, кто хочет разглядеть кадр,
   должен мочь вернуться к нему — иначе панель остаётся телевизором. Стрелки
   маленькие и угловатые: это часть приборной панели, а не кнопки действия. */
.hero-ctl { display: flex; gap: 4px; }
.hero-ctl button {
  width: 22px; height: 22px; padding: 0; line-height: 1;
  border: 1px solid var(--line-2); background: transparent; color: var(--dim-2);
  font-family: var(--mono); font-size: 13px; cursor: pointer;
  transition: color .18s ease, border-color .18s ease, background .18s ease, transform .1s ease;
}
.hero-ctl button:hover { color: var(--text); border-color: var(--edge); background: var(--panel); }
.hero-ctl button:active { transform: translateY(1px); }
@media (prefers-reduced-motion: reduce) {
  .hero-ctl button { transition: none; }
  .hero-ctl button:active { transform: none; }
}
.hero-rail { display: flex; gap: 3px; padding: 0 18px 10px; }
.hero-rail i {
  flex: 1; height: 2px; background: var(--line-2);
  transition: background .35s ease;
}
.hero-rail i.is-on { background: var(--accent); }
.hero-rail i.is-current { background: var(--accent-2); }

@media (prefers-reduced-motion: reduce) {
  .hero-rail i { transition: none; }
}

/* ── демо: смена примера читается как затухание, а не как рывок ───────────── */
.demo-swap {
  opacity: 0; transform: translateY(6px); white-space: pre-wrap;
  transition: opacity .5s cubic-bezier(.2,.7,.2,1), transform .5s cubic-bezier(.2,.7,.2,1);
}
.demo-swap.is-in { opacity: 1; transform: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   КАРТОЧНЫЕ СЕТКИ: КОЛОНОК СТОЛЬКО, СКОЛЬКО ДЕЛИТ КАРТОЧКИ
   ═══════════════════════════════════════════════════════════════════════════

   `auto-fill` набирает столько дорожек, сколько влезает, и оставляет пустые на
   конце: на 1440px дыра была в каждой сетке страницы — 330px в тарифах, 1060px
   в метриках, 794px в конфигураторе. `auto-fit` дыр не оставляет, но схлопывает
   пустые дорожки и возвращает растянутую последнюю строку (2 карточки по 662px).
   Оба варианта сломаны по одной причине: число колонок выбиралось по ШИРИНЕ
   ОКНА, а не по числу карточек.

   Поэтому имя класса — число КАРТОЧЕК, и колонок ровно столько, сколько их
   делит. Применить класс к сетке с другим числом карточек и не заметить нельзя.

   ЛИНИИ РИСУЕТ ЗАЗОР: фон контейнера — цвет линии, `gap:1px`, у карточек свой
   фон. Тогда сетка читается таблицей, а пустых клеток не бывает по построению. */
.cards { display: grid; gap: 1px; background: var(--line-3); }
.cards--n2  { grid-template-columns: repeat(2, 1fr); }
.cards--n3  { grid-template-columns: repeat(3, 1fr); }
.cards--n4  { grid-template-columns: repeat(4, 1fr); }
.cards--n6  { grid-template-columns: repeat(3, 1fr); }
.cards--n12 { grid-template-columns: repeat(4, 1fr); }

/* ТАРИФЫ — единственная сетка с переменным числом карточек, поэтому колонок
   ровно столько, сколько тарифов: класс ставит шаблон, зная `plans|length`.
   `auto-fit` здесь не годится — дорожки, занятые в первой строке, не
   схлопываются, и пятый тариф вставал в строку один (дыра 995px, измерено).
   При шести тарифах колонок три: шесть в строку — это 215px на карточку. */
.cards--plans-1 { grid-template-columns: 1fr; }
.cards--plans-2 { grid-template-columns: repeat(2, 1fr); }
.cards--plans-3 { grid-template-columns: repeat(3, 1fr); }
.cards--plans-4 { grid-template-columns: repeat(4, 1fr); }
.cards--plans-5 { grid-template-columns: repeat(5, 1fr); }
.cards--plans-6 { grid-template-columns: repeat(3, 1fr); }
.cards--plans-many { grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); }

@media (max-width: 1100px) {
  .cards--n4, .cards--n6 { grid-template-columns: repeat(2, 1fr); }
  .cards--n12 { grid-template-columns: repeat(3, 1fr); }
  /* И здесь число колонок обязано ДЕЛИТЬ число тарифов: тройка в две колонки
     давала 2+1, пятёрка — 2+2+1, то есть ту же дыру, от которой уходили. */
  .cards--plans-2 { grid-template-columns: repeat(2, 1fr); }
  .cards--plans-3 { grid-template-columns: repeat(3, 1fr); }
  .cards--plans-4 { grid-template-columns: repeat(2, 1fr); }
  .cards--plans-5 { grid-template-columns: 1fr; }
  .cards--plans-6 { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 760px) {
  .cards--n2, .cards--n3, .cards--n4, .cards--n6, .cards--n12,
  [class*="cards--plans-"] { grid-template-columns: 1fr; }
}

/* Фон карточки задан здесь, а не инлайном: инлайновый побеждал бы :hover. */
.cards > * { min-width: 0; background: var(--card-bg); }

/* ── метрика: подпись, число, пояснение ─────────────────────────────────── */
/* ПОДПИСЬ НАД ЧИСЛОМ, А НЕ СБОКУ. Числа разной ширины — «99,7%», «18», «0», —
   и в одну строку с ними подписи вставали на разной высоте по горизонтали:
   столбик подписей получался рваным. Над числом они выровнены по левому краю
   карточки все до одной. */
.metric { display: flex; flex-direction: column; padding: 28px 26px; background: var(--card-bg); }
.metric--lead { background: var(--panel); }
.metric-label { font-family: var(--mono); font-size: 11px; letter-spacing: .14em; color: var(--dim-2); }
/* ЧИСЛО — ЭТО ДАННЫЕ, поэтому моноширинное: «99,7%» и «48» встают с подписью
   тем же ритмом, что цифры в терминале и таблицах. Пропорциональный гротеск
   здесь читался бы как заголовок, а не как показание. */
.metric-num { margin-top: 10px; font-family: var(--mono); letter-spacing: -.02em; }
/* Пояснение прижато к НИЗУ карточки: в строке из трёх карточек разной высоты
   пояснения начинались бы на разной высоте, а так стоят на одной линии. */
.metric-note { margin-top: auto; padding-top: 14px; font-size: 14.5px; line-height: 1.6; color: var(--dim); }

/* ═══════════════════════════════════════════════════════════════════════════
   ТАКТИЛЬНОСТЬ: карточка и кнопка отвечают касанию
   ═══════════════════════════════════════════════════════════════════════════

   Всё сдержанное и обратимое: лёгкий подъём карточки, нажатие «вдавливается».
   Ни одной новой переменной цвета — только transform и transition поверх тех
   же токенов. Отключается для тех, кто попросил у системы меньше движения:
   у них подъём по hover — это дрожь, а не отклик. */
/* ═══════════════════════════════════════════════════════════════════════════
   ОДИН ЯЗЫК КАРТОЧКИ НА ВСЕ СЕТКИ
   ═══════════════════════════════════════════════════════════════════════════

   Тарифы задали его первыми, и он понравился: щедрые поля, действие прижато к
   низу, при наведении карточка приподнимается. Остальные сетки жили плотнее и
   без движения. Здесь это выровнено, а к подъёму добавлен УГОЛ — акцентная
   скобка отрастает в левом верхнем углу. Форма у нас угловатая, и скобка
   говорит на том же языке, что `hv-row` (вставная акцентная линия), а не
   вводит второй, «мягкий». Конфигуратор исключён: у него своя подсветка строки,
   и скобка на каждой галочке была бы шумом.

   Всё сдержанное и обратимое, отключается для тех, кто просил меньше движения. */
.cards > *:not(.cfg-item) {
  position: relative;
  transition: transform .28s cubic-bezier(.2,.7,.2,1), background .28s ease;
}
.cards > *:not(.cfg-item):hover { transform: translateY(-3px); }
.hv-btn, .hv-btn-glow, .hv-btn-ghost { transition: background .25s ease, color .25s ease, border-color .25s ease, box-shadow .25s ease, transform .1s ease; }
.hv-btn:active, .hv-btn-glow:active, .hv-btn-ghost:active { transform: translateY(1px); }

@media (prefers-reduced-motion: reduce) {
  .cards > *:not(.cfg-item), .hv-btn, .hv-btn-glow, .hv-btn-ghost { transition: none; }
  .cards > *:not(.cfg-item):hover { transform: none; }
  .hv-btn:active, .hv-btn-glow:active, .hv-btn-ghost:active { transform: none; }
}

/* ── своп-знак: тот же мотив, что у логотипа ─────────────────────────────── */
/* Два прямоугольника внахлёст меняются местами по наведению на карточку. Это
   не украшение: карточка ровно об этом и говорит — одно значение в двух
   формах, — поэтому жест повторяет знак, а не иллюстрирует текст. */
.swap-mark rect { transition: transform .4s cubic-bezier(.2,.7,.2,1); }
.swap-card:hover .swap-mark .sm-a { transform: translate(8px, -8px); }
.swap-card:hover .swap-mark .sm-b { transform: translate(-8px, 8px); }

@media (prefers-reduced-motion: reduce) {
  .swap-mark rect { transition: none; }
  .swap-card:hover .swap-mark .sm-a,
  .swap-card:hover .swap-mark .sm-b { transform: none; }
}

/* Блок «почему маскирования мало»: две колонки, вторая — карточка свопа.
   На узком экране колонки схлопываются: инлайновая сетка иначе не перебьётся. */
@media (max-width: 760px) {
  .hero-why { grid-template-columns: minmax(0, 1fr) !important; }
}

/* ── каскадное появление карточек ────────────────────────────────────────── */
/* Базовое состояние ставит JS классом `.reveal-item`, а не селектором атрибута:
   карточки обязаны начать ВИДИМЫМИ, если скрипт не отработал. JS добавляет
   класс вместе с задержкой, поэтому в разметке нет ни одного `data-*` на
   дочерней карточке — только на контейнере сетки.

   `:not(.is-in)`, А НЕ `.is-in { transform: none }`. Вторая форма — та же
   специфичность, что у `.cards > *:hover`, и, стоя ниже в файле, она ПОБЕЖДАЛА
   наведение: подъём карточки пропадал ровно у тех карточек, что прошли каскад.
   Так пропала тактильность у метрик, демо и трио. Здесь transform объявлен
   только у НЕпроявленной карточки, поэтому после появления им снова владеет
   hover. */
.reveal-item {
  transition: opacity .7s cubic-bezier(.2,.7,.2,1), transform .7s cubic-bezier(.2,.7,.2,1);
}
.reveal-item:not(.is-in) { opacity: 0; transform: translateY(18px); }
@media (scripting: none) {
  .reveal-item:not(.is-in) { opacity: 1; transform: none; transition: none; }
}
@media (prefers-reduced-motion: reduce) {
  .reveal-item, .reveal-item:not(.is-in) { opacity: 1; transform: none; transition: none; }
}

/* ── курсор-маска ────────────────────────────────────────────────────────── */
/* Над замаскированной панелью курсор сам становится маской: скруглённый контур
   с косой чертой — «значение скрыто». Это тот же язык, что у логотипа (подмена),
   только в форме курсора. SVG data-URI, как у стрелки select — img-src его
   пускает. */
.mask-cursor { cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Crect x='2.5' y='2.5' width='19' height='19' rx='5.5' fill='rgba(179,160,234,.14)' stroke='%23b3a0ea' stroke-width='1.6'/%3E%3Cpath d='M7 17 L17 7' stroke='%23b3a0ea' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") 12 12, text; }

/* ── ряд фактов (152-ФЗ) ─────────────────────────────────────────────────────
   Три равные колонки с волосяными разделителями. Заменил растянутый флекс:
   на широком экране он разносил три коротких факта редкими островками, и
   строка читалась обрывками, а не рядом. */
.trust-row {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  margin-top: 28px; border-top: 1px solid var(--line-3);
}
.trust-row > * {
  padding: 18px 22px 0 0;
  font-family: var(--mono); font-size: 13px; letter-spacing: .04em;
  line-height: 1.7; color: var(--dim);
}
.trust-row > * + * { border-left: 1px solid var(--line-3); padding-left: 22px; }
.trust-row b { color: var(--accent); font-weight: 400; }
@media (max-width: 820px) {
  .trust-row { grid-template-columns: minmax(0, 1fr); }
  .trust-row > * { padding: 14px 0 0; }
  .trust-row > * + * { border-left: 0; padding-left: 0; border-top: 1px solid var(--line-3); }
}

/* ── база знаний ─────────────────────────────────────────────────────────────
   Раздел под поисковые запросы. Проза здесь длиннее, чем на витрине, поэтому
   держим те же пороги читаемости, что и везде: 17px, интерлиньяж 1,7, мера
   строки до 64 знаков, контраст вторичного текста не ниже 7:1. Никаких
   отдельных «блоговых» стилей — тот же язык, что у остальных страниц. */
.kb-prose h2 { margin: 46px 0 16px; font-size: clamp(21px,2.3vw,29px); font-weight: 800; letter-spacing: -.03em; color: var(--text); }
.kb-prose h2:first-child { margin-top: 0; }
.kb-prose h3 { margin: 28px 0 12px; font-size: 18px; font-weight: 700; letter-spacing: -.015em; color: var(--text); }
.kb-prose p { margin: 0 0 18px; font-size: 17px; line-height: 1.7; color: var(--text-2); max-width: 64ch; text-wrap: pretty; }
.kb-prose ul, .kb-prose ol { margin: 0 0 20px; padding-left: 22px; max-width: 64ch; }
.kb-prose li { margin: 0 0 10px; font-size: 16.5px; line-height: 1.65; color: var(--text-2); }
.kb-prose b, .kb-prose strong { color: var(--text); font-weight: 600; }
.kb-prose a { color: var(--accent-2); }
.kb-quote {
  margin: 0 0 20px; padding: 16px 20px; border-left: 2px solid var(--accent);
  background: var(--panel); font-size: 16px; line-height: 1.65; color: var(--text-2); max-width: 64ch;
}
.kb-note {
  margin: 0 0 20px; border: 1px solid var(--line-3); padding: 16px 20px;
  font-family: var(--mono); font-size: 12.5px; line-height: 1.8; color: var(--dim); max-width: 64ch;
}
.kb-aside { position: sticky; top: 92px; font-family: var(--mono); font-size: 12px; line-height: 2.1; }
.kb-aside a { color: var(--dim); }
.kb-aside a:hover { color: var(--text); }
.kb-aside-title { color: var(--dim-2); letter-spacing: .18em; margin-bottom: 10px; }
.kb-grid { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,240px); gap: clamp(28px,4vw,64px); align-items: start; }
.kb-list { display: grid; grid-template-columns: repeat(auto-fit,minmax(min(100%,320px),1fr)); gap: 1px; background: var(--line-3); border: 1px solid var(--line-3); }
.kb-list > a { display: block; background: var(--card-bg); padding: 26px 24px; text-decoration: none; transition: transform .28s cubic-bezier(.2,.7,.2,1); }
.kb-list > a:hover { transform: translateY(-3px); }
.kb-list .kb-kicker { font-family: var(--mono); font-size: 11px; letter-spacing: .18em; color: var(--accent); }
.kb-list .kb-name { margin-top: 12px; font-size: 21px; font-weight: 700; letter-spacing: -.025em; color: var(--text); }
.kb-list .kb-desc { margin-top: 10px; font-size: 14.5px; line-height: 1.6; color: var(--dim); }
@media (max-width: 900px) { .kb-grid { grid-template-columns: minmax(0,1fr); } .kb-aside { position: static; } }

/* ── кликабельность и вход в базу знаний ─────────────────────────────────────
   ПОДЪЁМ ПРИ НАВЕДЕНИИ БЫЛ У ВСЕХ ДВАДЦАТИ ОДНОГО БЛОКА, А ВЕЛИ КУДА-ТО ШЕСТЬ.
   Значит подъём говорил «нажми меня» там, где нажимать нечего, и молчал о том,
   что кликнуть можно: внутри карточки ссылкой была одна строка, а не карточка.
   Теперь кликабельное отличается тремя признаками сразу — курсор, акцентная
   кромка слева (тот же язык, что у `hv-row`) и уехавшая стрелка, — а ведёт себя
   как ссылка ВСЯ карточка: `::after` растягивает её на весь блок — ссылка в этих карточках лежит внутри текста, поэтому берём потомка, а не прямого ребёнка. Карточки без
   ссылок сохраняют подъём, но курсор над ними остаётся обычным: движение — это
   «я живая», курсор — это «я нажимаемая», и путать их нельзя.
   `:has()` без поддержки ничего не ломает: там просто не будет кромки. */
.cards > *:has(a[href]):not(:has(button)) { cursor: pointer; position: relative; }
.cards > *:has(a[href]):not(:has(button)) a[href]::after { content: ""; position: absolute; inset: 0; }
.cards > *:has(a[href]):not(:has(button)):hover {
  box-shadow: inset 2px 0 0 var(--accent);
}
.cards > *:has(a[href]) a[href$="→"], .cards > *:has(a[href]) .card-go { transition: transform .24s cubic-bezier(.2,.7,.2,1); }
.cards > *:has(a[href]):hover a[href$="→"], .cards > *:has(a[href]):hover .card-go { transform: translateX(4px); }
.kb-list > a { cursor: pointer; position: relative; }
.kb-list > a::after { content: ""; position: absolute; inset: 0; }
.kb-list > a:hover { box-shadow: inset 2px 0 0 var(--accent); }
@media (prefers-reduced-motion: reduce) {
  .cards > *:has(a[href]) a[href$="→"], .cards > *:has(a[href]) .card-go { transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   МОБИЛЬНОЕ ПОЛЕ — то, что обязано отличаться на телефоне
   ═══════════════════════════════════════════════════════════════════════════

   ОТСТУПЫ СЕКЦИЙ ЗАДАНЫ ИНЛАЙНОМ (`padding:120px 36px 0` у каждой), поэтому
   сузить их можно только `!important`: инлайновое значение сильнее любого
   селектора. Селектор привязан к САМОМУ ЗНАЧЕНИЮ, а не к тегу `section`: по
   тегу правило задело бы страницы, где отступы заданы иначе (`how`, `faq`,
   `kb`), и добавило бы им 72 px сверху, которых они не просили.

   36 px по бокам на 360-px экране оставляли под текст 288 px, а 120 px сверху —
   половину первого экрана пустоты. */
@media (max-width: 760px) {
  section[style*="padding:120px"],
  section[style*="padding:140px"] { padding: 76px 20px 0 !important; }
  #top[style] { padding: 24px 20px 0 !important; }

  /* ПАНЕЛЬ ДЕМО. Отрицательный отступ прижимал её к правому краю колонки на
     широком экране; на узком он выносит её за вьюпорт — и горизонтальная
     прокрутка появляется у ВСЕЙ страницы, а не у блока. `min-height:456px` там
     же задаёт пустоту под коротким диалогом. */
  #hero-panel { margin-right: 0 !important; min-height: 0 !important; }

  /* КНОПКИ ПЕРВОГО ЭКРАНА — ВО ВСЮ ШИРИНУ. Две кнопки в ряд на 360 px не
     помещаются: вторая обрезается или переносится серединой слова. */
  #top .hv-btn, #top .hv-btn-ghost { display: block; width: 100%; text-align: center; }
  #top .hv-btn + .hv-btn-ghost { margin-top: 10px; }

  /* ТАБЛИЦЫ-РЕШЁТКИ. `.boundary` и `.gap-table` — сетка из трёх колонок с
     минимумами 120/70/80 px плюс паддинги: на 360 px это шире экрана. Разложить
     их в одну колонку значило бы потерять, какая ячейка к какому столбцу
     относится (заголовки у строки одни), поэтому блок прокручивается сам. */
  /* Таблицы-решётки живут в БАЗОВОМ `site.css`: их видят и страницы, которые
     landing.css не грузят (/architecture), и там переполнение оставалось. */

  /* ПОЯСНЕНИЯ К ДЕМО-КАРТОЧКАМ И ВИТРИНА: двухколоночные сетки в инлайне
     схлопываются, но у карточек остаётся щедрый паддинг на весь экран. */
  #znaniya [style*="grid-template-columns"] { grid-template-columns: minmax(0, 1fr) !important; }

  /* ЦЕНЫ: щедрые поля карточки рассчитаны на колонку в 300+ px, на телефоне
     они съедают половину ширины под пустоту. */
  .cards > * { padding-left: 20px !important; padding-right: 20px !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ТЕЛЕФОН — ЭТО НЕ УМЕНЬШЕННЫЙ ДЕСКТОП
   ═══════════════════════════════════════════════════════════════════════════

   ЗАМЕРЕНО ДО: главная на 390 px — 17 571 px, то есть 20.8 экранов против 11.1
   на десктопе. Причина не в шрифтах, а в композиции: каждая сетка, которая на
   большом экране делила ширину, на телефоне вставала в одну колонку — шестнадцать
   ячеек покрытия подряд, три тарифа подряд, четыре карточки демо подряд. Это и
   есть «всё скопом»: иерархии нет, потому что всё одинаково вертикально.

   Поэтому здесь меняется СХЕМА, а не масштаб: сетки остаются сетками (в две
   колонки), дубли убираются, воздух между смысловыми блоками уменьшается
   вдвое — 120 px поля на телефоне читаются как пустой экран, а не как пауза. */
@media (max-width: 760px) {
  section[style*="padding:120px"],
  section[style*="padding:140px"] { padding: 44px 18px 0 !important; }
  #top[style] { padding: 26px 18px 0 !important; }

  /* СЕТКИ ОСТАЮТСЯ СЕТКАМИ. Одна колонка превращала покрытие в 3 012 px, а
     тарифы — в 2 843 px: горизонтальная сетка — это способ показать МНОГО
     ЗА ОДИН ВЗГЛЯД, и на телефоне он не перестаёт работать, просто колонок
     две. */
  /* ДВЕ КОЛОНКИ — ТОЛЬКО ТАМ, ГДЕ ЯЧЕЙКА ЕСТЬ СПИСОК ЧИПОВ.
     В покрытии и конфигураторе ячейка — набор коротких подписей, и две колонки
     работают: в одну колонку 16 ячеек давали 3 000 px ленты. В демо ячейка
     содержит фразу на шестьдесят знаков: в колонке 185 px она рвётся на четыре
     строки и читается ХУЖЕ, чем в полную ширину. Одинаковое число колонок для
     обоих случаев — это и есть «сделать 1:1», только сбоку. */
  #coverage .cards, #configurator .cards { grid-template-columns: repeat(2, 1fr); }

  /* МЕТРИКИ — ТОЖЕ ЧИПЫ: подпись, число и одна строка пояснения. Шесть метрик в
     одну колонку — 975 px внутри первого экрана; две колонки делят это надвое,
     а пояснение ужимается кеглем, а не переносом в четыре строки. */
  #top .cards--n6 { grid-template-columns: repeat(2, 1fr); }
  #top .metric-note { font-size: 12px !important; line-height: 1.45 !important; }
  #top .metric-num { font-size: 26px !important; }

  /* КАРТОЧКА НА ТЕЛЕФОНЕ — ЧИТАЕМАЯ, А НЕ ВОЗДУШНАЯ. Поля 22–28 px съедали
     половину ширины колонки под пустоту. */
  .cards > * { padding: 16px 14px !important; }

  /* ДУБЛЬ УХОДИТ. `.hero-why` — тезис и карточка подмены; и то и другое на
     телефоне уже сказано дважды: панель демо выше и раздел «почему это
     сложнее» ниже. На большом экране они стоят рядом и работают на контрасте,
     на телефоне — это ещё один экран текста под первым. */
  .hero-why { display: none !important; }

  /* ФОРМА ЗАЯВКИ — ОДНА КОЛОНКА. Два поля в ряд на 390 px дают поля по 170 px,
     где не видно введённого адреса. */
  #signup-form { grid-template-columns: minmax(0, 1fr); }

  /* ЗАГОЛОВКИ СЕКЦИЙ: `clamp` с минимумом 28 px на телефоне — это шесть строк
     на заголовок. Ниже — предел, на котором строка ещё читается как строка. */
  section h2 { font-size: clamp(23px, 6.4vw, 30px) !important; }

  /* ЧИПЫ В ДВЕ КОЛОНКИ НЕ ВЛЕЗАЮТ В ПОЛНОМ РАЗМЕРЕ. Колонка — 185 px, и подпись
     вроде «Номер кредитного договора» переносилась на три строки: ячейка вырастала
     до 300 px, и сетка покрытия всё равно занимала 2 317 px. Ужимаются кегль,
     поля и зазор — текст остаётся текстом, высота падает почти вдвое. */
  #coverage .cards > * { padding: 14px 12px !important; }
  #coverage .cards span { font-size: 11px !important; padding: 2px 7px !important; }
  #coverage .cards > * > div:first-child { font-size: 13px !important; margin-bottom: 10px !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ПАЛЕЦ, А НЕ КУРСОР — то, чего на телефоне не хватало вовсе
   ═══════════════════════════════════════════════════════════════════════════

   ЗАМЕРЕНО ДО: ссылки навигации 14–15 px высотой, кнопки шапки 32 px, знак
   24 px, а моно-подписи («КЛИЕНТ ПИШЕТ», «1/6 · КЛИЕНТ», «СВЕТ») — 9.5–10.5 px.
   Это размеры под курсор: палец промахивается по цели ниже ~40 px, а 10 px
   текста на телефоне не читается вовсе — человек не «плохо видит», он видит
   серую кашу и уходит.

   Пол по цели касания — 44 px (Apple HIG; Material допускает 40), по кеглю —
   11.5 px для служебных подписей. Видимый размер подписи при этом не растёт:
   у ссылок навигации увеличивается ПАДДИНГ, а не кегль, поэтому ряд выглядит
   так же плотно, но по нему можно попасть. */
@media (max-width: 760px) {
  /* ЦЕЛЬ 40 px — ПАДДИНГОМ, НЕ ВЫСОТОЙ ШАПКИ. Паддинг 13 px растянул шапку до
     160 px: пятая часть экрана до первого слова. 11 px держит ту же плотность
     ряда и оставляет шапке ~120 px. */
  header.top nav a { padding: 12px 0; }
  header.top .brand { min-height: 44px; }
  /* ВИТРИНА ЗОВЁТ СВОИ КНОПКИ ИНАЧЕ (`hv-btn-glow`, `hv-btn-ghost`), поэтому
     селектор по `.btn` их не ловил и пол по цели касания не срабатывал. Берём
     все ссылки и кнопки шапки: у остальных страниц это `.btn`, у витрины —
     свои классы, и правило обязано покрывать оба случая. */
  header.top .head-cta a,
  header.top .head-cta button {
    min-height: 40px; display: inline-flex; align-items: center; justify-content: center;
  }
  /* СТРЕЛКИ ДЕМО. 22×34 px — вдвое меньше пальца, а ими листают шесть шагов. */
  .hero-ctl button { min-width: 40px; min-height: 38px; }
  /* ССЫЛКИ-ДЕЙСТВИЯ ВНУТРИ БЛОКОВ. В абзаце ссылка обязана остаться строкой,
     поэтому пол ставится только тем, что стоит отдельно. */
  .cards a, .rows a, .trust-row a, .kb-list > a { min-height: 40px; display: inline-flex; align-items: center; }
  /* ФЛАЖКИ КОНФИГУРАТОРА: 15×15 px. Отметить группу пальцем нельзя. */
  input[type="checkbox"], input[type="radio"] { width: 22px; height: 22px; }
  label:has(input[type="checkbox"]), label:has(input[type="radio"]) { min-height: 44px; }
  /* Подвал: ссылки в столбик — тоже цели, а не подписи. */
  footer a { min-height: 40px; display: inline-flex; align-items: center; }

  /* ПОЛ ЧИТАЕМОСТИ. Селектор привязан к самому инлайновому кеглю: часть подписей
     задана в разметке атрибутом `style`, и перебить их иначе нечем. Область
     сужена до панели демо и служебных меток — правило не трогает ни один
     содержательный абзац. */
  #hero-panel [style*="font-size:9.5px"],
  #hero-panel [style*="font-size:10px"],
  #hero-panel [style*="font-size:10.5px"],
  .hero-ctl button { min-height: 34px; }
  #hero-panel [style*="font-size:9.5px"],
  #hero-panel [style*="font-size:10.5px"] { font-size: 11.5px !important; }
  .metric-label, .cfg-mark, .eyebrow span { font-size: 11.5px !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ОСТАТКИ ПОЛА: ТО, ЧТО ЗАДАНО ИНЛАЙНОМ И ПОЭТОМУ НЕ ПЕРЕБИРАЛОСЬ
   ═══════════════════════════════════════════════════════════════════════════

   Флажок конфигуратора несёт `style="width:15px;height:15px"`, а метка группы —
   `style="font-size:10px"`. Инлайновое значение сильнее селектора, поэтому
   первый заход по цели касания их не задел: галка осталась 15×15, подпись —
   10 px. Здесь `!important` не украшение, а единственный способ дотянуться. */
@media (max-width: 760px) {
  #cfg input[type="checkbox"] { width: 22px !important; height: 22px !important; }
  #cfg label.cfg-item { min-height: 52px; }
  #cfg span[style*="font-size:10px"] { font-size: 11.5px !important; }
  /* Метки в пузырях диалога рисует скрипт классом, а не инлайном. */
  .hero-bubble-label { font-size: 11.5px; }
  /* Кнопки шапки: 10.5 px латиницей в разрядку на телефоне сливаются. */
  header.top .head-cta a, header.top .head-cta button { font-size: 11.5px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ПОСЛЕДНИЕ ДВА МЕСТА, ГДЕ ПОЛ НЕ ДОСТАВАЛ
   ═══════════════════════════════════════════════════════════════════════════

   КНОПКИ ШАПКИ. Правило в `site.css` написано как
   `header.top .head-cta .btn, … .theme-toggle` — это три класса (0,3,1), а моё
   `header.top .head-cta a` — два (0,2,2). Классов больше, поэтому 10.5 px
   выигрывало. Здесь тот же селектор по классам, что и там, но этот файл
   подключается позже — и правило доходит.

   СТРЕЛКИ ДЕМО. `min-height: 38px` не срабатывал по той же причине: у кнопки
   стояла явная высота. `!important` здесь — потому что высоту задаёт правило
   для десктопа, а мельче 38 px палец по стрелке не попадает. */
@media (max-width: 760px) {
  header.top .head-cta .btn,
  header.top .head-cta .theme-toggle,
  header.top .head-cta a,
  header.top .head-cta button { font-size: 11.5px; }
  #hero-panel .hero-ctl button { min-width: 40px !important; height: 38px !important; }
  .hero-record-label { font-size: 11.5px; }
  /* Согласие на обработку — тоже цель: 36 px при рекомендованных 44. */
  #signup-form label { min-height: 44px; }
}

/* СЛУЖЕБНЫЕ НАДЗАГОЛОВКИ СЕКЦИЙ — тоже инлайном (10.5–11 px). Это не декор:
   ими подписаны блоки («ЧТО НАПИСАЛ КЛИЕНТ», «ТЕЛО ОТЧЁТА, ДОСЛОВНО»), и на
   телефоне 10 px в разрядку читаются как серая полоса. */
@media (max-width: 760px) {
  body.v2 section [style*="font-size:10.5px"],
  body.v2 section [style*="font-size:11px"] { font-size: 11.5px !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   СВЁРТКА ВТОРОСТЕПЕННОГО НА ТЕЛЕФОНЕ
   ═══════════════════════════════════════════════════════════════════════════

   Узлы `<details class="m-fold">` строит `landing.js` и только при
   `max-width: 760px`, поэтому на большом экране правила ниже не находят ничего.
   Строка свёртки — цель в 52 px (палец, а не курсор), набрана тем же моно, что и
   служебные подписи, и не выглядит кнопкой «показать ещё» из интернет-магазина:
   это оглавление, а не приманка. */
@media (max-width: 760px) {
  .m-fold > summary {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    min-height: 52px; padding: 0 16px; cursor: pointer; list-style: none;
    border: 1px solid var(--line-2); background: var(--panel);
    font-family: 'JetBrains Mono', monospace; font-size: 11.5px;
    letter-spacing: .16em; color: var(--text-2);
  }
  .m-fold > summary::-webkit-details-marker { display: none; }
  .m-fold > summary::after { content: "+"; color: var(--accent); font-size: 15px; }
  .m-fold[open] > summary::after { content: "–"; }
  .m-fold[open] > summary { margin-bottom: 20px; }
  /* Секция, у которой содержимое ушло в свёртку, больше не держит свои 44 px
     поля: строка свёртки и есть её начало. */
  .m-fold { width: 100%; }
}

/* ── страница интеграции с LiteLLM: выводы команд вместо абзацев ─────────────
   Смысл страницы — сравнение, поэтому оно нарисовано блоками и стрелками, а
   пояснений ровно по строке на блок. Классы живут здесь, а не инлайном: один и
   тот же блок встречается шесть раз, и шесть копий стиля разъедутся. */
.mono-block {
  border: 1px solid var(--line-2); background: var(--panel); padding: 14px 16px;
  font-family: 'JetBrains Mono', monospace; font-size: 12.5px; line-height: 1.75;
  color: var(--text-3); white-space: pre-wrap; overflow-wrap: anywhere;
}
.mono-block.bad  { border-color: var(--amber-bg); background: var(--warn-bg-deep); }
.mono-block.good { border-color: var(--accent); }
.mono-block b    { color: var(--amber); font-weight: 400; }
.mono-block.good b { color: var(--accent-2); }
.arm { border: 1px solid var(--line-3); background: var(--card-bg); }
.arm-us { border-color: var(--accent); }
.arm-h {
  padding: 12px 18px; border-bottom: 1px solid var(--line-3);
  font-family: 'JetBrains Mono', monospace; font-size: 11px; letter-spacing: .16em;
}
.arm-g { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: 1px; background: var(--line-3); }
.arm-g > div { background: var(--card-bg); padding: 18px; min-width: 0; }
.arm-l { font-family: 'JetBrains Mono', monospace; font-size: 9.5px; letter-spacing: .18em; color: var(--dim-3); margin-bottom: 8px; }
.arm-cap { margin-top: 10px; font-size: 13px; line-height: 1.55; color: var(--dim); }
.mono { font-family: 'JetBrains Mono', monospace; font-size: 11px; letter-spacing: .16em; }
.mono-s { font-family: 'JetBrains Mono', monospace; font-size: 12.5px; line-height: 1.6; color: var(--text-3); overflow-wrap: anywhere; }
.mono-s.good { color: var(--accent-2); }
.ds-t { margin-top: 8px; font-size: 16px; font-weight: 700; letter-spacing: -.02em; color: var(--text); }
.ds-n { margin-top: 6px; font-size: 13.5px; line-height: 1.55; color: var(--dim); }
.chain { display: grid; grid-template-columns: minmax(0,1fr) auto minmax(0,1fr) auto minmax(0,1fr); gap: 10px; align-items: stretch; }
.chain-i { border: 1px solid var(--line-3); background: var(--card-bg); padding: 16px; min-width: 0; }
.chain-i-bad  { border-color: var(--amber-bg); background: var(--warn-bg-deep); }
.chain-i-us   { border-color: var(--accent); }
.chain-i-good { border-color: var(--green); }
.chain-k { font-family: 'JetBrains Mono', monospace; font-size: 9.5px; letter-spacing: .18em; color: var(--dim-3); }
.chain-v { margin-top: 8px; font-size: 14.5px; line-height: 1.45; color: var(--text-2); overflow-wrap: anywhere; }
.chain-b { margin-top: 8px; font-size: 12.5px; line-height: 1.5; color: var(--dim); }
.chain-a { align-self: center; color: var(--accent); font-size: 18px; }
@media (max-width: 760px) {
  .chain { grid-template-columns: minmax(0, 1fr); }
  .chain-a { transform: rotate(90deg); text-align: center; }
}

/* исходы для агента: подпись, значение, результат одной строкой */
.out-k { font-family: 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: .16em; color: var(--dim-3); }
.out-k.bad { color: var(--amber); }
.out-k.good { color: var(--accent); }
.out-r { margin-top: 12px; font-size: 13.5px; line-height: 1.6; color: var(--dim); }
.out-r b { color: var(--text-2); }
.out-r.bad b { color: var(--amber); }
.out-r.good b { color: var(--accent-2); }

/* ── /litellm: два этапа, шаги по порядку ─────────────────────────────────────
   Страница читается сверху вниз: сначала «видит ли данные», потом «что бывает,
   когда увидел». Шаги пронумерованы и соединены линией, потому что порядок тут —
   смысл: выдуманный адрес появляется на шаге 3 и доезжает до клиента на шаге 5. */
.stage {
  display: inline-block; padding: 3px 9px; margin-right: 12px; vertical-align: middle;
  border: 1px solid var(--accent); color: var(--accent);
  font-family: 'JetBrains Mono', monospace; font-size: 11px; letter-spacing: .16em;
}
.vis { display: grid; gap: 1px; background: var(--line-3); border: 1px solid var(--line-3); }
.vis-r { display: grid; grid-template-columns: 190px minmax(0, 1fr) 200px; gap: 20px; padding: 20px; background: var(--card-bg); align-items: start; }
.vis-r.vis-us { background: var(--panel); box-shadow: inset 3px 0 0 var(--accent); }
.vis-k { font-family: 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: .14em; color: var(--dim-3); line-height: 1.7; }
.vis-k span { color: var(--dim-2); letter-spacing: .04em; }
.vis-v { text-align: right; }
.vis-c { grid-column: 2 / 4; font-size: 13px; line-height: 1.55; color: var(--dim); }
.badge-bad, .badge-good { display: inline-block; padding: 4px 10px; font-family: 'JetBrains Mono', monospace; font-size: 10.5px; letter-spacing: .1em; white-space: nowrap; }
.badge-bad { border: 1px solid var(--amber-bg); color: var(--amber); }
.badge-good { border: 1px solid var(--accent); color: var(--accent); }
.mono-s b.leak { color: var(--amber); font-weight: 400; }
.mono-s b.good { color: var(--accent-2); font-weight: 400; }
.flow-h { font-family: 'JetBrains Mono', monospace; font-size: 11px; letter-spacing: .18em; margin-bottom: 14px; }
.flow { display: grid; gap: 0; }
.flow-i { display: grid; grid-template-columns: 54px minmax(0, 1fr); gap: 16px; padding: 16px 18px; border: 1px solid var(--line-3); border-bottom: 0; background: var(--card-bg); }
.flow-i:last-child { border-bottom: 1px solid var(--line-3); }
.flow-i.flow-bad { background: var(--warn-bg-deep); border-color: var(--amber-bg); }
.flow-i.flow-us { box-shadow: inset 3px 0 0 var(--accent); }
.flow-n { display: grid; place-items: center; width: 34px; height: 34px; border: 1px solid var(--line-2); font-family: 'JetBrains Mono', monospace; font-size: 13px; color: var(--dim-2); }
.flow-n.bad { border-color: var(--amber-bg); color: var(--amber); }
.flow-n.us { border-color: var(--accent); color: var(--accent); }
.flow-k { font-family: 'JetBrains Mono', monospace; font-size: 9.5px; letter-spacing: .18em; color: var(--dim-3); }
.flow-k.bad { color: var(--amber); }
.flow-k.us { color: var(--accent); }
.flow-v { margin-top: 8px; font-size: 14px; line-height: 1.55; color: var(--text-2); overflow-wrap: anywhere; }
.flow-c { margin-top: 8px; font-size: 13px; line-height: 1.55; color: var(--dim); }
.flow-c b { color: var(--text-2); }
.mono-s b.bad { color: var(--amber); font-weight: 400; }
.cap { margin-top: 14px; font-size: 13px; line-height: 1.6; color: var(--dim-2); max-width: 74ch; }
@media (max-width: 860px) {
  .vis-r { grid-template-columns: minmax(0, 1fr); }
  .vis-v { text-align: left; }
  .vis-c { grid-column: 1 / 2; }
  .flow-i { grid-template-columns: 40px minmax(0, 1fr); padding: 14px; }
  .flow-n { width: 30px; height: 30px; font-size: 12px; }
}

/* чипы «что утекло / что заменено»: список читается быстрее, чем подсветка в строке */
.chips { grid-column: 2 / 4; display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.chip { padding: 3px 9px; font-family: 'JetBrains Mono', monospace; font-size: 10.5px; letter-spacing: .06em; border: 1px solid var(--line-2); color: var(--dim-2); }
.chip.leak { border-color: var(--amber-bg); background: var(--warn-bg-deep); color: var(--amber); }
.chip.ok { border-color: var(--accent); color: var(--accent-2); }
@media (max-width: 860px) { .chips { grid-column: 1 / 2; } }
