/* ============================================================
   VulnEye · landing design system
   Ported from the v3 redesign. Self-contained: no Tailwind here.
   NOTE: the redesign's `.dark` section class is renamed to
   `.night-sec` so it can never collide with Tailwind's
   class-based dark-mode variant if that ever gets enabled.
   ============================================================ */

/* ── Токены ──────────────────────────────────────── */
:root{
  --night:#0B0F1A;
  --night-2:#0E1424;
  --paper:#FAFAF9;
  --paper-2:#F3F4F6;
  --ink:#101828;
  --muted:#5D6675;
  --line:#E7E9EF;
  --d-text:#E7EAF2;
  --d-muted:#98A1B3;
  --d-line:rgba(231,234,242,.13);
  --indigo:#4F46E5;
  --indigo-h:#6058F0;
  --indigo-d:#818CF8;
  --em:#10B981;
  --em-2:#34D399;
  --sev-crit:#EF4444;
  --sev-high:#F97316;
  --sev-med:#F59E0B;
  --sans:"Onest",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  --r:12px;
}

*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  font-family:var(--sans);
  font-size:16px;line-height:1.55;
  color:var(--ink);background:var(--paper);
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
}
::selection{background:rgba(79,70,229,.18)}
img,svg{display:block;flex-shrink:0}
a{color:inherit;text-decoration:none}
button{font:inherit;border:0;background:none;cursor:pointer;color:inherit}
:focus-visible{outline:2px solid var(--indigo);outline-offset:3px;border-radius:4px}

/* Мелкая графика фиксированного размера — то же правило, что в console.css.
   Точка на 5–9px внутри flex-строки сжимается по ширине раньше текста и
   становится овалом ровно тогда, когда подписи рядом хватило места впритык;
   форма не должна зависеть от длины соседнего слова. Часть точек лендинга уже
   носила flex:none поштучно — остальные здесь. */
.vwin-dots i,.tag-ransom::before,.c-breakwrap summary::after{flex:0 0 auto}
.night-sec :focus-visible{outline-color:var(--indigo-d)}

.container{max-width:1128px;margin:0 auto;padding:0 24px}
.mono{font-family:var(--mono)}

section{padding:104px 0}
[id]{scroll-margin-top:66px}

/* заголовочная система */
.sec-label{
  font-family:var(--mono);font-size:13px;letter-spacing:.04em;
  color:var(--indigo);margin-bottom:14px;
}
.night-sec .sec-label{color:var(--indigo-d)}
h2{
  font-size:clamp(28px,3.6vw,42px);font-weight:800;
  letter-spacing:-.015em;line-height:1.12;max-width:22ch;
}
/* «Массовое сканирование сети» — 26 знаков, при общих 22ch «сети» уходило
   третьим словом на вторую строку. Запас ровно под этот заголовок: на узком
   экране ширину всё равно задаёт колонка, и перенос там остаётся нормальным. */
#problem .sec-head h2{max-width:27ch}
/* «Для тех, кто отвечает за сайты» — 30 знаков, при общих 22ch «за сайты»
   уезжало на вторую строку и обрывало обращение пополам. */
#audience .sec-head h2{max-width:31ch}
/* «Эти уязвимости уже используют хакеры» — 36 знаков, при общих 22ch на
   вторую строку уходили «используют хакеры», то есть ровно действующее лицо
   и его действие. Запас под этот заголовок; на телефоне ширину по-прежнему
   задаёт колонка, и перенос там остаётся нормальным. */
#threats .sec-head h2{max-width:37ch}
.lead{font-size:18px;color:var(--muted);max-width:62ch;margin-top:16px}
.night-sec .lead{color:var(--d-muted)}
.sec-head{margin-bottom:52px}

/* тёмные секции */
.night-sec{
  background:var(--night);color:var(--d-text);position:relative;
}
.night-sec::before{ /* миллиметровая сетка, 3–4% */
  content:"";position:absolute;inset:0;pointer-events:none;
  background-image:
    linear-gradient(rgba(231,234,242,.035) 1px,transparent 1px),
    linear-gradient(90deg,rgba(231,234,242,.035) 1px,transparent 1px);
  background-size:48px 48px;
}
.night-sec>.container{position:relative;z-index:1}

/* ── Кнопки ─────────────────────────────────────── */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  padding:14px 24px;border-radius:10px;
  font-weight:600;font-size:15.5px;line-height:1;white-space:nowrap;
  transition:background .18s ease,border-color .18s ease,transform .18s ease,box-shadow .18s ease;
}
.btn:active{transform:translateY(1px)}

/* ПОДСВЕТКА ТАПА СНЯТА ТАМ, ГДЕ ЕСТЬ СВОЯ РЕАКЦИЯ НА НАЖАТИЕ. Мобильные
   браузеры рисуют поверх элемента полупрозрачный прямоугольник, и он идёт по
   всей области ссылки, включая её поля: на кнопке с закруглением 10px это
   читается вспышкой чужого прямоугольника под пальцем. Убирать её без замены
   нельзя — нажатие обязано откликаться, — поэтому список ровно из тех
   элементов, у которых состояние :active описано своим правилом. */
.btn,.tour-nav label,.seg button,.cfg-step,.faq summary{-webkit-tap-highlight-color:transparent}
.tour-nav label:active{transform:translateY(1px)}
.btn-primary{
  background:var(--indigo);color:#fff;
  box-shadow:0 10px 28px -14px rgba(79,70,229,.7);
}
.btn-primary:hover{background:var(--indigo-h)}
/* Заливка сплошная, в тон карточкам .cve (#121620/#161A24): прозрачная кнопка
   показывала сквозь себя сетку фона секции, и линии резали надпись. */
.btn-ghost{border:1px solid var(--d-line);color:var(--d-text);background:#121620}
.btn-ghost:hover{border-color:rgba(231,234,242,.34);background:#161A24}
.btn-ghost-l{border:1px solid #D5D9E2;color:var(--ink)}
.btn-ghost-l:hover{border-color:#AEB4C2;background:#fff}
.btn-sm{padding:10px 18px;font-size:14.5px}

/* ГРАДИЕНТ ТОЛЬКО В РАМКЕ, А НЕ В ЗАЛИВКЕ. Кнопка демо стоит рядом с
   .btn-primary, и залить её градиентом целиком — значит поставить на первом
   экране две одинаково громкие кнопки: посетитель перестаёт понимать, что тут
   главное действие. Поэтому заливка остаётся тёмной и полупрозрачной (сетка
   секции сквозь неё видна, кнопка не выглядит наклейкой), а цвет уходит в
   рамку: два слоя background — padding-box кроет середину, border-box рисует
   градиент под рамкой. Отдельный класс вместо .btn-ghost намеренно: тот же
   ghost стоит в «Угрозах», и там эта подсветка не нужна.

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

   ПЕРЕЛИВ СДЕЛАН СДВИГОМ ФОНА, А ГРАДИЕНТ ЗАМКНУТ В КОЛЬЦО. Слой рамки втрое
   шире кнопки и начинается тем же индиго, которым заканчивается, поэтому при
   сдвиге ровно на период (150% — при background-size:300% один процент
   позиции стоит 2% ширины) картинка встаёт сама на себя и цикл не даёт стыка.
   Угол именно 90deg: под наклоном левый и правый край не совпали бы по
   вертикали, и на месте склейки была бы видна полоса.

   ПОДЛОЖКА МЕНЯЕТСЯ ЧЕРЕЗ ПЕРЕМЕННУЮ, А НЕ ПОВТОРОМ background В :hover.
   Короткая запись background сбрасывает background-size и -position, то есть
   на первом же наведении убила бы и ширину слоя, и перелив. --veil трогает
   только цвет вуали, вся анимация остаётся нетронутой. */
/* Без регистрации кастомное свойство для браузера просто текст, и transition
   на нём не работает — вуаль переключалась бы рывком. Браузер, который
   @property не знает, правило пропустит: останется тот же рывок, не поломка. */
@property --veil{syntax:"<color>";inherits:false;initial-value:rgba(11,15,26,.66)}
.btn-demo{
  --veil:rgba(11,15,26,.66);
  border:2px solid transparent;color:#fff;
  background:
    linear-gradient(var(--veil),var(--veil)) padding-box,
    linear-gradient(90deg,
      var(--indigo) 0%,var(--indigo-d) 18%,var(--em-2) 36%,
      var(--sev-med) 54%,var(--sev-crit) 72%,var(--indigo-d) 88%,
      var(--indigo) 100%) border-box;
  background-size:100% 100%,300% 100%;
  background-position:0 0,0 50%;
  box-shadow:0 12px 32px -16px rgba(129,140,248,.6);
  animation:btn-demo-flow 8s linear infinite;
  transition:box-shadow .18s ease,transform .18s ease,--veil .18s ease;
}
.btn-demo:hover{
  --veil:rgba(11,15,26,.4);
  box-shadow:0 16px 38px -14px rgba(239,68,68,.45);
}
/* Расстояние до стрелки — общий для кнопок gap:9px, ничего своего: прижатая
   вплотную (пробовалось 5px) она читалась как часть последнего слова.
   На наведении уходит по своей же диагонали — то самое движение, которое
   обозначает. */
.btn-demo .i-tap{transition:transform .18s ease}
.btn-demo:hover .i-tap{transform:translate(2px,-2px)}
@keyframes btn-demo-flow{
  from{background-position:0 0,0 50%}
  to{background-position:0 0,150% 50%}
}

/* Движение здесь декоративное: гасим его целиком, кнопка остаётся с обычным
   статичным градиентом в рамке. */
@media (prefers-reduced-motion:reduce){
  .btn-demo{animation:none}
  .btn-demo:hover{animation:none}
  .btn-demo .i-tap{transition:none}
  .btn-demo:hover .i-tap{transform:none}
}
.micro{
  font-family:var(--mono);font-size:12.5px;color:var(--d-muted);
  margin-top:14px;letter-spacing:.01em;
}

/* ── Хедер ──────────────────────────────────────── */
.top{
  position:sticky;top:0;z-index:50;
  background:var(--night);
  border-bottom:1px solid var(--d-line);
  transition:box-shadow .25s ease;
}
.top.scrolled{box-shadow:0 14px 34px -24px rgba(0,0,0,.9)}
.top-in{
  max-width:1128px;margin:0 auto;padding:0 24px;height:66px;
  display:flex;align-items:center;gap:36px;
}
.logo{display:flex;align-items:center;gap:10px;color:var(--d-text)}
/* top:1.2px — оптическая правка, а не произвол. align-items:center равняет
   line-box целиком, вместе с местом под выносной элемент («y» в VulnEye),
   поэтому масса букв садится выше центра кружка. Метрики Onest 800
   (ascender 970, descender 305, cap 708) дают на 19px ровно 1.22px увода;
   замер рендером подтверждает. В консоли то же самое лечит
   console.css .logo b{top:1px} — там кегль 18px. */
.logo b{font-weight:800;font-size:19px;letter-spacing:-.01em;position:relative;top:1.2px}
.logo b span{color:var(--indigo-d)}
.top .logo{position:relative;top:-2px}
.nav{display:flex;gap:28px;margin-left:8px}
.nav a{position:relative;padding:4px 0;font-size:14.5px;color:var(--d-muted);transition:color .15s}
.nav a::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:var(--indigo-d);transform:scaleX(0);transform-origin:left;
  transition:transform .22s ease;
}
.nav a:hover{color:var(--d-text)}
.nav a:hover::after{transform:scaleX(1)}
.top-cta{margin-left:auto;display:flex;align-items:center;gap:22px}
.top-cta .login{font-size:14.5px;color:var(--d-muted)}
.top-cta .login:hover{color:var(--d-text)}

/* ── Бургер и раскрывающееся меню (только ≤719, см. блок адаптива) ──
   На широком экране кнопки нет вовсе, а «Войти» внутри <nav> спрятано:
   там та же ссылка стоит справа, в .top-cta. Обе строки — про десктоп;
   всё поведение мобильного меню собрано в @media(max-width:719px). */
.burger{display:none}
.nav .nav-login{display:none}

/* ── Hero ───────────────────────────────────────── */
/* ПЕРВЫЙ ЭКРАН ЗАНИМАЕТ ЭКРАН ЦЕЛИКОМ. 100svh, а не vh: на мобильных vh
   считается по окну с убранной адресной строкой, то есть при первой отрисовке
   секция оказывается выше видимой области и низ уезжает под браузер. svh берёт
   наименьшее состояние — то, что посетитель видит сразу.
   Минус высота шапки: она sticky и лежит НАД секцией, а не поверх неё, поэтому
   без вычитания первый экран получался бы на 66px длиннее окна.
   min-height, а не height: как только контент перестаёт помещаться (узкое окно,
   низкий ноутбук), секция растёт дальше, а не режет кнопки.
   Отступы остаются нижним пределом для случая, когда экран ниже контента. */
.hero{
  padding:60px 0 96px;overflow:hidden;
  min-height:calc(100svh - 66px);
  display:grid;align-content:center;
}
/* СЕТКА ПОСЧИТАНА, А НЕ ПОДОБРАНА НА ГЛАЗ. Было `1.04fr .96fr` при gap 56:
   контейнер 1128 минус поля 48 = 1080, значит левая колонка 532.5, правая
   491.5. Правая при этом ещё и короче: кадр 580×493 в окне 491.5 даёт 416
   высоты, плюс шапка окна 52.6, рамки 2 и подпись 34.6 = 505 против 576 у
   текста. При `align-items:center` разница в 70px раскладывалась по 35 сверху
   и снизу, и окно висело в пустоте — ровно то, что читается как «скриншот
   меньше блока слева».

   Теперь обе колонки считаются от одного ограничения. 532px слева — это не
   круглое число, а пол: строка кнопок требует 278 + 14 + 232 = 524px, и на
   523 «Посмотреть кабинет» уезжает на второй ряд, добавляя левой колонке 57px
   высоты. 532 оставляет 8px запаса; уменьшать нельзя, увеличивать незачем.
   Отсюда правая: 1080 − 532 − 40 = 508.

   Высоты колонок не равны, и это принято сознательно. Кадр 580×558
   (demo/shots.py, четвёртая строка очереди) в окне 506 шириной даёт 486.8
   высоты, с шапкой окна и рамками — 541.4. Слева после выноса заголовка наверх
   остались лид, кнопки и строка micro — примерно 350.

   ОТСЮДА `align-items:start`, А НЕ `center`. Пока заголовок стоял в левой
   колонке, центрирование было верным: разница раскладывалась поровну и обе
   колонки читались как один блок. Теперь заголовок общий для обеих, и при
   `center` под ним слева открывалась дыра в четверть экрана — лид отрывался
   от собственного заголовка и повисал в воздухе напротив середины кадра.
   Верхний край важнее нижнего: h1 и первая строка лида должны идти подряд,
   а пустота уходит вниз, где её закрывает факт-строка.

   Правите кнопки или обрезку кадра — пересчитывайте здесь же: ширины держатся
   на трёх числах (524, 40, 558/580) и рассыпаются от любого из них. */
.hero-grid{
  display:grid;grid-template-columns:532px minmax(0,1fr);
  gap:40px;align-items:stretch;
}
/* НИЖНИЕ КРАЯ КОЛОНОК СОВПАДАЮТ. Правая колонка выше левой примерно на 190px
   (541.4 против 350), и при `align-items:start` строка micro заканчивалась
   заметно раньше нижней рамки окна — два параллельных блока с разной нижней
   границей читаются как незавершённая вёрстка. `stretch` тянет колонку на всю
   высоту, а излишек уходит в ОДИН зазор — перед кнопками
   (`.cta-row{margin-top:auto}`). Текст читают сразу после заголовка, поэтому
   числа и лид идут подряд сверху; кнопка — то, к чему возвращаются, приняв
   решение, и ей место у нижнего края. Строка micro едет вместе с кнопками и
   заканчивает колонку ровно там же, где правая заканчивается рамкой окна.

   Пробовались и отвергнуты: `space-between` (по девяносто пикселей между всеми
   блоками, лид с кнопками переставали читаться как одно целое) и `auto` перед
   лидом — тогда текст отрывался от заголовка и висел у нижнего края.

   ВЫРАВНИВАНИЕ НЕ ДЕРЖИТСЯ НИ НА ОДНОМ КОНКРЕТНОМ ПОСЛЕДНЕМ ЭЛЕМЕНТЕ. Раньше
   правая колонка заканчивалась подписью «первый экран кабинета», и в этом
   месте было написано, что на одной линии стоят две мелкие моноширинные
   строки. Подпись убрана — оговорка «демо-данные» переехала бейджем в шапку
   окна (см. hero.html), колонка стала на 34.6 короче, а нижние края сошлись
   по-прежнему: линию задаёт `stretch`, а не то, что оказалось последним. */
.hero-copy{display:flex;flex-direction:column}
.badge{
  display:inline-flex;align-items:center;gap:9px;
  font-family:var(--mono);font-size:12.5px;color:var(--d-muted);
  border:1px solid var(--d-line);background:rgba(255,255,255,.03);
  padding:7px 14px;border-radius:999px;
}
/* Маркер строки. Один универсальный индикатор заменён на знак по смыслу:
   кольцо со зрачком там, где сканер видит, круговая стрелка там, где речь про
   обновление базы, треугольник там, где угроза. Общая точка с расходящимися
   волнами читалась как дежурный «live»-огонёк с любого шаблонного лендинга и
   ничего не сообщала; знак, совпадающий с текстом строки, не требует
   расшифровки вообще. Сами SVG лежат по месту использования — каждый нужен
   ровно один раз, общий партиал ради этого не заводим.
   Ничего не движется: статика здесь и есть смысл правки.
   Размер в em, чтобы знак сам подстраивался под кегль контекста. */
.mark{width:.95em;height:.95em;flex:none;color:var(--indigo-d)}

/* Бейдж «vulneye наблюдает · 24/7» — единственное место, где знак не ставится:
   обозначать им нечего, текст уже всё сказал. Наблюдение показывает сама рамка —
   по ней раз в 7 секунд по часовой проходит светлая дуга. Одно медленное
   непрерывное движение вместо мигания: его видно боковым зрением, но оно не
   дёргает взгляд обратно каждую секунду.
   Проходка идёт слева направо, а не по часовой: бейдж — «пилюля» примерно
   210×34, и у conic-gradient'а на такой геометрии почти весь угол приходится
   на два скруглённых торца. Подсветка на них залипает и вдоль длинных сторон
   практически не движется — проверено раскладкой фаз, вращение читается как
   мерцание торцов. Линейная полоса идёт с постоянной скоростью по всей длине.
   Рисуется в ::after и обрезается mask'ой до кольца толщиной 1px — ровно
   поверх собственной рамки бейджа. Проход занимает 45% цикла, остальное время
   бейдж стоит спокойно: непрерывный поток полос был бы тем же шумом. */
.badge{position:relative}
.badge::after{
  content:"";position:absolute;inset:-1px;border-radius:inherit;padding:1px;
  pointer-events:none;
  background:linear-gradient(90deg,
    rgba(129,140,248,0),rgba(129,140,248,.9) 50%,rgba(129,140,248,0));
  background-repeat:no-repeat;background-size:38% 100%;
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;
  mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  mask-composite:exclude;
  animation:badge-sweep 7s linear infinite;
}
@keyframes badge-sweep{
  0%{background-position:-70% 0}
  45%,100%{background-position:170% 0}
}
/* ЗДЕСЬ БЫЛ ЛОЗУНГ В 62px С ОБВОДКОЙ ОТ РУКИ («Дыры в вашем сайте найдут.
   Лучше, если это будете вы»). Он кричал и не называл продукт: посетитель
   с первого экрана узнавал интонацию, а не то, что перед ним. Теперь h1 —
   прямое определение, и кегль ему нужен спокойный.

   ЗАГОЛОВОК СТОИТ НАД СЕТКОЙ И ЗАНИМАЕТ ВСЮ ШИРИНУ КОНТЕЙНЕРА. Раньше он жил
   в левой колонке, то есть его кегль был ограничен шириной, которую под собой
   требовала строка кнопок (532px), — первая строка страницы набиралась уже
   кадра справа.

   ВЕРХНЯЯ ГРАНИЦА КЕГЛЯ ПОДОБРАНА ЗАМЕРОМ В БРАУЗЕРЕ ПОД ОДНУ СТРОКУ, а не
   взята круглой. Контейнер даёт 1080px (1128 минус поля 24+24).
   «Круглосуточное наблюдение за безопасностью ваших сайтов» (55 знаков)
   набирается Onest 800 с letter-spacing -.022em так (замер в headless
   chromium на тех же woff2 из theme/static/fonts):

     35px — 1052   35.8px — 1065   36px — 1079.5   36.2px — две строки

   Взято 35.8px, остаток справа 15px. Формально влезает и 36px, но там запас
   полпикселя: его съест первое же различие в рендере шрифта, а сорванная
   строка отжимает кнопки ниже сгиба. Круглые 35px недобирают: 28px пустоты
   справа глаз читает как недотянутую строку — правый край кадра кабинета
   заканчивается ровно на границе контейнера, и расхождение видно.

   Кегль опущен сюда с 39px, мерянных по прежнему заголовку в 49 знаков: на
   нынешних 55 знаках 39px дают две строки с большим отрывом.

   3.12vw: потолок достигается при ширине окна 35.8 / 0.0312 ≈ 1147px, на 19px
   позже, чем перестаёт расти контейнер (1128). Эти 19px безопасны только
   потому, что на потолке строка всё ещё на 15px короче контейнера, — то есть
   держатся на том же замере. Больше брать нельзя: шрифт продолжил бы расти
   при неизменной ширине и сорвал бы строку.

   Правите текст h1 — перемеряйте обе цифры, на глаз не выйдет.

   text-wrap:balance для узких экранов, где одной строкой уже не обойтись
   (ниже ~1000px): без него перенос оставляет последнюю строку в одно слово.
   Браузер без поддержки свойства просто перенесёт как обычно.

   max-width не задан намеренно: ширину держит контейнер, и второе ограничение
   в ch только разошлось бы с ним при смене шрифта. */
.hero h1{
  font-size:clamp(28px,3.12vw,35.8px);font-weight:800;
  text-wrap:balance;
  letter-spacing:-.022em;line-height:1.14;
  margin:0 0 28px;
}
/* 56ch на десктопе ни на что не влияет: колонка 532px и так уже. Ограничение
   работает ниже 1120, где сетка складывается в одну колонку — без него лид
   растянулся бы строкой на весь контейнер, а такую длину глаз не дочитывает
   до конца. Заголовок сверху при этом остаётся во всю ширину намеренно: у
   строки в 35.8px и у текста в 18px разная предельная длина. */
/* В ДВЕ КОЛОНКИ ЛИД НАЧИНАЕТСЯ РОВНО ТАМ ЖЕ, ГДЕ КАДР. Собственного отступа
   сверху у него нет: обе колонки сетки стартуют от одной линии (margin-bottom
   у h1), и первая строка текста встаёт вровень с верхней рамкой окна справа.
   Здесь стояло 30px «чтобы лид не прилипал к заголовку» — заголовок к тому
   моменту уже вынесен над сеткой и отбит своими 28px, так что добавка только
   роняла текст ниже кадра и делала расхождение видимым.
   В одну колонку отступ возвращается: там лид идёт сразу за заголовком и
   выравнивать его не с чем (см. @media max-width:1120px). */
.hero .sub{
  font-size:18px;color:var(--d-muted);max-width:56ch;line-height:1.62;
  margin-top:0;
}
/* auto собирает сюда всю лишнюю высоту левой колонки (см. .hero-copy): текст
   остаётся у заголовка, кнопки со своей строкой micro стоят у нижнего края
   вровень с подписью кадра. padding — минимум под лидом, когда лишней высоты
   нет (низкое окно): на auto=0 кнопки иначе прилипли бы к тексту. */
.cta-row{display:flex;gap:14px;margin-top:auto;padding-top:30px;flex-wrap:wrap}
/* Кнопки первого экрана разнесены по краям колонки. Горизонтальная линия
   сетки фактов идёт во всю ширину колонки (532px), а две кнопки вместе —
   526px: линия торчала за «Посмотреть кабинет» на 6px. Подрезать сетку на
   число нельзя — сменится текст кнопки или выключится демо (кнопка одна), и
   край опять разъедется; space-between совмещает края при любой ширине кнопок,
   а одиночная кнопка остаётся слева. Ниже 1120 колонки нет (.hero-copy —
   display:contents), кнопки на всю ширину разносить незачем — сброс там. */
.hero-copy .cta-row{justify-content:space-between}

/* слабая подсветка под курсором */
.hero-spot{
  position:absolute;inset:0;pointer-events:none;
  opacity:0;transition:opacity .5s ease;
  background:radial-gradient(460px circle at var(--mx,50%) var(--my,40%),
             rgba(129,140,248,.07),transparent 65%);
}

/* факт-строка */
/* 3×2, А НЕ 2×3 И НЕ РЯД. Ряд достался от прежней раскладки, где факты шли
   под всей сеткой во всю ширину контейнера; в левой колонке (532px) четыре
   ячейки по 133px дали бы подписи в три строки каждая, и строка сложилась в
   2×2. С шестым фактом та же арифметика решает уже другой вопрос — куда
   поставить третью пару. В две колонки это третий ряд: сетка растёт со 180 до
   243px и съедает зазор перед кнопками с 80px до 17. В три колонки те же шесть
   ложатся в прежние два ряда — 193px, воздуха остаётся 67. Ячейка при этом
   151px, и это потолок на длину числа: «раз в неделю» (130px) влезает,
   «12 инструментов» (162px) уже нет.
   margin-top:24px — ровно столько, чтобы числа отделились от последней строки
   лида, и не больше. Ноль стоял, пока факты шли первыми под заголовком; теперь
   над ними абзац, и без зазора «13 000+» читается его продолжением.
   Пробовались 34, 48 и 56 — на них факт-строка отрывается от текста и встаёт
   отдельным блоком, а она подтверждает как раз то, что сказано в лиде.

   ЛИНЕЕК ЗДЕСЬ БОЛЬШЕ НЕТ, И ЭТО ИЗ-ЗА ФОНА. Секция `.night-sec` рисует под
   собой миллиметровую сетку (::before), поэтому собственная разлиновка блока
   ложилась поверх фоновой и обе читались как одна путаная решётка: глаз не
   понимал, где граница факта, а где клетка подложки. Разделяют теперь
   расстояние и разный кегль — числу хватает воздуха, чтобы стоять отдельно.
   Ровно по той же причине убрана верхняя граница всей строки: под заголовком
   она выглядела вторым подчёркиванием. */
/* align-items:start — ПО ВЕРХУ, И ЭТО СМЕНА РЕШЕНИЯ. Здесь стоял `center` с
   объяснением: подписи разной длины (у «сразу» две строки, у соседа одна), ряд
   не может быть ровным и сверху и снизу, а центр разносит расхождение в одну
   строку на половину вверх и половину вниз — ни одна граница не обещает быть
   линией, поэтому ни одна не читается сбоем.

   Посылка изменилась. В первый факт въехала строка свежести каталога
   (.fact-note, см. hero.html), и «13 000+» стал выше соседа не на половину
   строки, а на полторы. Центр начал опускать «сразу» на заметные 12px, и ряд
   читался не «разной длины подписи», а «число съехало». По верху числа встают
   в одну линию, а лишние строки уходят вниз, где их никто не сверяет.

   По низу («end») по-прежнему нельзя: короткий факт проваливается целиком.
   Не `stretch` с margin-top:auto у подписи: тогда ровными становятся обе
   линии, но между числом и его подписью открывается зазор в целую строку, и
   пара перестаёт читаться как одно целое. */
/* ТАБЛИЦА ИЗ ЛИНИЙ, А НЕ ШЕСТЬ ПАР В ВОЗДУХЕ (24.09.2026). Без линий шесть
   «число + подпись» на миллиметровке фона читались одним облаком. Из четырёх
   примеренных вариантов (плашка с заливкой, плитки, цветная черта, линия над
   фактом) владелец выбрал сетку из одних внутренних линий: без рамки, без
   заливки, без скругления. Плашка с фоном рядом с кадром кабинета читалась
   второй панелью и спорила с ним. Анимацию подписей по наведению тоже
   примерили и сняли: подпись должна читаться сразу, без поиска курсором.

   ДОТЯГИВАЕТСЯ ДО КНОПОК. .hero-copy — колонка flex, и раньше всю лишнюю
   высоту забирал `.cta-row{margin-top:auto}`: под фактами висело ~80px
   пустоты. Теперь её забирает сама сетка (flex:1), ряды делят её поровну
   (grid-auto-rows:1fr), и низ сетки встаёт ровно на padding-top кнопок. Ниже
   1180px .hero-copy становится display:contents, flex там не действует, и
   сетка просто занимает свою высоту.

   ЛИНИИ — ЛЕВЫЙ И ВЕРХНИЙ БОРДЕР ЯЧЕЙКИ СО СДВИГОМ НА −1px, внешние края
   ячеек срезает overflow:hidden контейнера, остаются только внутренние.
   Работает при любом числе ячеек: две из шести условные, и при пяти пустой
   слот остаётся просто пустым, а не залитым цветом линии, как было бы у
   варианта с gap.

   Линия .16 — чуть ярче --d-line (.13): без заливки линии таблицы лежат прямо
   на миллиметровке фона (.035) и должны от неё отличаться с первого взгляда. */
.facts{
  display:grid;grid-template-columns:repeat(3,1fr);grid-auto-rows:1fr;
  flex:1 1 auto;gap:0;margin-top:28px;overflow:hidden;
}
.fact{
  padding:16px 16px 18px;
  border-left:1px solid rgba(231,234,242,.16);border-top:1px solid rgba(231,234,242,.16);
  margin:-1px 0 0 -1px;
}
/* Первая колонка без левого поля: рамки нет, и значения первой колонки стоят
   по одной вертикали с лидом и кнопками, а не с отступом от пустоты. Ниже
   1020 колонок две, первая — каждая нечётная, правило переписано там. */
.fact:nth-child(3n+1){padding-left:0}
.fact b{
  display:block;font-family:var(--mono);font-weight:500;
  font-size:19px;color:var(--d-text);letter-spacing:-.01em;
}
/* balance — подписи разной длины: одни встают в строку, другие в две. Без него
   перенос оставляет во второй строке одно слово, и ряд выглядит сломанным, а не
   просто разновысоким. align-items у .facts не трогаем: ряды выравниваются по
   верху, и разная высота подписей соседей не двигает. */
.fact span{
  font-family:var(--mono);font-size:12px;color:var(--d-muted);
  display:block;margin-top:5px;letter-spacing:.01em;
  line-height:1.5;text-wrap:balance;
}
/* ЗДЕСЬ БЫЛО ПРАВИЛО СНОСКИ `.fact .fact-note` — строка свежести каталога,
   11px с часами, вложенная в первый факт. Она стала шестой... точнее пятой
   ячейкой сетки и набирается теперь как обычная подпись факта (.fact span),
   поэтому собственного правила у неё не осталось. Почему переехала и почему
   потеряла иконку — в комментарии над .facts в hero.html.

   Заодно ушла ловушка, которую это правило держало: селектор был из двух
   классов, потому что `.fact span` весит (0,1,1) и перебивал одиночный класс.
   Если когда-нибудь внутри .fact снова появится собственный элемент — помнить
   про это. */

/* ── Окно с кадром кабинета ──────────────────────
   Здесь ЖИЛИ .rot-a со `spin` (медленно вращавшийся круг прежнего окна) и
   `pupilPulse` — свечение зрачка «глаза на горизонте» из старого финального
   экрана. Разметки под них не осталось ни там, ни там; правило про удалённую
   разметку — такой же мусор, как разметка без правила. */
/* 582 = кадр 580 + две рамки по 1px: шире окно растягивать нечем, дальше идёт
   апскейл ассета. В сетке выше колонка и так 508, так что потолок работает
   предохранителем: сдвинут gap или поля контейнера — окно упрётся в кадр,
   а не в мыло. */
.vwin-wrap{position:relative;max-width:582px;margin-left:auto;width:100%}
.vwin-glow{
  position:absolute;inset:-9% -12%;border-radius:40px;pointer-events:none;
  background:radial-gradient(closest-side,rgba(129,140,248,.11),transparent 70%);
  filter:blur(8px);
}
.vwin{
  position:relative;margin:0;border:1px solid var(--d-line);border-radius:16px;
  background:#0D1322;overflow:hidden;
  box-shadow:0 34px 80px -34px rgba(0,0,0,.85);
}
.vwin-chrome{
  display:flex;align-items:center;gap:12px;padding:11px 20px 11px 16px;
  border-bottom:1px solid var(--d-line);background:rgba(255,255,255,.02);
}
.vwin-dots{display:flex;gap:6px}
.vwin-dots i{width:9px;height:9px;border-radius:50%;background:rgba(231,234,242,.14)}
.vwin-url{
  display:inline-flex;align-items:center;gap:7px;margin:0 auto 0 4px;
  font-family:var(--mono);font-size:12px;color:var(--d-muted);
  border:1px solid var(--d-line);border-radius:7px;padding:4.5px 14px;
  background:rgba(255,255,255,.02);
}
.vwin-url svg{width:11px;height:11px;stroke:var(--em-2)}
/* Кадр Обзора. ЗДЕСЬ БЫЛО ОКНО-СРАВНЕНИЕ: два слоя с нарисованным каркасом
   чужого сайта, четыре выдуманные находки поверх и перетаскиваемая полоса
   между ними — около ста строк на .vwin-body, .vwin-layer, .wf-*, .mk-*,
   .vwin-divider и .vwin-handle. Всё удалено вместе с разметкой и обработчиком
   в landing.js: рисунок продукта заменён самим продуктом, см. шапку
   landing/partials/hero.html.

   Рамка окна (.vwin, .vwin-chrome, точки и строка адреса) осталась — она и
   раньше была настоящей частью композиции, а не частью подделки. */
.vwin-shot picture{display:block}
.vwin-shot img{display:block;width:100%;height:auto}

/* Оговорка о содержимом кадра — на самом кадре. Здесь был `.vwin-cap`:
   «первый экран кабинета · демо-данные», 12px по центру под рамкой, третья
   подряд серая моноширинная строка первого экрана после .fact-note и .micro.
   Почему она уехала в шапку окна — в комментарии над .vwin-wrap в hero.html.

   НИ РАМКИ, НИ ФОНА. Сначала оговорка стояла в такой же обведённой «таблетке»,
   как строка адреса, и шапка окна получала два одинаковых по форме объекта —
   глаз читал второй как ещё один элемент браузера (вкладка, расширение,
   профиль), то есть как часть подделки, а не как нашу пометку о кадре. Рамка
   с фоном в интерфейсе означает управляемость; здесь управлять нечем.

   НИ СКОБОК, НИ КАКОГО-ЛИБО ДРУГОГО ЗНАКА ВОКРУГ. Пробовались `[демо-данные]`,
   курсив, капитель вразрядку. Все три решали одну задачу — отделить пометку от
   содержимого шапки — и все три делали её заметнее адреса, то есть заметнее
   того, что она подписывает. Скобки вдобавок читаются как тег уровня лога и
   тянут внимание к правому краю; курсив был бы единственным наклонным словом
   на лендинге; капитель повторяет заголовки внутри самого кадра («УРОВЕНЬ
   РИСКА») и спорит с ними. Отделяет пометку тишина: 10.5px против 12px и
   #525C70 против --d-muted — она читается последней, когда кадр уже понят.

   Правое поле шапки увеличено до 20px (`.vwin-chrome` слева оставляет 16 под
   точки). Голый текст упирается в край рамки вплотную, обведённая «таблетка»
   держала дистанцию своим padding'ом — убрав рамку, отступ надо вернуть
   руками, иначе строка выглядит прижатой.

   Высоты шапке пометка не добавляет — на ней держится расчёт правой колонки
   в .hero-grid. `flex:none` при nowrap: сжимать строку нечем, а место справа
   от адреса ей отдаёт `margin-right:auto` у .vwin-url. */
.vwin-tag{
  flex:none;white-space:nowrap;
  font-family:var(--mono);font-size:10.5px;color:#525C70;letter-spacing:.01em;
}

/* ── Проблема: «Гонка» ──────────────────────────── */
.tl-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:18px;margin-top:12px}
.tl-card{
  background:#fff;border:1px solid var(--line);border-radius:var(--r);
  padding:24px 22px 26px;position:relative;
  transition:border-color .2s,transform .2s;
}
.tl-card:hover{border-color:#C9CEDD;transform:translateY(-2px)}
.tl-day{
  font-family:var(--mono);font-size:12.5px;color:var(--muted);
  display:inline-block;border:1px solid var(--line);
  padding:3px 10px;border-radius:6px;background:var(--paper-2);
  margin-bottom:16px;
}
.tl-card:last-child .tl-day{color:#B45309;background:#FEF6E7;border-color:#F4E3C2}
.tl-card h3{font-size:17px;font-weight:800;letter-spacing:-.01em;margin-bottom:9px}
.tl-card p{font-size:14.5px;color:var(--muted)}
/* Настоящий случай под сеткой из общих мест. Не карточка и не врезка
   намеренно: пятый прямоугольник в ряду из четырёх читался бы пятым шагом
   таймлайна, а это не шаг, а сноска ко всем четырём сразу. Поэтому голый
   абзац, отбитый линией сверху, — тот же приём, что у .feed-note в ленте KEV.

   Кегль на полпункта меньше карточного (14 против 14.5) и ширина ограничена
   ~76ch: строка длинная, из дат и ссылки, и на всю ширину контейнера читалась
   бы дисклеймером мелким шрифтом. Даты моноширинными не набираем — это
   предложение, а не таблица. */
.tl-anchor{margin-top:26px;padding-top:20px;border-top:1px solid var(--line)}
/* Линия — по ширине сетки, мера строки — по абзацу внутри, и разводить их
   пришлось: пока border-top висел на самом абзаце, правило обрывалось на его
   76ch, то есть под третьей карточкой из четырёх, и читалось не отбивкой, а
   обрезанной линией. */
.tl-anchor p{font-size:14px;line-height:1.6;color:var(--muted);max-width:76ch}
.tl-anchor a{color:var(--ink);text-decoration:underline;text-underline-offset:2px;
  text-decoration-color:#C9CEDD;transition:text-decoration-color .2s}
.tl-anchor a:hover{text-decoration-color:var(--indigo-d)}

/* Здесь БЫЛ .contrast — тёмная плашка «С VulnEye порядок другой» в конце
   секции problem. Она пересказывала how_it_works и держала второй CTA там, где
   секция ещё не закончила доказывать. Разметка убрана, стили за ней. */

/* ── Как это работает ─────────────────────────────
   ДВА БЛОКА, А НЕ ЧЕТЫРЕ КАРТОЧКИ. Секция обещает заголовком «два действия
   ваших», и форма обязана обещать то же самое до чтения текста: две широкие
   полосы видно как «две», сетка из четырёх — как «список». Она же первая
   ломает ряд одинаковых сеток, идущий от hero до тарифов.

   Номер вынесен в свою колонку и вырос: в узкой карточке он был значком над
   заголовком, здесь он несёт счёт. Прежние .steps/.step/.step-n удалены — в
   разметке лендинга их больше нет. */
.grey{background:var(--paper-2)}
.steps-two{display:grid;grid-template-columns:repeat(2,1fr);gap:20px}
.step2{
  background:#fff;border:1px solid var(--line);border-radius:var(--r);
  padding:34px 34px 36px;
  display:grid;grid-template-columns:auto 1fr;gap:22px;align-items:start;
}
.step2-n{
  font-family:var(--mono);font-weight:500;font-size:30px;line-height:1;
  color:var(--indigo);letter-spacing:-.02em;
  padding-right:22px;border-right:1px solid var(--line);
}
.step2-body h3{font-size:19px;font-weight:800;margin-bottom:10px;letter-spacing:-.015em}
.step2-body p{font-size:15px;color:var(--muted)}
/* ── «Дальше без вас»: машинная половина секции ───
   Полоса, а не карточки. Карточки на этой странице дважды оказывались формой,
   в которой нечего доказывать, а здесь они ещё и соревновались бы с кадрами
   кабинета из следующей секции. Линия сверху непрерывна через все четыре
   шага — это одна цепочка событий, а не четыре независимых пункта. */
.how-flow{margin-top:52px}
.how-flow-cap{
  font-family:var(--mono);font-size:12px;color:#8A93A3;letter-spacing:.02em;
  margin-bottom:18px;
}
.flow{list-style:none;display:grid;grid-template-columns:repeat(4,1fr)}
.flow li{position:relative;padding:22px 26px 0 0}
.flow li::before{
  content:"";position:absolute;inset:0 0 auto 0;height:1px;background:#DDE1EA;
}
/* Точка сидит НА линии и обведена фоном секции: без обводки линия проходила
   сквозь неё и точка переставала читаться узлом. */
.flow li::after{
  content:"";position:absolute;left:0;top:-4px;width:9px;height:9px;
  border-radius:50%;background:var(--indigo);box-shadow:0 0 0 4px var(--paper-2);
}
.flow-t{display:block;font-size:15.5px;font-weight:800;letter-spacing:-.01em}
.flow-d{display:block;margin-top:6px;font-size:13.5px;color:var(--muted);line-height:1.5}

.how-cta{
  margin-top:44px;display:flex;align-items:center;gap:22px;flex-wrap:wrap;
}
.how-cta p{color:var(--muted);font-size:15.5px}

/* ── Тур по кабинету ──────────────────────────────
   ЗДЕСЬ БЫЛА СЕТКА .fgrid/.fcard — шесть карточек с одинаковым знаком. Она
   удалена целиком вместе с .pupil-b: см. шапку landing/partials/product_tour.html.

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

   ШИРИНА КАДРА ПОДОБРАНА ПОД СЪЁМКУ, А НЕ НАОБОРОТ. Кадры сняты в 760–1200
   CSS-пикселей (demo/shots.py) и показываются в масштабе 0.9–1.0. Это и есть
   смысл всей затеи: ужатый вдвое интерфейс превращается в текстуру «какой-то
   экран» и работает не лучше рисунка. */
/* ── Тур: одна сцена и вкладки ──────────────────────
   Четыре развёрнутых блока занимали треть страницы; теперь на экране один кадр,
   а остальные три ждут клика. Состояние держат скрытые radio — переключение
   обязано работать без JS.

   ШИРИНА КАДРА ПОДОБРАНА ПОД СЪЁМКУ, А НЕ НАОБОРОТ. Кадры сняты в 760–1200
   CSS-пикселей (demo/shots.py) и показываются в масштабе 0.9–1.0. Это и есть
   смысл всей затеи: ужатый вдвое интерфейс превращается в текстуру «какой-то
   экран» и работает не лучше рисунка. Поэтому кадр идёт во всю ширину сцены,
   а узкие кадры не растягиваются, а центрируются. */
/* ПРЫЖОК ПРИ СМЕНЕ ВКЛАДКИ — ЭТО SCROLL ANCHORING, А НЕ НЕДОБРАННЫЙ РЕЗЕРВ
   ВЫСОТЫ. Панели разной высоты, и браузер, заметив изменение, честно
   удерживает на месте ЯКОРЬ — элемент, который он выбрал сам среди видимых,
   а это обычно кадр или то, что под ним. Чтобы якорь не сдвинулся, уезжает
   вся страница: вкладка, по которой только что кликнули, уходит из-под
   курсора. Измерено на живой странице: 131 px на телефоне, 28 px на десктопе,
   и по одному такому скачку почти на каждое переключение.

   Резерв высоты (min-height ниже) это не лечит. Он уменьшает разницу между
   панелями, но компенсацию вызывает любая ненулевая разница, а свести её к
   нулю можно только заморозив сцену по самому высокому кадру — то есть вернув
   дыру в четыреста пикселей под коротким.

   Правило перевёрнуто в нужную сторону: при смене вкладки неподвижным обязано
   остаться то, что ВЫШЕ панели (навигация, на которую смотрит человек), а не
   то, что ниже. Поэтому в этой секции якоря нет вовсе. Область правила узкая:
   на остальной странице anchoring полезен и остаётся включённым. */
#features,#features *{overflow-anchor:none}

.tour-tabs{position:relative}
.tour-radio{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}

/* Навигация — заголовками утверждений, а не номерами: вкладка «Шесть строк
   вместо ста» работает, даже если по ней не кликнут. */
.tour-nav{
  display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;
  margin-bottom:22px;
}
.tour-nav label{
  display:block;cursor:pointer;background:#F2F3F7;border:1px solid transparent;
  border-radius:14px;padding:14px 16px;
  font-size:14.5px;font-weight:700;line-height:1.3;letter-spacing:-.01em;
  color:#5B6474;transition:background .15s,color .15s,border-color .15s;
}
.tour-nav label:hover{background:#EAECF2;color:var(--ink)}
.tour-n{
  display:block;font-family:var(--mono);font-size:11px;color:#9AA1B1;
  letter-spacing:.14em;margin-bottom:7px;font-weight:400;
}

/* Сцена. min-height считан по самому высокому кадру: без него переключение
   на короткий кадр подбрасывает страницу вверх и уносит из-под курсора ту
   вкладку, по которой только что кликнули. */
/* ВЫСОТА СЦЕНЫ ЗАРЕЗЕРВИРОВАНА, И ЭТО НЕ КОСМЕТИКА. Кадры сняты в разных
   пропорциях: самый высокий (triage, 1200×760) даёт 0.633 своей ширины, самый
   низкий (history, 760×352) — вдвое меньше. Без резерва переключение на
   короткий кадр подбрасывало страницу на три сотни пикселей и уносило
   из-под курсора ту самую вкладку, по которой только что кликнули.

   Коэффициент взят ПО СЕРЕДИНЕ ДИАПАЗОНА, а не по самому высокому кадру.
   С максимумом (.633) сцена держала высоту triage всегда, и под коротким
   history зияла пустота в целый скриншот. Теперь высокие кадры чуть раздвигают
   сцену сами, короткие оставляют небольшой запас: сдвиг падает с трёхсот
   пикселей примерно до ста тридцати, а дыра — с четырёхсот до ста двадцати.
   Ширина считается от фактической: контейнер 1128 минус его поля 48 минус
   наши 76. На телефоне резерв снят — там кадры мобильные, вытянутые по
   вертикали, и общей мерки у них нет. */
/* СЦЕНА — КОЛОНКА-ФЛЕКС, А ПАНЕЛЬ ТЯНЕТСЯ НА ВСЮ ЕЁ ВЫСОТУ. Без этого
   зарезервированная min-height оставалась пустотой ПОД панелью: панель
   считала высоту по содержимому, и margin:auto на кадре нечего было делить.
   Короткий кадр (history, 760×352) висел вверху, а весь запас сцены копился
   одной дырой снизу. Теперь остаток попадает внутрь панели и делится поровну
   над кадром и под ним. */
.tour-panels{
  background:#F2F3F7;border-radius:22px;padding:34px 38px 32px;
  min-height:calc(.47 * min(1004px, 100vw - 124px) + 265px);
  display:flex;flex-direction:column;
}
.tour-panel{display:none;flex:1 1 auto;flex-direction:column;row-gap:16px}
.tour-panel h3{font-size:23px;font-weight:800;letter-spacing:-.022em;line-height:1.22}
.tour-panel>p{font-size:15.5px;color:var(--muted);max-width:78ch}

#tt1:checked ~ .tour-panels .tour-panel:nth-child(1),
#tt2:checked ~ .tour-panels .tour-panel:nth-child(2),
#tt3:checked ~ .tour-panels .tour-panel:nth-child(3),
#tt4:checked ~ .tour-panels .tour-panel:nth-child(4){display:flex}

#tt1:checked ~ .tour-nav label[for="tt1"],
#tt2:checked ~ .tour-nav label[for="tt2"],
#tt3:checked ~ .tour-nav label[for="tt3"],
#tt4:checked ~ .tour-nav label[for="tt4"]{
  background:#fff;color:var(--ink);border-color:#E3E6EE;
  box-shadow:0 1px 2px rgba(16,24,40,.05),0 10px 24px -18px rgba(16,24,40,.5);
}
/* Клавиатура: фокус живёт на скрытом input, показать его надо на подписи. */
#tt1:focus-visible ~ .tour-nav label[for="tt1"],
#tt2:focus-visible ~ .tour-nav label[for="tt2"],
#tt3:focus-visible ~ .tour-nav label[for="tt3"],
#tt4:focus-visible ~ .tour-nav label[for="tt4"]{outline:2px solid var(--indigo);outline-offset:2px}

/* Рамка — ПО ШИРИНЕ КАДРА, а не сцены: узкие кадры (760 px) оставляли справа
   пустое белое поле в четверть ширины, потому что фигура тянулась на всю сцену,
   а картинка внутри шла в натуральную величину.

   margin:auto по вертикали — центрирование в зарезервированной высоте: остаток
   делится поровну сверху и снизу, вместо того чтобы копиться одной дырой под
   коротким кадром. Работает это только вместе с растяжкой панели на всю сцену
   (см. .tour-panels выше): свободной высоты у панели по содержимому нет, и
   делить auto-полям было бы нечего. Минимальный отступ от текста держит
   row-gap панели. */
.tour-shot{
  position:relative;margin:auto;width:fit-content;background:#fff;
  border:1px solid #E3E6EE;border-radius:14px;
  /* Тень мягкая и почти без цвета: кадр и так самый контрастный объект блока,
     а заметная тень превращает его в наклейку. */
  box-shadow:0 1px 2px rgba(16,24,40,.05),0 18px 40px -24px rgba(16,24,40,.4);
  overflow:hidden;max-width:100%;
}
.tour-shot picture{display:block}
/* width:auto, а не 100%: кадры сняты в 760–1200 px, и растянутый до ширины
   сцены 760-пиксельный экран мылится — ровно то, против чего вся секция. */
.tour-shot img{max-width:100%;width:auto;height:auto}
/* Подпись живёт ВНУТРИ рамки, на своей полке. Под рамкой она отрывалась от
   кадра и читалась как начало следующего блока. */
.tour-shot figcaption{
  font-size:13.5px;color:var(--muted);line-height:1.5;
  padding:13px 18px;border-top:1px solid #EDEFF4;background:#FBFCFD;
}

/* Кадры, обрезанные по высоте: страница за нижним краем продолжается, и резкий
   срез читается как обрыв файла. Растворяем последние 60px в белом — тот же
   приём, что и в самом интерфейсе, где длинные списки уходят под фильтр. */
.tour-shot-cut img{
  -webkit-mask-image:linear-gradient(#000 calc(100% - 60px),transparent);
  mask-image:linear-gradient(#000 calc(100% - 60px),transparent);
}

/* Остаток — перечнем. Ни рамок, ни значков: это факты, которые нечем показать,
   и плитка вокруг них вернула бы ровно ту форму, из-за которой секцию
   переделывали. */
.tour-more{
  margin-top:52px;padding-top:26px;border-top:1px solid var(--line);
}
.tour-more-cap{
  font-family:var(--mono);font-size:12px;color:#8A93A3;letter-spacing:.02em;
  margin-bottom:14px;
}
.tour-more ul{list-style:none;display:grid;grid-template-columns:1fr 1fr;gap:14px 40px}
.tour-more li{font-size:14.5px;color:var(--muted);line-height:1.55}
.tour-more li b{color:var(--ink);font-weight:700}

/* ── Живые угрозы ───────────────────────────────── */
.badge-red{
  display:inline-flex;align-items:center;gap:9px;
  font-family:var(--mono);font-size:12.5px;color:#FCA5A5;
  border:1px solid rgba(239,68,68,.3);background:rgba(239,68,68,.08);
  padding:7px 14px;border-radius:999px;margin-bottom:20px;
}
.badge-red .mark{color:var(--sev-crit)}
.cve-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:48px}
/* Заливка сплошная, а не rgba поверх --night: сквозь полупрозрачную карточку
   просвечивала сетка фона секции и резала текст линиями. Цвета — те же 2,8% и
   4,5% белого, посчитанные поверх --night заранее, так что тон не сдвинулся. */
.cve{
  display:flex;flex-direction:column;
  background:#121620;border:1px solid var(--d-line);
  border-radius:var(--r);padding:20px 20px 18px;
  transition:border-color .2s,background .2s;
}
.cve:hover{border-color:rgba(231,234,242,.26);background:#161A24}
.cve-top{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:13px}
.cve-id{font-family:var(--mono);font-size:13px;color:var(--d-muted)}
.sev{
  font-family:var(--mono);font-size:11px;letter-spacing:.03em;
  padding:3px 9px;border-radius:6px;border:1px solid;
}
.sev.crit{color:#FCA5A5;border-color:rgba(239,68,68,.32);background:rgba(239,68,68,.10)}
.sev.high{color:#FDBA74;border-color:rgba(249,115,22,.32);background:rgba(249,115,22,.10)}
.sev.med{color:#FCD34D;border-color:rgba(245,158,11,.32);background:rgba(245,158,11,.10)}
.sev.low{color:var(--d-muted);border-color:var(--d-line);background:rgba(255,255,255,.04)}
.cve h3{font-size:15.5px;font-weight:600;letter-spacing:-.005em;color:var(--d-text)}
.cve .d{font-size:13.5px;color:var(--d-muted);margin:7px 0 16px;min-height:42px}
/* Подвал прижат к низу карточки: описания разной длины, и без auto-отступа
   разделительная линия вставала на своей высоте в каждой из шести карточек. */
.cve-foot{
  display:flex;align-items:center;justify-content:space-between;
  margin-top:auto;padding-top:13px;border-top:1px solid var(--d-line);
  font-family:var(--mono);font-size:11.5px;
}
.cve-foot time{color:#6C7688}
/* Здесь был .tag-live («проверка активна») — одинаковый на всех шести
   карточках, то есть не различавший их ничем. Вместо него признак, который у
   записей РАЗНЫЙ и берётся из каталога: KEV помечает уязвимости, замеченные в
   работе шифровальщиков (KnownVulnerability.known_ransomware). */
.tag-ransom{
  color:#FCA5A5;display:flex;align-items:center;gap:6px;
  font-size:11.5px;letter-spacing:.01em;
}
.tag-ransom::before{content:"";width:5px;height:5px;border-radius:50%;background:#EF4444}
.feed-num{font-weight:500;color:var(--em-2)}
.feed-note{
  margin-top:26px;font-family:var(--mono);font-size:12.5px;color:#6C7688;
  display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;
}
/* Ссылка на первоисточник. Глобальное a{color:inherit;text-decoration:none}
   делает её неотличимой от подписи, поэтому подчёркивание возвращается точечно.
   Селектор через span — чтобы не задеть кнопку .btn-ghost, лежащую в том же
   флексе вторым элементом. */
.feed-note span a{text-decoration:underline;text-underline-offset:3px}
.feed-note span a:hover{color:var(--d-text)}
.feed-empty{
  margin-top:48px;text-align:center;color:var(--d-muted);font-size:14px;
  border:1px dashed var(--d-line);border-radius:var(--r);padding:40px 20px;
}

/* Здесь БЫЛА секция «Четыре привычных способа» (.cmp-grid/.cmp). Удалена
   целиком: половина её карточек повторяла problem и FAQ, а вторая половина
   переехала в .honest — см. landing/partials/audience.html. */

/* ── Кому подходит / кому нет ───────────────────── */
.aud-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:18px}
.aud{
  background:#fff;border:1px solid var(--line);border-radius:var(--r);
  padding:24px 24px 26px;
}
/* Верхнего отступа больше нет: он держал место под значок, который снят
   (см. landing/partials/audience.html). */
.aud h3{font-size:16.5px;font-weight:800;letter-spacing:-.01em;margin:0 0 8px}
.aud p{font-size:14.5px;color:var(--muted)}
.honest{
  margin-top:26px;background:#fff;border:1px solid var(--line);
  border-left:3px solid var(--ink);border-radius:var(--r);
  padding:28px 30px;
}
.honest h3{font-size:17.5px;font-weight:800;margin-bottom:18px;letter-spacing:-.01em}
/* Две колонки: «мы не заменяем» и «и не подойдём». Это разные вопросы — что
   мы за инструмент и кому он не нужен, — и одним списком они читались как
   один перечень отказов, где вторая половина отменяет первую. */
.honest-cols{display:grid;grid-template-columns:1fr 1fr;gap:30px}
.honest-cap{
  font-family:var(--mono);font-size:12px;color:#8A93A3;letter-spacing:.02em;
  padding-bottom:9px;margin-bottom:5px;border-bottom:1px solid var(--line);
}
.honest ul{list-style:none}
.honest li{
  font-size:14.5px;color:var(--muted);padding:8px 0 8px 24px;position:relative;
}
.honest li b{color:var(--ink);font-weight:700}
.honest li::before{
  content:"—";position:absolute;left:0;top:8px;color:#B3B9C6;font-family:var(--mono);
}

/* ── Тарифы ─────────────────────────────────────────
   Два тарифа, не четыре. Карточки НЕ равной ширины: бесплатному хватает
   узкой колонки с фиксированным списком, а у Pro цены нет вообще (990 ₽ —
   только нижняя точка), поэтому он несёт внутри себя конфигуратор и занимает
   всё остальное место. Отдельным блоком под карточками конфигуратор читался
   как третий продукт.

   АКЦЕНТ (главное изменение этой версии). На секцию претендовали три объекта
   сразу: «0 ₽» бесплатного (34 px, и он левее — значит читается первым), два
   ползунка (единственное цветное и единственное движущееся пятно на экране)
   и «990 ₽» (38 px). Ни один не выигрывал, поэтому взгляд метался. Сделано:

     • ползунков нет вообще — управление только степперами (см. pricing_calc.js);
     • цена Pro — самый крупный кегль в секции, крупнее любого заголовка;
     • цена бесплатного набрана строкой текста: это не второй товар на
       витрине, а способ попробовать без карты;
     • всё, что дублировало числа из полей ввода, удалено.

   Порядок чтения внутри Pro задан одной осью: «сколько целей» → «столько
   стоит» → «оформить». Всё, что не одна из этих трёх остановок, из карточки
   вынесено вниз или убрано. */

/* align-items:stretch — обе карточки одной высоты. Это не косметика: только
   так у панели Pro появляется гарантированный запас под раскрытый расчёт.
   Кнопка прижата к низу (margin-top:auto), поэтому «из чего складывается»
   разворачивается в уже занятое место и карточка не растёт под курсором.
   Свободное место распределяют списки возможностей (`.feats{flex:1}`) —
   растянут именно он, а не разрыв перед кнопкой. */
/* 315 px, а не 300. Ширина выбрана по РИТМУ списка, а не по числу строк в нём.

   На 300 первый пункт уходил в три строки против двух у остальных, и столбик
   читался сбитым. На 315 все пять пунктов ровно по две строки — одинаковые
   блоки, глаз идёт по ним без спотыканий. Расширять дальше выгодно только
   арифметически: на 350 список короче (8 строк против 10, карточки 504 px
   против 545), но ритм становится рваным — 2, 2, 1, 2, 1, — и той же ширины
   лишается Pro, где на 350 рвётся надвое «разбор находки нейросетью по
   кнопке». На 315 все плюсы Pro целые, кроме самого длинного.

   Потолок, если ширину когда-нибудь снова захотят двинуть: 360. Дальше выигрыш
   кончается совсем (следующий по длине пункт не влезает и в 400), а подписи
   полей Pro уходят в три строки и карточка становится ВЫШЕ исходной.

   clamp, а не фикс: двухколоночный режим живёт с 970 px, где контейнер всего
   922 px. Фиксированные 315 забрали бы их у конфигуратора, которому ширина
   нужна, — процент сам возвращает бесплатному его прежние 300 px. */
.plans-two{
  display:grid;grid-template-columns:clamp(300px,29.2%,315px) minmax(0,1fr);
  gap:20px;align-items:stretch;
}
.plan{
  border:1px solid var(--line);border-radius:16px;background:#fff;
  padding:28px 26px;display:flex;flex-direction:column;position:relative;
}
.plan-free{background:#FCFCFD}
.plan-pro{
  border-color:rgba(79,70,229,.34);
  background:linear-gradient(178deg,#fff 0%,#FAFAFE 100%);
  box-shadow:0 22px 60px -34px rgba(79,70,229,.6);
}
.badge-pro{
  position:absolute;top:-11px;left:26px;
  font-family:var(--mono);font-size:11px;letter-spacing:.04em;
  background:var(--indigo);color:#fff;padding:4px 11px;border-radius:999px;
}
/* Имя тарифа стоит без подзаголовка: класс .pcard-tag удалён вместе с
   абзацем, который под ним жил (см. комментарий в pricing.html). */
.p-name{font-weight:800;font-size:19px;letter-spacing:-.015em}

/* Цена бесплатного — СТРОКОЙ, а не крупным числом. В прежней вёрстке она шла
   34-м кеглем в моно, то есть почти вровень с ценой Pro, и при этом стояла
   левее — глаз садился на «0 ₽» раньше, чем находил платную цену. */
.p-price{margin:16px 0 0;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.p-price b{font-family:var(--mono);font-weight:500;font-size:22px;letter-spacing:-.02em}
.p-price span{font-size:13px;color:var(--muted)}

/* Квота бесплатного — отдельной плашкой, а не первой строкой списка:
   это то единственное, чем он отличается, и сравнивают именно её. */
.quota{
  margin-top:16px;padding:12px 14px;border-radius:10px;background:var(--paper-2);
  display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;
  font-size:14px;color:var(--muted);
}
.quota b{font-family:var(--mono);font-weight:500;font-size:14.5px;color:var(--ink)}

/* flex:1 — список забирает весь свободный ход карточки, когда та растянута
   до высоты соседней. Пустота копится здесь, между пунктами и кнопкой, а не
   разрывом посреди карточки. */
.feats{list-style:none;margin:18px 0 22px;flex:1}
/* Отбивка 6, и увеличивать её не надо. Соблазн был: этот список задаёт
   высоту обеих карточек (бесплатная выше Pro и растягивает соседку), и
   каждые 5 px здесь превращались в 50 px запаса в панели с ценой, куда
   разворачивается расчёт. Пробовали — разреженный список читается уже не
   перечнем, а лестницей, и видно это сразу на обеих карточках. Запас панели
   решён иначе и списка не касается, см. .c-breakwrap. */
.feats li{
  font-size:14px;line-height:1.45;color:var(--muted);
  padding:6px 0 6px 27px;position:relative;
}
.feats li::before{
  content:"";position:absolute;left:1px;top:8px;
  width:16px;height:16px;border-radius:50%;background:rgba(79,70,229,.1);
}
.feats li::after{
  content:"";position:absolute;left:5.5px;top:12px;
  width:6px;height:3px;transform:rotate(-45deg);
  border-left:1.7px solid var(--indigo);border-bottom:1.7px solid var(--indigo);
}
.plan .btn{width:100%}

/* ── Шапка Pro: имя слева, период справа ─────────── */
/* align-items:center, а не flex-start: в шапке осталось одно имя тарифа в
   одну строку против переключателя высотой 44 px, и по верхнему краю оно
   висело бы напротив пустоты. Прежний flex-start держал абзац-подзаголовок,
   которого больше нет. По той же причине basis auto вместо 300 px — тот
   резервировал ширину под две строки текста. */
.pcard-head{
  display:flex;align-items:center;justify-content:space-between;
  gap:24px;flex-wrap:wrap;
}
.pcard-headline{flex:1 1 auto;min-width:0}
.seg{
  display:inline-flex;border:1px solid var(--line);border-radius:10px;
  padding:4px;background:var(--paper-2);gap:4px;flex:none;
}
.seg button{
  padding:8px 16px;border-radius:7px;font-size:13.5px;font-weight:600;
  color:var(--muted);white-space:nowrap;transition:background .15s,color .15s;
}
.seg button:hover{color:var(--ink)}
.seg button.on{background:var(--indigo);color:#fff}
.seg-save{margin-left:6px;font-weight:700;color:var(--indigo)}
/* На активной (тёмной) кнопке акцентный индиго не читается. */
.seg button.on .seg-save{color:currentColor;opacity:.85}

/* ── Конфигуратор ──────────────────────────────────
   Левая колонка узкая намеренно: без ползунков ей нужно ровно два поля,
   и лишняя ширина здесь работала бы против правой панели с ценой. */
/* Раскладка областями, а не порядком в разметке. Панель с ценой занимает обе
   строки правой колонки, а под полями встаёт список плюсов — иначе левая
   колонка держит два компактных поля (~130 px) против ~270 px панели, и
   разницу нечем закрыть: пустота там структурная, а не косметическая.

   Areas выбраны ради узкого экрана. В столбик порядок «поля → плюсы → цена»
   уводил бы цену за экран текста; с областями тот же DOM перестраивается в
   «поля → цена → плюсы» одной строкой в медиазапросе. */
.cfg{
  margin-top:24px;flex:1;
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,326px);
  grid-template-areas:
    "fields total"
    "feats  total";
  grid-template-rows:auto 1fr;
  gap:22px;align-items:stretch;
}
.cfg-fields{grid-area:fields;display:grid;gap:20px;align-content:start}
.cfg-total{grid-area:total}
.pcard-feats{grid-area:feats}

/* Подпись слева, степпер справа, в одну строку. Раньше между ними стоял
   ползунок во всю ширину, и подпись отрывалась от своего же поля.

   БЕЗ flex-wrap. С ним браузер, которому не хватило пары пикселей, переносил
   степпер под подпись целиком, вместо того чтобы дать подписи сжаться:
   при wrap перенос считается по max-content, а не по min-content. Сжатие
   разрешено явно (flex:1 1 auto + min-width:0), перенос запрещён — в столбик
   поля уходят только на узком экране, отдельным правилом в медиазапросе. */
.cfg-field{
  display:flex;align-items:center;justify-content:space-between;
  gap:16px;min-width:0;
}
.cfg-label{
  flex:1 1 auto;min-width:0;
  font-size:14px;font-weight:600;color:var(--ink);line-height:1.35;
}
.cfg-label small{
  display:block;margin-top:3px;
  font-size:12.5px;font-weight:400;color:var(--muted);
}
/* Моно только там, где в подписи стоит число: в наборном тексте
   («сайты, которые вы заявляете сами») моноширинный читается как код. */
.cfg-included{font-family:var(--mono);font-size:12px}

/* Единственный орган управления. Ползунком нельзя ни попасть точно в нужное
   число, ни увидеть, какие значения бывают, — а человек, у которого ровно
   17 доменов, приходит сюда именно с этим числом. */
.cfg-num{
  flex:none;display:inline-flex;align-items:stretch;
  border:1px solid var(--line);border-radius:10px;background:#fff;overflow:hidden;
  transition:border-color .15s,box-shadow .15s;
}
.cfg-num:focus-within{
  border-color:var(--indigo);box-shadow:0 0 0 3px rgba(79,70,229,.13);
}
.cfg-step{
  width:34px;font-size:17px;line-height:1;color:var(--muted);
  display:flex;align-items:center;justify-content:center;
  transition:background .15s,color .15s;
}
.cfg-step:hover:not(:disabled){background:var(--paper-2);color:var(--ink)}
.cfg-step:disabled{opacity:.3;cursor:default}
.cfg-input{
  width:56px;height:42px;border:0;
  border-left:1px solid var(--line);border-right:1px solid var(--line);
  background:#fff;text-align:center;color:var(--ink);
  font-family:var(--mono);font-size:16px;
  -moz-appearance:textfield;appearance:textfield;
}
.cfg-input::-webkit-outer-spin-button,
.cfg-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.cfg-input:focus{outline:none}

/* В покое пусто — только ошибка расчёта. Раньше здесь стояла сводка
   «Под наблюдением: 3 домена и 15 поддоменов», то есть пятый по счёту
   повтор той же пары чисел. */
.cfg-hint{font-size:13px;line-height:1.5;color:var(--sev-crit)}
.cfg-hint:empty{display:none}

/* ── Итог: точка, в которую должен падать взгляд ─── */
.cfg-total{
  border:1px solid rgba(79,70,229,.22);border-radius:14px;background:#fff;
  box-shadow:0 10px 30px -22px rgba(16,24,40,.5);
  padding:22px;display:flex;flex-direction:column;
}
.c-cap{
  font-family:var(--mono);font-size:11px;letter-spacing:.05em;
  text-transform:uppercase;color:var(--muted);
}
.c-price{margin-top:6px;display:flex;align-items:baseline;gap:7px}
.c-price b{
  font-family:var(--mono);font-weight:500;font-size:46px;
  letter-spacing:-.035em;line-height:1;
}
.c-price span{font-family:var(--mono);font-size:13px;color:var(--muted)}
/* Две строки заняты всегда, хотя помесячно там одна («330 ₽ за домен»).
   При годовой оплате строка длиннее («спишем 9 504 ₽ сразу за 12 месяцев ·
   264 ₽ за домен») и переносится, а с ней уезжала вниз вся панель: плашка
   объёма, расчёт, кнопка. Переключение периода — не повод двигать кнопку.
   Побочно это делает запас под расчётом одинаковым в обоих периодах, и
   потолок .c-break можно назвать одним числом, а не двумя. */
.c-sub{margin-top:5px;font-size:12.5px;line-height:1.5;color:var(--muted)}
.c-sub:not(:empty){min-height:3em}   /* 2 × line-height, в единицах самого блока */
/* Без JS строка остаётся пустой, и её margin отодвигал бы плашку от цены
   ни за что. */
.c-sub:empty{display:none}

/* Что входит за эти деньги — ПЛАШКОЙ, в том же оформлении, что квота
   бесплатного (.quota), и в том же слоте карточки: цена → примечание к цене
   → объём. Раньше здесь стояла подпись 13.5 px без подложки, зажатая между
   46-м кеглем и кнопкой, — объём Pro читался сноской к деньгам, а не тем,
   что покупают. Плашка слева против подписи справа не сравнивалась вовсе, и
   дыру однажды заткнули строкой «больше целей под наблюдением» в списке
   плюсов: словами чинили сломанную форму. Строка удалена
   (см. catalog._features_extra), форма выровнена.

   Моноширинная целиком, а не только числа: в .quota моно набраны оба <b>, и
   не-моно там остаётся один «+». Здесь строку пишет JS одним textContent,
   разметки внутри нет — значит либо вся моно, либо ничего.

   Строка живая и остаётся единственным местом, где названы обе квоты:
   дублировать их в описании тарифа или под полями по-прежнему не нужно.

   14 px, а не 14.5, И ЭТО РАСЧЁТ, А НЕ ВКУС. Строку пишет JS, и самая длинная,
   какую он может написать, — «до 40 доменов и 500 поддоменов»: 30 знаков
   (40 — потолок самообслуживания, 500 — квота поддоменов при нём). Ширина
   плашки внутри панели 280 px, за вычетом собственных отступов остаётся 254.
   JetBrains Mono отдаёт целочисленный шаг: 9 px на знак при 14.5 и 8 px при
   14 (13–14 включительно дают те же 8). 30 × 9 = 270 — перенос, и плашка
   становится двухстрочной ровно там, где рядом раскрывают расчёт, то есть в
   самом тесном состоянии панели. 30 × 8 = 240 ≤ 254 — влезает всегда, с
   запасом и на случай, если веб-шрифт не доехал и подставился системный
   моноширинный (0.6 em → 252). Поэтому же боковой отступ 13, а не 14.

   Полпункта разницы с .quota бесплатного оставлены намеренно: у той плашки
   текст короткий и жёсткого предела длины нет, а здесь он есть.

   ОТСТУП 7, А НЕ 14: при помесячной оплате примечание к цене занимает одну
   строку из двух зарезервированных (.c-sub min-height), и та вторая строка
   пустоты складывалась с отступом плашки в провал, в котором цена и объём
   переставали читаться парой. Резерв тронуть нельзя — он держит кнопку на
   месте при переключении периода, — поэтому сокращён отступ. */
.c-scope{
  margin-top:7px;padding:12px 13px;border-radius:10px;background:var(--paper-2);
  font-family:var(--mono);font-weight:500;font-size:14px;
  line-height:1.4;color:var(--ink);
}
/* margin-top:auto — кнопка у нижнего края панели, и свободное место копится
   НАД ней. Пробовали наоборот (margin-bottom:auto у плашки объёма, чтобы
   пустота уходила выше разбивки): зазор до кнопки становился ровным, но
   строка «из чего складывается» отрывалась от плашки, к которой относится, и
   уезжала к самой кнопке. Пустота в покое — меньшее зло, чем разорванная
   пара; к тому же теперь её съедает раскрытый расчёт. */
.cfg-total .btn{width:100%;margin-top:auto}

/* Разбивка убрана из состояния покоя. При базовом объёме она содержит ровно
   одну строку, дословно повторяющую цену этажом выше 46-м кеглем; JS держит
   блок скрытым, пока строк не станет больше одной.

   РАСКРЫТЫЙ РАСЧЁТ РАСТИТ КАРТОЧКУ — И ЭТО НОРМАЛЬНО, ЕСЛИ ОН РАСТИТ ЕЁ
   ПЛАВНО. Здесь были перепробованы обе альтернативы, и обе оказались хуже.

   Первая: зарезервировать место заранее. Пять строк — не выдумка (`Тариф` +
   две ступени доп. доменов + пачка + поштучные, это 11 доменов и 15 доп.
   поддоменов, пара нажатий «+»), и стоят они 99 px. Взять их можно было
   только сделав выше левую колонку Pro, то есть добавив в покое ~120 px
   пустоты между плашкой объёма и кнопкой. Покой видят все, раскрытый расчёт —
   единицы; менять первое ради второго нельзя.

   Вторая: не резервировать, а обрезать лишние строки прокруткой. Разбивка
   складывается в итог, стоящий над ней 46-м кеглем: спрятанная строка
   превращает её в арифметику, которая не сходится на глазах у клиента.
   Прокрутка в расчёте цены запрещена по этой причине, а не по вкусовой.

   Остаётся третье, и оно же честное: высота меняется, но переход анимирован,
   и глаз читает его как раскрытие, а не как прыжок. block-size:auto
   интерполируется благодаря interpolate-size ниже; allow-discrete нужен,
   чтобы содержимое доживало до конца анимации закрытия, иначе оно исчезает
   в первом кадре. Карточка растёт следом сама: её высота выводится из этой,
   а не задана.

   Браузер без ::details-content правило целиком не понимает и отбрасывает —
   там расчёт просто раскрывается мгновенно, как раньше. prefers-reduced-motion
   гасит переход глобальным правилом в конце файла.

   margin-bottom — зазор до кнопки. Он не остаток, а требование: без него
   последняя строка расчёта прилипала к «Оформить» вплотную. */
.c-breakwrap{margin:14px 0 16px;interpolate-size:allow-keywords}
.c-breakwrap::details-content{
  block-size:0;overflow:hidden;
  transition:block-size .3s cubic-bezier(.4,0,.2,1),
             content-visibility .3s allow-discrete;
}
.c-breakwrap[open]::details-content{block-size:auto}
.c-breakwrap summary{
  list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:6px;
  font-size:12.5px;color:var(--muted);
}
.c-breakwrap summary::-webkit-details-marker{display:none}
.c-breakwrap summary::after{
  content:"";width:5px;height:5px;margin-top:-3px;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:rotate(45deg);transition:transform .15s;
}
.c-breakwrap[open] summary::after{transform:rotate(225deg);margin-top:1px}
.c-breakwrap summary:hover{color:var(--ink)}
/* Плотнее обычного текста и в панели пошире (326 px вместо 284): подписи
   позиций приходят с сервера как есть — «Дополнительные домены (11–40)», — и
   в узкой колонке каждая вторая ломалась на две строки.

   Шаг строки 18.4 px (12/1.2 плюс gap 4) — это не вкус, а бюджет: пять
   строк при нём занимают 99 px, и ровно столько панель может отдать, не
   став выше. Прежние 12/1.35 с gap 7 давали 23.2 px на строку и 156 px на
   пять — их пришлось бы покупать ещё сотней пикселей высоты у обеих
   карточек. Это мелкий шрифт под ценой, набранный однострочными позициями;
   плотность ему по чину.

   Ни потолка, ни прокрутки здесь нет намеренно: см. .c-breakwrap. */
.c-break{
  margin-top:10px;padding-top:10px;border-top:1px solid var(--line);
  display:grid;gap:4px;
}
.brk{
  display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  font-size:12px;line-height:1.2;color:var(--muted);
}
.brk b{flex:none;font-family:var(--mono);font-weight:500;color:var(--ink)}
.cfg-note{
  margin-top:12px;font-size:11.5px;line-height:1.45;
  color:#9AA2B1;text-align:center;
}

/* Пересчёт на сервере: спиннер был бы шумом — пульсирует ровно то число,
   которое меняется, остальное остаётся читаемым. */
.calc-busy .c-price b{animation:calc-pulse 900ms ease-in-out infinite}
@keyframes calc-pulse{0%,100%{opacity:1}50%{opacity:.45}}

/* ── Что входит в Pro ──────────────────────────────
   Одна колонка, не две. В две это читалось сноской, хотя именно эти строки
   отвечают на вопрос «за что деньги»: количество целей — лишь множитель.

   Живёт под полями, в левой колонке конфигуратора: так она читается как
   «сколько целей и что мы с ними делаем», а правая остаётся про деньги.
   Граница идёт по ширине колонки, а не через всю карточку — она отделяет
   настройку от описания, а не режет карточку пополам.

   Здесь стоял padding-bottom:123px — запас, из которого разворачивался
   расчёт. Убран вместе со всей затеей «карточка не меняет высоту»: он
   покупался пустотой в покое, а покой видят все, тогда как раскрытый расчёт
   единицы. Теперь карточка растёт, но растёт плавно (см. .c-breakwrap). */
.pcard-feats{margin-top:4px;padding-top:20px;border-top:1px solid var(--line)}
.pcard-feats-cap{
  font-family:var(--mono);font-size:11px;letter-spacing:.05em;
  text-transform:uppercase;color:var(--muted);margin-bottom:8px;
}
.feats-pro{margin:0;flex:none}

/* ── Что считается целью ───────────────────────────
   Стоит ПОСЛЕ карточек: до них это был экран текста между заголовком секции
   и первым числом на странице. */
.unitbox{
  border:1px solid var(--line);border-radius:var(--r);background:var(--paper-2);
  padding:22px 26px;margin-top:28px;
  display:flex;gap:18px;align-items:flex-start;
}
.unitbox svg{flex:none;margin-top:3px}
.unitbox-body{min-width:0}
/* Заголовок — отдельный класс, а не голый <b>: правило display:block на
   `.unitbox b` рвало на строки каждое выделение внутри абзаца, и определение
   домена рассыпалось на пять обрывков. */
.unitbox-title{
  display:block;font-weight:800;font-size:15.5px;
  margin-bottom:12px;letter-spacing:-.005em;
}
.unit-defs{display:grid;gap:7px;margin-bottom:12px}
.unit-def{display:flex;gap:12px;align-items:baseline;flex-wrap:wrap}
.unit-term{
  flex:none;min-width:92px;
  font-family:var(--mono);font-size:11.5px;letter-spacing:.05em;
  text-transform:uppercase;color:var(--indigo);
}
.unit-desc{font-size:14.5px;color:var(--muted);min-width:0}
.unit-desc code{
  font-family:var(--mono);font-size:13px;color:var(--ink);
  background:rgba(16,24,40,.055);padding:1.5px 7px;border-radius:6px;
}
.unitbox p{font-size:14.5px;color:var(--muted)}
.unitbox p b{font-weight:700;color:var(--ink)}

/* ── Мелкий шрифт ─────────────────────────────────── */
/* Две колонки, потому что пунктов двое: при трёх третья стояла бы пустой, и
   пара текстов читалась бы обрезанным рядом, а не парой. */
.pnotes{
  margin-top:24px;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:20px 28px;
}
.pnote{font-size:13px;line-height:1.55;color:var(--muted)}
.pnote b{display:block;margin-bottom:5px;font-size:13px;font-weight:700;color:var(--ink)}
.pnote a{color:var(--indigo);text-decoration:underline;text-underline-offset:2px}
.anchor-note{margin-top:22px;font-size:13px;color:#8A93A3;max-width:76ch}
/* Живёт не только здесь: тем же классом набрана приписка о фиксации согласия
   на /consent/. Осталось от прежней тройки .vol-note/.legal-note/.anchor-note
   — первые две в секции тарифов заменены на .pnote. */
.legal-note{margin-top:20px;font-size:14px;color:var(--muted);max-width:76ch}

/* ── FAQ ────────────────────────────────────────── */
.faq{max-width:780px}
.faq details{border-bottom:1px solid var(--line)}
.faq summary{
  list-style:none;cursor:pointer;position:relative;
  padding:22px 44px 22px 0;font-weight:600;font-size:16.5px;letter-spacing:-.005em;
}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{
  content:"+";position:absolute;right:4px;top:50%;
  transform:translateY(-50%);
  font-family:var(--mono);font-size:20px;color:var(--indigo);
  transition:transform .2s;
}
.faq details[open] summary::after{transform:translateY(-50%) rotate(45deg)}
.faq details p{padding:0 0 24px;color:var(--muted);font-size:15px;max-width:70ch}
.faq details a{color:var(--indigo);font-weight:600}
.faq details a:hover{text-decoration:underline}

/* ── Финальный CTA ────────────────────────────────
   «Глаза на горизонте» (.horizon, .h-ring/.h-tick/.h-pupil/.h-halo) здесь
   больше нет: разметку заменили два круга прямо в final_cta.html. Вместе с
   ним ушёл и `.final .alt` — стиль вторичной ссылки «подпишитесь на
   телеграм-канал», которую удалили как ведущую в никуда (см. комментарий в
   final_cta.html). Стили пережили разметку на два захода, что и делает их
   опасными: следующий редактор считает, что блок где-то есть. */
.final{text-align:center;padding:128px 0;overflow:hidden}
.final .badge{margin-bottom:28px}
.final h2{margin:0 auto;max-width:20ch}
.final .lead{margin:18px auto 0;max-width:52ch}
.final .cta-row{justify-content:center;margin-top:36px}
.final .micro{margin-top:16px}

/* ── Футер ──────────────────────────────────────── */
footer.site-footer{background:var(--night);color:var(--d-muted);border-top:1px solid var(--d-line);padding:64px 0 40px}
/* Колонок столько, сколько блоков: «контакты» исчезают вместе с незаданным
   LEGAL_EMAIL (см. footer.html), и жёсткие четыре трека оставили бы на их
   месте пустую четверть подвала.

   Явный трек ровно один — фирменный блок; остальные создаются неявно по числу
   элементов. repeat(auto-fit,…) здесь НЕ работает: авто-повтор запрещён, когда
   в шаблоне есть гибкий трек (1.5fr), — вся строка становится невалидной, и
   подвал молча схлопывается в одну колонку. */
.f-cols{
  display:grid;grid-template-columns:1.5fr;
  grid-auto-flow:column;grid-auto-columns:1fr;gap:32px;
}
.f-col h4{
  font-family:var(--mono);font-size:12px;letter-spacing:.06em;
  color:#6C7688;font-weight:500;margin-bottom:16px;
}
.f-col a{display:block;font-size:14px;color:var(--d-muted);padding:5px 0;transition:color .15s}
.f-col a:hover{color:var(--d-text)}
/* Знак в футере — тоже ссылка внутри .f-col, и правило выше его ломало:
   display:block перебивал .logo{display:flex} (класс+тип против одного
   класса), а без flex-контейнера вступало глобальное svg{display:block}
   со строки 43 — кружок вставал отдельной строкой, «VulnEye» съезжал под
   него. padding:0 возвращает исходный отступ до подписи (.f-brand p). */
/* Цвет и transition возвращаются из-под .f-col a: то правило (класс + тип)
   перебивает .logo по специфичности, и лого в подвале выходило приглушённым,
   да ещё плавно перекрашивалось при наведении — единственное лого на сайте,
   которое так себя вело. Здесь оно обязано быть тем же, что в шапке. */
.f-brand .logo{display:flex;padding:0;color:var(--d-text);transition:none}
.f-brand .logo:hover{color:var(--d-text)}
.f-bottom{
  margin-top:52px;padding-top:24px;border-top:1px solid var(--d-line);
  font-family:var(--mono);font-size:12px;color:#5E6879;
}
/* Оговорка под лого (была .disclaimer отдельным блоком над подвалом,
   где читалась первой и перебивала навигацию). 34ch — ширина не красоты
   ради: при ней текст встаёт в семь строк и колонка заканчивается вровень с
   колонкой ссылок. Цвет тише ссылок: это справка, а не навигация. */
.f-legal{font-size:12.5px;line-height:1.6;color:#79839A;max-width:34ch;margin-top:16px}

/* ── Дуги знака на светлых секциях ──── */
.deco{position:relative;overflow:hidden}
.deco>.container{position:relative;z-index:1}
.arcs{position:absolute;z-index:0;pointer-events:none;color:rgba(79,70,229,.08)}
.arcs-fade {
    -webkit-mask-image: linear-gradient(
        to bottom,
        #000 0%,
        #000 40%,
        transparent 56%,
        transparent 100%
    );

    mask-image: linear-gradient(
        to bottom,
        #000 0%,
        #000 40%,
        transparent 56%,
        transparent 100%
    );
}
.grey .arcs{color:rgba(79,70,229,.095)}

/* ── Мобильный липкий CTA ──────────────────── */
.mcta{
  position:fixed;left:0;right:0;bottom:0;z-index:60;
  padding:12px 16px calc(12px + env(safe-area-inset-bottom));
  background:rgba(11,15,26,.9);backdrop-filter:blur(12px);
  border-top:1px solid var(--d-line);
  transform:translateY(110%);transition:transform .3s ease;
  display:none;
}
.mcta .btn{width:100%}
.mcta.show{transform:translateY(0)}
/* ПОЛОСА ПОД ПАНЕЛЬЮ. На телефонах со скруглённым экраном и жестовой
   навигацией высота, которую отдаёт env(safe-area-inset-bottom), не всегда
   совпадает с тем, что браузер реально оставляет под вьюпортом: панель
   заканчивалась выше нижнего края, и в щель светила белая страница. Тень без
   размытия продолжает фон панели вниз на любую такую щель и ничего не стоит:
   она не участвует в раскладке и не ловит нажатия. */
.mcta{box-shadow:0 60px 0 0 rgba(11,15,26,.9)}

/* ── Появление при скролле ────────────────────────
   ПОД `.js`, А НЕ БЕЗУСЛОВНО. Класс ставит инлайновый скрипт в <head>
   (base_landing.html), и он же снимается, если landing.js так и не доехал.
   Без этой оговорки несработавший скрипт оставлял прозрачными все секции
   между hero и подвалом — страница была, а посетитель её не видел. */
.js .reveal{opacity:0;transform:translateY(14px);transition:opacity .6s ease,transform .6s ease}
.js .reveal.in{opacity:1;transform:none}

/* ── Адаптив ────────────────────────────────────── */
/* ПЕРВЫЙ ЭКРАН СКЛАДЫВАЕТСЯ РАНЬШЕ ОСТАЛЬНОЙ СТРАНИЦЫ, И ЭТО НЕ ПРИДИРКА.
   Две колонки hero держатся на 524px под строку кнопок; контейнер даёт эту
   ширину, только пока сам не начал сжиматься, то есть до 1128. Ниже левая
   колонка проваливается под 524, кнопки встают в два ряда, левая колонка
   вырастает на 57px, а правая одновременно худеет — расхождение доходило до
   135px на 1024. Ровно тот диапазон, где страницу смотрят с ноутбука.
   Порог 1120 — округлённый вниз предел контейнера: выше него две колонки
   сходятся по высоте до пары пикселей, ниже — не сходятся никак.
   Остальные сетки страницы к 524px не привязаны и ломаются на своих 1020.

   В одну колонку окно наконец получает свою натуральную ширину: 560 против
   508 на десктопе, кадр 580 рисуется почти 1:1. Прежние 480 достались от
   порога 1020 и в колонке шириной 1072 смотрелись бы потерянными. */
@media(max-width:1120px){
  .hero-copy .cta-row{justify-content:flex-start}
  /* В ОДНУ КОЛОНКУ КАДР УХОДИТ В САМЫЙ НИЗ, А НЕ ВСТАЁТ ПОСЕРЕДИНЕ. В разметке
     факт-строка лежит внутри текстового блока, сразу под заголовком, — на
     десктопе она закрывает пустоту слева от кадра. Сложи колонки как есть, и
     кадр разорвал бы связку «заголовок → числа → лид → кнопки».
     display:contents раскрывает обёртку, её дети становятся элементами той же
     сетки, и порядок задаётся order. Собственный gap сетки при этом снят:
     расстояния между блоками — их собственные margin. */
  /* Растяжка на весь экран снимается вместе с двумя колонками: в одну колонку
     контент выше окна почти всегда, а на высоком окне (планшет вертикально)
     центрирование отбивало бы заголовок гигантским полем сверху. */
  .hero{min-height:0;align-content:start}
  .hero-grid{grid-template-columns:minmax(0,1fr);gap:0}
  .hero-copy{display:contents}
  /* Отступ, снятый на десктопе ради выравнивания с кадром: в одну колонку
     выравнивать не с чем, а лид, идущий вплотную за заголовком, читается
     его продолжением. */
  .hero .sub{order:1;margin-top:30px}
  /* Три колонки остаются и здесь, но становятся широкими: контейнер ~1080
     против 532px левой колонки, то есть на факт приходится 340+ вместо 151, и
     подписи ложатся в строку. Ряд из шести не делаем: на 180px подпись снова
     ломается на три строки, а ради чего — шесть чисел в ряд читаются как
     таблица курса валют, а не как шесть утверждений. */
  .facts{order:2;grid-template-columns:repeat(3,1fr)}
  .cta-row{order:4}
  .micro{order:5}
  .vwin-wrap{order:6;margin:52px auto 0;max-width:560px}
  /* Ограничения ширины у h1 здесь больше нет: заголовок вынесен над сеткой и
     занимает всю ширину контейнера на любом экране — в одну колонку он просто
     набирается двумя строками. Прежние 532px держали его в габарите левой
     колонки, которой на этом пороге уже не существует. */
}
@media(max-width:1020px){
  /* Ниже 1020 подписи в трети ширины ломаются на три строки — 2 колонки,
     то есть три ряда по два факта. */
  .facts{grid-template-columns:repeat(2,1fr)}
  .fact:nth-child(3n+1){padding-left:16px}
  .fact:nth-child(2n+1){padding-left:0}
  .tl-grid{grid-template-columns:repeat(2,1fr)}
  /* Четыре вкладки в ряд дают по два слова в строку заголовка — ниже 1020
     они встают в две по две. */
  .tour-nav{grid-template-columns:repeat(2,minmax(0,1fr))}
  .tour-panels{padding:28px 26px 26px}
  .cve-grid{grid-template-columns:repeat(2,1fr)}
  /* Два блока «как это работает» встают друг под друга раньше остального:
     каждому нужна колонка номера плюс строка текста, и в половине ширины
     заголовок ломается на три строки. */
  .steps-two{grid-template-columns:minmax(0,1fr)}
  /* Четыре шага в ряд на 1000px дают по два слова в строку описания. */
  .flow{grid-template-columns:repeat(2,1fr);gap:0 26px}
  .flow li:nth-child(n+3){margin-top:22px}
  /* Карточки в столбик раньше, чем остальное: Pro с конфигуратором
     внутри требует ширины, а бесплатному её и не нужно. */
  .plans-two{grid-template-columns:minmax(0,1fr);max-width:640px;margin-inline:auto}
  /* В столбик порядок исходников работает против акцента: бесплатный
     занимает целый экран, и до цены Pro человек доскроллит уже уставшим.
     В строку такой проблемы нет — там обе карточки видны разом. */
  .plan-pro{order:-1}
  /* КНОПКА ПРИЛИПАЛА К ПЛАШКЕ ОБЪЁМА. `margin-top:auto` у .cfg-total .btn
     держит её у нижнего края панели, пока панель выше своего содержимого, —
     на широком экране туда уходит 119px запаса. В столбик панель ровно по
     контенту, auto превращается в ноль, и «до 3 доменов и 15 поддоменов»
     оказывалось впритык к «Оформить»: две разные вещи — что покупают и чем
     платят — читались одним блоком. Здесь зазор задаётся явно, а у разбивки
     снимается нижний отступ: во flex-колонке margin'ы соседей не схлопываются
     и в раскрытом расчёте сложились бы в 32px. */
  .cfg-total .btn{margin-top:16px}
  .c-breakwrap{margin-bottom:0}
  /* В столбик цена идёт сразу за полями: между ними не должно быть экрана
     текста, который на широком экране лежит соседней колонкой. */
  .cfg{
    grid-template-columns:minmax(0,1fr);
    grid-template-areas:"fields" "total" "feats";
    gap:22px;
  }
  /* grid-auto-flow сбрасывается вместе со сменой сетки: без этого элементы
     продолжали бы уезжать в неявные КОЛОНКИ, и «две колонки» остались бы
     четырьмя. */
  .f-cols{grid-template-columns:1fr 1fr;grid-auto-flow:row}
  /* Фирменный блок во всю ширину: в половине узкого экрана оговорка
     под лого рвётся на дюжину строк по три слова и вытягивает столбец вдвое
     выше соседнего. Мерка меняется, а не снимается: без потолка на
     планшете строка растягивается на всю ширину подвала, а это за сотню
     знаков — глаз теряет начало следующей. На телефоне 78ch шире экрана
     и ничего не ограничивает. */
  .f-brand{grid-column:1/-1}
  .f-legal{max-width:78ch}
}
/* ── Мобильное меню ────────────────────────────────────────────
   ПОРОГ 779, А НЕ 719. Строке шапки нужно 772px: логотип, четыре пункта
   меню, «Войти» и кнопка. Ниже этого страница уезжала вправо целиком —
   на 720px ровно на 52px, — и вина была не в контенте, а в самой шапке,
   единственном блоке лендинга, который не умел сжиматься. Между 720 и 779
   бургер теперь стоит вместо строки меню, и горизонтальной прокрутки нет.
   Всё остальное мобильное живёт в блоке на 719: там она про телефон, тут —
   про то, что строка не влезла. */
@media(max-width:779px){
  .nav,.top-cta .login{display:none}

  /* Панель — тот же <nav>, что на десктопе лежит строкой: display меняется
     на flex-столбик, и он выпадает из-под шапки. position:absolute отсчи-
     тывается от .top (она sticky, то есть позиционированная), поэтому
     top:100% — это ровно нижняя кромка шапки, без магических 66px.
     Панель не в потоке: страница под ней не прыгает при открытии. */
  .burger{
    display:inline-flex;align-items:center;justify-content:center;
    width:40px;height:40px;margin-right:-8px;flex:none;
    background:none;border:0;padding:0;cursor:pointer;color:var(--d-text);
  }
  /* Три полоски одним элементом: средняя — сам span, крайние — его
     псевдоэлементы. В открытом виде средняя гаснет, крайние сходятся в
     крестик; transform-ы считаются от центра, поэтому линии пересекаются
     ровно посередине кнопки. */
  .burger-i,.burger-i::before,.burger-i::after{
    content:"";display:block;width:20px;height:2px;border-radius:2px;
    background:currentColor;transition:transform .22s ease,opacity .16s ease;
  }
  .burger-i{position:relative}
  .burger-i::before{position:absolute;top:-6px}
  .burger-i::after{position:absolute;top:6px}
  .top.is-open .burger-i{background:transparent}
  .top.is-open .burger-i::before{transform:translateY(6px) rotate(45deg)}
  .top.is-open .burger-i::after{transform:translateY(-6px) rotate(-45deg)}

  .top.is-open .nav{
    display:flex;flex-direction:column;gap:0;margin:0;
    position:absolute;left:0;right:0;top:100%;
    padding:2px 24px 12px;
    background:var(--night);border-bottom:1px solid var(--d-line);
    box-shadow:0 26px 44px -30px rgba(0,0,0,.9);
  }
  .top.is-open .nav a{
    padding:14px 0;font-size:16px;color:var(--d-text);
    border-top:1px solid var(--d-line);
  }
  /* Подчёркивание при наведении — приём строки меню, а не столбика:
     в панели оно ложится на границу соседнего пункта. */
  .top.is-open .nav a::after{content:none}
  .top.is-open .nav .nav-login{display:block;color:var(--d-muted)}
}

@media(max-width:719px){
  section{padding:72px 0}

  /* Строка шапки на 390px: логотип, кнопка и бургер. Зазор 36px и поля 24px
     были рассчитаны на широкую строку с меню внутри — с бургером на конце
     «Начать бесплатно» переставало помещаться и ломалось на две строки
     (у .btn на телефоне разрешён перенос — это лечит длинную кнопку под
     лентой KEV, но здесь вредит). Кнопке шапки перенос возвращаем запретом,
     а место находим в зазорах. */
  .top-in{gap:12px;padding:0 16px}
  .top-cta{gap:12px}
  .top-cta .btn{white-space:nowrap;padding:10px 14px;font-size:14px}
  .hero{padding:52px 0 72px}

  /* ── Первый экран на телефоне ────────────────────────────────
     ЗАГОЛОВОК И ЛИД СТОЯЛИ В 58px ДРУГ ОТ ДРУГА: 28 от margin-bottom у h1
     плюс 30 у .sub. На десктопе это верно — там лид отбит от заголовка в
     полторы строки и колонка тянется на всю высоту экрана. На 390px тот же
     зазор занимает шестую часть первого экрана, а над ним висит заголовок в
     три строки: между собственным текстом и его же продолжением открывается
     дыра шире, чем между секциями.
     Обнуляем нижний отступ h1 и оставляем расстояние одним значением у лида —
     так его видно целиком, а не как сумму двух чисел из разных мест. */
  .hero h1{margin-bottom:0}
  .hero .sub{margin-top:14px}

  /* КАДР КАБИНЕТА НА ТЕЛЕФОНЕ НЕ ПОКАЗЫВАЕТСЯ. В одну колонку он уезжает под
     кнопки (order:6), то есть на первый экран не попадает всё равно, а высоты
     занимает вместе с рамкой окна и подписью около 500px — ровно перед
     секцией problem, куда посетитель и идёт дальше. Продукт кадрами показан
     в туре (#features), там их четыре и все сняты в мобильной раскладке;
     здесь тот же кадр во второй раз только удлинял дорогу до тарифов.
     Файлы остаются в статике и на широком экране показываются как прежде. */
  .vwin-wrap{display:none}
  .tl-grid,.cve-grid,.aud-grid{grid-template-columns:1fr}
  /* ЛЕНТА KEV НА ТЕЛЕФОНЕ — ДВЕ КАРТОЧКИ, А НЕ ШЕСТЬ. В одну колонку секция
     занимала 2049px, почти два с половиной экрана: доказательство тезиса
     «эти уязвимости уже используют» работает и на двух, а остальные четыре
     просто отодвигали тарифы. Режется показ, а не выборка: число под лентой
     («+N за 7 дней», всего в каталоге) считается по каталогу целиком и
     остаётся верным. */
  .cve-grid .cve:nth-child(n+3){display:none}
  /* На телефоне вкладки — столбиком: в две колонки заголовок из шести слов
     ломается на четыре строки, и ряд кнопок становится выше самого кадра. */
  .tour-nav{grid-template-columns:minmax(0,1fr);gap:8px}
  .tour-nav label{padding:11px 14px;font-size:14px}
  .tour-n{margin-bottom:5px}
  .tour-panels{padding:20px 16px 18px;border-radius:16px;min-height:0}
  .tour-panel h3{font-size:20px}
  .tour-shot figcaption{padding:12px 14px;font-size:13px}
  .tour-more ul{grid-template-columns:1fr}
  /* Номер уходит из своей колонки наверх: на узком экране вертикальная линейка
     съедала треть строки, и текст рвался по два слова. */
  .step2{grid-template-columns:minmax(0,1fr);gap:14px;padding:28px 24px 30px}
  .step2-n{padding-right:0;border-right:0;font-size:24px}
  .honest-cols{grid-template-columns:1fr;gap:22px}
  .flow{grid-template-columns:1fr}
  .flow li{padding-right:0}
  .flow li+li{margin-top:20px}
  .fact b{font-size:16px}
  .vwin-wrap{max-width:100%}
  .plan{padding:24px 20px}
  .pcard-head{gap:16px}
  .seg{width:100%}
  .seg button{flex:1;padding:9px 10px;text-align:center}
  /* Подпись и степпер в столбик: на 320px они в строку не помещаются,
     и перенос по flex-wrap отрывал ввод от его подписи. */
  .cfg-field{flex-direction:column;align-items:stretch;gap:10px}
  .cfg-num{align-self:flex-start}
  /* 46px — кегль для широкого экрана; на 320px он упирается в края панели. */
  .c-price b{font-size:38px}
  .pnotes{grid-template-columns:minmax(0,1fr)}
  .unit-term{min-width:0}
  .mcta{display:block}
  /* ...и подвал получает под себя её высоту. Панель фиксированная, из потока
     выключена, поэтому последние строки — ИНН, ОГРНИП, ссылки на документы —
     оказывались под ней и не выкручивались прокруткой ни на пиксель. */
  footer.site-footer{padding-bottom:calc(40px + 68px + env(safe-area-inset-bottom))}
  .final{padding:88px 0}

  /* ГОРИЗОНТАЛЬНАЯ ПРОКРУТКА НА ТЕЛЕФОНЕ БЫЛА ОТ КНОПОК. У .btn стоит
     white-space:nowrap — на широком экране это правильно (кнопка не должна
     рваться на два слова), но «Проверить мои домены на эти уязвимости»
     в одну строку шире любого телефона, и страница уезжала вправо целиком.
     Здесь перенос разрешён, а ширина ограничена контейнером. */
  .btn{white-space:normal;text-align:center;max-width:100%}
  /* Кнопка под лентой KEV — на всю ширину: рядом с ней в этой строке стоит
     подпись про источник, и в остатке ширины кнопка вырождается в столбик
     по два слова. */
  .feed-note{gap:14px}
  .feed-note .btn{width:100%}

  /* СНАЧАЛА БЕСПЛАТНЫЙ, ПОТОМ PRO. Порядок перевёрнут в блоке на 1020, где
     он оправдан: на планшете обе карточки ещё сопоставимы по высоте. На
     телефоне Pro с конфигуратором внутри занимает несколько экранов, и
     бесплатный оказывался за ним — то есть простой ответ пряталcя за
     сложным. */
  .plan-pro{order:0}

  /* Резерв высоты сцены возвращается, но со своим коэффициентом: мобильные
     кадры сняты вытянутыми по вертикали (336×780 против 1096×659), и мерка
     десктопа тут не работает. Как и там, берётся середина диапазона —
     высокие кадры чуть раздвигают сцену, короткие оставляют запас. */
  .tour-panels{min-height:calc(1.6 * (100vw - 80px) + 200px)}
}

/* ── Reduced motion ── */
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation:none!important;transition:none!important}
  /* `*` не покрывает ::details-content: это не ::before/::after, а собственный
     бокс элемента details, и звёздочка до него не достаёт. Раскрытие расчёта
     в тарифах пришлось бы гасить вручную — вот оно. */
  .c-breakwrap::details-content{transition:none!important}
  /* Селектор с `.js` — не украшение: скрытое состояние тоже переехало под
     этот класс, и голый `.reveal` его больше не перебивает по специфичности. */
  .js .reveal{opacity:1;transform:none}
  /* Дуга по рамке бейджа без вращения — просто светлое пятно на одном краю.
     Смысла в ней тогда нет, убираем совсем. */
  .badge::after{display:none}
}

/* ---------------------------------------------------------------------------
   Правовые страницы: оферта, политика ПДн
   Длинный текст, который читают выборочно. Поэтому узкая колонка (~70ch),
   крупный межстрочный интервал и заметные заголовки — по ним ищут нужный
   пункт, а не читают подряд.
   --------------------------------------------------------------------------- */
.legal{padding:72px 0 104px}
/* 40px — расстояние до боковой колонки, которая на узком экране стоит над
   текстом; на десктопе она уезжает вправо, там отступ до текста снова 56px
   (медиазапрос в конце блока). */
.legal-head{max-width:70ch;margin-bottom:40px}
.legal-head h1{font-size:clamp(28px,4vw,40px);line-height:1.15;letter-spacing:-.02em;margin-top:12px}
.legal-meta{margin-top:20px;font-size:14px;color:var(--muted)}

/* padding:0 отменяет section{padding:104px 0} из шапки файла. То правило
   разводит секции лендинга, а .legal-body — тоже <section>, и получал от него
   104px пустоты между «Редакция от …» и первым разделом плюс 104px в конце,
   поверх .legal{padding-bottom:104px}. Правило .legal-body h2:first-child ниже
   написано ровно против этого зазора, но против чужого padding оно бессильно —
   обнулять надо здесь. */
.legal-body{max-width:70ch;padding:0}
.legal-body h2{
  font-size:20px;
  line-height:1.3;
  margin:44px 0 14px;
  padding-top:22px;
  border-top:1px solid var(--line);
  /* Вторая протечка из шапки файла, после section{padding}: h2{max-width:22ch}
     рассчитан на заголовки секций лендинга в 42px, а здесь шрифт 20px — те же
     22ch давали 306px, то есть «4. Права на Активы и разрешение на
     сканирование» ломалось на три строки, а линейка над разделом обрывалась на
     половине колонки. Ширину задаёт колонка текста, а не число символов. */
  max-width:none;
}
.legal-body h2:first-child{margin-top:0;padding-top:0;border-top:0}
.legal-body p{margin:0 0 14px;line-height:1.7;color:var(--ink)}
.legal-body ul{margin:0 0 18px;padding-left:22px}
.legal-body li{margin-bottom:9px;line-height:1.7}
.legal-body b{font-weight:600}
.legal-body a{color:var(--indigo);text-decoration:underline;text-underline-offset:2px}
.legal-body code{
  font-family:var(--mono);
  font-size:.9em;
  background:var(--paper-2);
  border:1px solid var(--line);
  border-radius:4px;
  padding:1px 5px;
}

/* Незаполненный раздел. Видно и в вёрстке, и на скриншоте — чтобы черновик
   не уехал в прод незамеченным. */
.legal-todo{
  border-left:3px solid var(--sev-med);
  background:rgba(245,158,11,.07);
  padding:12px 16px;
  border-radius:0 6px 6px 0;
  color:var(--muted);
}

/* Ссылка-якорь у заголовка раздела: способ скопировать ссылку на конкретный
   пункт, не разбирая адресную строку. Появляется по наведению и по фокусу с
   клавиатуры; на тач-устройствах её нет — там за навигацию отвечает
   оглавление. Ставится скриптом, в разметке документов её нет. */
.legal-body h2 .legal-anchor{
  margin-left:10px;
  font-family:var(--mono);font-size:.8em;font-weight:400;
  color:var(--indigo);text-decoration:none;
  opacity:0;transition:opacity .15s ease;
}
.legal-body h2:hover .legal-anchor,
.legal-body h2 .legal-anchor:focus-visible{opacity:1}

/* ── Боковая колонка документа ─────────────────────────────
   Оферта — это 7000px текста, который не читают подряд: приходят за конкретным
   пунктом по ссылке из тарифов, из письма или из поиска. Поэтому оглавление
   липкое — переход к соседнему разделу не должен требовать возврата наверх, —
   и рядом с ним лежит переход между тремя документами: из оферты регулярно
   уходят в политику ПДн, а ссылки на неё до этого были только в подвале, то
   есть в семи тысячах пикселей вниз.

   <ol> оглавления собирает landing.js из заголовков самого документа. Список
   названий разделов, написанный в шаблоне рядом с текстом, разъезжается с
   текстом при первой же правке.

   Базовая раскладка здесь — узкая (колонка встаёт над текстом), двухколоночная
   включается медиазапросом ниже. Порядок именно такой, потому что над текстом
   каждый лишний пиксель виден: жалоба, с которой всё началось, была ровно про
   пустоту перед первым разделом. max-width держит колонку по ширине текста —
   без него карточка растягивалась во всю ширину контейнера. */
.legal-aside{max-width:70ch;margin:0 0 36px}

.legal-toc{
  margin-bottom:16px;
  border:1px solid var(--line);
  border-radius:var(--r);
  background:#fff;
}
.legal-toc>summary{
  display:flex;align-items:center;gap:10px;
  padding:13px 16px;
  font-family:var(--mono);font-size:12px;letter-spacing:.06em;
  color:var(--muted);
  cursor:pointer;list-style:none;
  transition:color .15s;
}
.legal-toc>summary::-webkit-details-marker{display:none}
.legal-toc>summary:hover{color:var(--ink)}
/* Шеврон вместо стандартного треугольника: вниз у свёрнутого, вверх у раскрытого. */
.legal-toc>summary::after{
  content:"";margin-left:auto;
  width:7px;height:7px;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:translateY(-2px) rotate(45deg);
  transition:transform .18s ease;
}
.legal-toc[open]>summary::after{transform:translateY(2px) rotate(-135deg)}

.legal-toc ol{
  list-style:none;
  padding:6px 16px 14px;
  border-top:1px solid var(--line);
}
.legal-toc a{
  display:grid;grid-template-columns:26px 1fr;
  padding:6px 0;
  font-size:13.5px;line-height:1.45;
  color:var(--muted);
  transition:color .15s;
}
.legal-toc a:hover{color:var(--ink)}
.legal-toc a>span{font-family:var(--mono);font-size:12px;opacity:.72;padding-top:1.5px}
.legal-toc a[aria-current]{color:var(--indigo);font-weight:600}

/* Над текстом три документа лежат строкой, а не столбиком: столбик добавлял бы
   ещё сотню пикселей ровно там, где их и не хватало. В боковой колонке (ниже)
   он снова становится списком. */
.legal-docs{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 18px}
.legal-docs-h{
  font-family:var(--mono);font-size:12px;letter-spacing:.06em;
  color:var(--muted);
}
.legal-docs a{
  font-size:13.5px;line-height:1.45;color:var(--muted);
  transition:color .15s;
}
.legal-docs a:hover{color:var(--ink)}
.legal-docs a[aria-current]{color:var(--ink);font-weight:600}
/* На телефоне три названия в строку не влезают в любом случае — тогда подпись
   уходит на свою строку целиком, иначе первая строка обрывается после одной
   ссылки и список выглядит рваным. */
/* ── Совсем узкие телефоны (iPhone SE и подобные) ──────────────
   На 320px строка шапки требует 334px: логотип, «Начать бесплатно» и
   бургер. Кнопку не переносим и не прячем — это единственный CTA на первом
   экране; вместо этого ужимаются кегли и зазоры, ровно настолько, чтобы
   строка сошлась. */
@media(max-width:380px){
  .top-in{gap:8px;padding:0 12px}
  .logo b{font-size:17px}
  .top-cta{gap:8px}
  .top-cta .btn{padding:9px 11px;font-size:13px}
  .burger{width:36px;margin-right:-6px}
}

@media(max-width:560px){
  .legal-docs-h{flex-basis:100%;margin-bottom:2px}
}

/* Две колонки — только когда справа от 70ch колонки текста действительно есть
   место под оглавление (70ch ≈ 712px + 264px + зазор). Ниже порога всё встаёт
   в один столбец в порядке DOM: шапка → оглавление → текст. Он же и есть
   правильный порядок чтения, поэтому колонки расставлены сеткой, а не порядком
   элементов в шаблоне. */
@media(min-width:1120px){
  .legal .container{
    display:grid;
    grid-template-columns:minmax(0,70ch) 264px;
    justify-content:space-between;
    /* align-items:start обязателен: растянутому по высоте элементу sticky
       некуда двигаться, и колонка молча перестаёт залипать. */
    align-items:start;
  }
  .legal-head{grid-column:1/-1;margin-bottom:56px}
  .legal-body{grid-column:1;grid-row:2}
  .legal-aside{
    grid-column:2;grid-row:2;margin:0;max-width:none;
    position:sticky;top:96px;          /* липкая шапка 66px + воздух */
    max-height:calc(100vh - 128px);
    overflow-y:auto;
  }
  .legal-toc{margin-bottom:26px}
  .legal-docs{display:block}
  .legal-docs-h{margin-bottom:8px;padding-left:2px}
  .legal-docs a{display:block;padding:5px 2px}
}

/* ── Печать ────────────────────────────────────────────────
   Единственные страницы сайта, которые живут вне браузера: оферту сохраняют в
   PDF и подшивают к бухгалтерии, согласие распечатывают. На бумаге не нужны
   ни тёмная шапка (это ещё и полстраницы тонера), ни подвал, ни оглавление со
   ссылками, ни плашка про cookie поверх текста. */
@media print{
  @page{margin:18mm 16mm}
  .top,footer.site-footer,.mcta,.cookie-bar,.legal-aside{display:none!important}
  .legal-body h2 .legal-anchor{display:none}
  body{background:#fff;color:#000}
  .legal{padding:0}
  .legal .container{display:block;max-width:none;padding:0}
  .legal-head{max-width:none;margin-bottom:26px}
  .legal-head h1{font-size:23px}
  .legal-body{max-width:none}
  .legal-body h2{font-size:15px;break-after:avoid;page-break-after:avoid}
  .legal-body p,.legal-body li{color:#000;orphans:3;widows:3}
  .legal-body a{color:#000;text-decoration:none}
  .legal-body code{background:none;border-color:#999}
  .sec-label,.lead,.legal-meta,.legal-todo,.legal-note{color:#333}
  .legal-todo{background:none;border-left-color:#000}
}

/* Здесь БЫЛ блок @media (prefers-color-scheme:dark), переключавший текст
   документов на тёмную палитру (--d-text, --d-line, --indigo-d). Он приехал
   из редизайна, где страница целиком темнела, — а у лендинга такого режима
   нет: body жёстко на --paper, темнеют только явно помеченные .night-sec,
   шапка и подвал. Получалось #E7EAF2 по #FAFAF9, контраст 1.2:1 — оферта и
   политика ПДн становились нечитаемыми у всех, у кого система в тёмной теме.
   Симптом узнаваемый: пункты списков (li, цвет наследуется) читаются, а
   абзацы (p, цвет задан) — пропадают.

   Тёмная тема есть только у консоли (app/console.css), она на
   :root[data-theme] и переключается руками. Если лендингу когда-нибудь
   понадобится своя — темнеть должен фон страницы, а не один текст. */

/* ── Уведомление о cookie ────────────────────────
   z-index выше .mcta (60): липкий CTA на мобильных живёт в том же углу, и
   уведомление должно быть поверх — иначе кнопку «Понятно» нечем нажать.
   Скрытие — атрибутом hidden из landing.js, чтобы баннер не мигал у тех, кто
   его уже закрыл. */
.cookie-bar{
  position:fixed;left:16px;right:16px;bottom:16px;z-index:70;
  display:flex;align-items:center;gap:16px;flex-wrap:wrap;
  max-width:760px;margin:0 auto;
  padding:14px 18px;
  background:#fff;border:1px solid var(--line);border-radius:var(--r);
  box-shadow:0 12px 32px rgba(16,24,40,.12);
}
.cookie-bar[hidden]{display:none}
/* 320px базиса хватает ровно до тех пор, пока экран шире 320 плюс кнопка и
   поля: на 360-м телефоне плашка распирала вьюпорт. Ниже 560 текст занимает
   всю строку, кнопка встаёт под ним. */
.cookie-bar p{flex:1 1 320px;min-width:0;font-size:14px;line-height:1.6;color:var(--muted)}
@media(max-width:560px){
  .cookie-bar{gap:12px}
  .cookie-bar p{flex:1 1 100%}
  .cookie-bar .btn{width:100%}
}
.cookie-bar a{color:var(--indigo);text-decoration:underline;text-underline-offset:2px}
.cookie-bar .btn{flex:0 0 auto}
/* Две кнопки в режиме согласия. ОДНОГО РАЗМЕРА И РЯДОМ — отказ, нарисованный
   мельче или бледнее, это тот же тёмный паттерн, только вежливый: выбор
   формально есть, а взгляд ведут к одному варианту. Отличаются заливкой, а не
   весом: «Принять» основное действие, «Только необходимые» — полноценная
   альтернатива, а не отказ от сайта.
   На узком экране порядок тот же, что в разметке: сначала отказ, потом
   согласие. Палец на телефоне живёт у нижнего края, и нижняя кнопка нажимается
   чаще — ставить туда «Принять» значило бы собирать согласия большим пальцем. */
.cookie-bar-actions{display:flex;gap:10px;flex:0 0 auto;flex-wrap:wrap}
@media(max-width:560px){
  .cookie-bar-actions{width:100%}
  .cookie-bar-actions .btn{flex:1 1 auto;width:auto}
}

@media(max-width:719px){
  /* .mcta показывается только на мобильных — поднимаем баннер над ним.
     Порог тот же, что у самой .mcta в блоке адаптива: при 720 против 719
     ровно на 720px баннер поднимался над кнопкой, которой на этой ширине
     ещё нет, и под ним оставалась полоса пустоты. */
  .cookie-bar{bottom:84px}
  /* …кроме правовых страниц: там липкий CTA убран (base_landing.html, блок
     mcta), и подниматься не над чем — иначе под баннером остаётся полоса
     пустоты в высоту кнопки, которой на странице нет. */
  body:has(.legal) .cookie-bar{bottom:16px}
}

@media (prefers-color-scheme:dark){
  .cookie-bar{
    background:var(--night-2);border-color:var(--d-line);
    box-shadow:0 12px 32px rgba(0,0,0,.45);
  }
  .cookie-bar p{color:var(--d-muted)}
  .cookie-bar a{color:var(--indigo-d)}
  .cookie-bar .btn-ghost-l{border-color:var(--d-line);color:var(--d-text)}
  .cookie-bar .btn-ghost-l:hover{border-color:var(--d-muted);background:rgba(231,234,242,.06)}
}
