/* base.css - сброс, шрифты, типографика, сетка, body. Мобайл-first. Зависит от tokens.css.
   Ревизия хиро главной 2026-07-26 (hero-vs-2): --vs, потолок высоты блока по 100svh,
   расширяющаяся мера. Высота окна ≥800px не затронута.
   Ревизия 9, 2026-08-12 (v122): вертикальный сдвиг кадра хиро выведен расчетом, а не
   подгонкой по ширинам. Три разных object-position (44/36/25%) заменены на одно
   значение для каждого кадра: 50% 16% для вертикального, 100% 25% для горизонтального.
   Проверено на 243 сочетаниях ширины и высоты, срезанных макушек нет ни на одном.
   Ревизия 10, 2026-08-12 (v124): новый горизонтальный кадр от Геши, вторая редакция
   (люди подвинуты ближе к центру), пропорция 1.75 вместо 2.334. object-position
   горизонтального кадра 50% 18%. Плюс отдельный градиент для короткой секции. *//* ── Self-host шрифты (нулевой зарубежный egress; woff2 заливаются в assets/fonts/) ── */

@font-face {
  font-family: "Manrope";
  src: url("/assets/fonts/manrope/Manrope-Regular.2fd1076c.woff2") format("woff2");
  font-weight: 400; font-display: swap; font-style: normal;
}
@font-face {
  font-family: "Manrope";
  src: url("/assets/fonts/manrope/Manrope-Medium.5d8163c8.woff2") format("woff2");
  font-weight: 500; font-display: swap; font-style: normal;
}
@font-face {
  font-family: "Manrope";
  src: url("/assets/fonts/manrope/Manrope-SemiBold.2412fa43.woff2") format("woff2");
  font-weight: 600; font-display: swap; font-style: normal;
}
@font-face {
  font-family: "Manrope";
  src: url("/assets/fonts/manrope/Manrope-Bold.55414fb2.woff2") format("woff2");
  font-weight: 700; font-display: swap; font-style: normal;
}
@font-face {
  font-family: "Source Serif 4";
  src: url("/assets/fonts/source-serif/SourceSerif4-Regular.d18b3c55.woff2") format("woff2");
  font-weight: 400; font-display: swap; font-style: normal;
}
@font-face {
  font-family: "Source Serif 4";
  src: url("/assets/fonts/source-serif/SourceSerif4-SemiBold.22352e6b.woff2") format("woff2");
  font-weight: 600; font-display: swap; font-style: normal;
}/* ── Ревизия (сдвиг макета, CLS): подложки с подогнанными метриками ──
   font-display: swap означает, что до загрузки woff2 текст рисуется системным шрифтом,
   а потом перерисовывается своим. Метрики не совпадают - абзацы меняют высоту,
   и вся страница дергается. После починки шапки (components.css) это осталось
   ЕДИНСТВЕННОЙ причиной сдвига: в замере все оставшиеся источники - текстовые узлы
   с неизменной высотой строки, но изменившейся высотой блока
   (например /how/ 375px: P.product-hero__lead h 252->223, то есть минус 29px).
   Preload шрифтов отвергнут: три критичных начертания - это 119 КБ, которые на
   мобильном канале конкурируют с CSS и картинками. Вместо этого объявляем
   ПОДЛОЖКУ - тот же системный шрифт, но с принудительно выставленными метриками
   Manrope / Source Serif 4. Тогда дозагрузка своего шрифта не меняет геометрию.
   Итоговая отрисовка НЕ затрагивается: подложка стоит в стеке ПОСЛЕ своего шрифта
   и используется только пока тот не приехал (или если не приехал совсем).

   Числа получены измерением, а не на глаз. Средняя ширина символа взята по РЕАЛЬНОМУ
   тексту сайта (256 270 знаков со всех 50 страниц, теги/скрипты вырезаны) - обычные
   таблицы метрик считают среднее по латинской частотности, а у нас текст русский,
   и для пары Source Serif 4 / Times расхождение между этими двумя способами доходит
   до 6% (по латинице Times уже, по кириллице - нет).
     size-adjust      = средняя ширина своего шрифта / средняя ширина подложки
     ascent/descent   = метрики своего шрифта, деленные на size-adjust
   Замеры (em на наш корпус): Manrope-Regular 0.51612, Manrope-SemiBold 0.53298,
   Manrope-Bold 0.54123; Liberation Sans (= метрики Arial) 0.50799, его Bold 0.54451;
   Source Serif 4 Regular 0.54353, SemiBold 0.55386; Liberation Serif (= метрики
   Times New Roman) 0.46153, его Bold 0.49183; Noto Serif 400 0.54809, 600 0.56109.
   hhea: Manrope 2132/-600/0 при upm 2000; Source Serif 4 1036/-335/0 при upm 1000.

   Подложек под serif две, потому что одним лицом системы не накрываются:
   Windows / macOS / iOS / Linux дают Times New Roman (или метрически совместимые
   Liberation Serif, Tinos, Nimbus Roman), Android - Noto Serif, а он шире Times
   на 19%, и одна общая поправка сломала бы половину устройств. Georgia отдельным
   лицом НЕ объявляем: везде, где она есть, есть и Times New Roman, а ее кириллические
   ширины проверить нечем - оставляем ее просто в конце стека, как было.
   Проверка в браузере: local() резолвится по ПОЛНОМУ имени начертания, поэтому
   у жирных лиц перечислены имена вида "Times New Roman Bold"; последним номером
   стоит светлое имя - если жирного не нашлось, лучше правильная ширина без насыщенности
   на те же 150 мс, чем скачок числа строк. */

@font-face {
  font-family: "Manrope Fallback";
  src: local("Arial"), local("Helvetica Neue"), local("Roboto"), local("Liberation Sans");
  font-weight: 400 500; font-style: normal;
  size-adjust: 101.61%; ascent-override: 104.91%; descent-override: 29.53%; line-gap-override: 0%;
}
@font-face {
  font-family: "Manrope Fallback";
  src: local("Arial Bold"), local("Helvetica Neue Bold"), local("Roboto Bold"),
       local("Liberation Sans Bold"), local("Arial");
  font-weight: 600 900; font-style: normal;
  /* 600 дает 97.88%, 700 - 99.40%; беру середину 98.6% */
  size-adjust: 98.6%; ascent-override: 108.11%; descent-override: 30.43%; line-gap-override: 0%;
}/* Ветка Times New Roman: Windows, macOS, iOS, Linux с Liberation/Tinos */

@font-face {
  font-family: "Source Serif 4 Fallback";
  src: local("Times New Roman"), local("Liberation Serif"), local("Tinos"), local("Nimbus Roman");
  font-weight: 400 500; font-style: normal;
  size-adjust: 117.77%; ascent-override: 87.97%; descent-override: 28.45%; line-gap-override: 0%;
}
@font-face {
  font-family: "Source Serif 4 Fallback";
  src: local("Times New Roman Bold"), local("Liberation Serif Bold"), local("Tinos Bold"),
       local("Nimbus Roman Bold"), local("Times New Roman");
  font-weight: 600 900; font-style: normal;
  size-adjust: 112.61%; ascent-override: 92.00%; descent-override: 29.75%; line-gap-override: 0%;
}/* Ветка Noto Serif: Android */

@font-face {
  font-family: "Source Serif 4 Fallback Noto";
  src: local("Noto Serif"), local("Droid Serif");
  font-weight: 400 500; font-style: normal;
  size-adjust: 99.17%; ascent-override: 104.47%; descent-override: 33.78%; line-gap-override: 0%;
}
@font-face {
  font-family: "Source Serif 4 Fallback Noto";
  src: local("Noto Serif SemiBold"), local("Noto Serif Bold"), local("Droid Serif Bold"),
       local("Noto Serif");
  font-weight: 600 900; font-style: normal;
  size-adjust: 98.71%; ascent-override: 104.95%; descent-override: 33.94%; line-gap-override: 0%;
}/* ── Сброс ── */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body, h1, h2, h3, h4, p, ul, ol, li, figure, blockquote { margin: 0; padding: 0; }/* Списки сбрасываем ТОЧЕЧНО (Б7: глобальный reset убил бы маркеры в юр-документах) */

.site-menu ul, .faq-list{ list-style: none; padding: 0; }
img, picture, svg { max-width: 100%; display: block; }
img { height: auto; }/* P1-12: против искажения при HTML width/height */
button, input, textarea, select { font: inherit; color: inherit; }
a { color: inherit; }/* Юр-документы: маркеры списков возвращаются (Б7) *//* ── Body ── */

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: var(--fw-regular);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-wrap: anywhere;      /* перенос длинных e-mail, адресов и реквизитов */
  min-height: 100vh;            /* fallback для старых браузеров (Б11) */
  min-height: 100svh;           /* small viewport unit для мобильных панелей */
}/* ── Типографика ── */

h1, h2, h3 { line-height: var(--lh-head); font-weight: var(--fw-bold); color: var(--ink); }
h1 { font-size: var(--fs-h1); letter-spacing: -0.01em; }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); font-weight: var(--fw-semibold); }
p { font-size: var(--fs-body); }

a { text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { text-decoration-color: var(--cta-press); }

strong, b { font-weight: var(--fw-semibold); }/* ── Контейнер (читаемая колонка, мобайл-first) ──
   ТОЛЬКО .section - НЕ main>section (Б1: иначе hero и #tarify,
   будучи прямыми <section>, схлопнулись бы в узкую колонку 720px). *//* ── Единый видимый фокус (Б20; для CTA, burger, FAQ, cookie-кнопок, полей, тарифов) ── */

:where(a, button, input, textarea, select, [tabindex]):focus-visible {
  outline: var(--focus-width) solid var(--focus-ring);
  outline-offset: var(--focus-offset);
  border-radius: var(--radius-sm);
}/* На темном hero фокус-кольцо светлое (Б4) */

.site-header[data-variant="on-hero"] :where(a, button):focus-visible,
.hero :where(a, button):focus-visible {
  outline-color: var(--ink-on-dark);
}/* ── Progressive enhancement: меню (Б3, Б4, Б14) ──
   Без JS меню видимо строкой. Бургер и скрытие меню включаются ТОЛЬКО когда
   menu.js поставил .menu-ready (после регистрации обработчиков) - иначе при
   упавшем JS остался бы нерабочий бургер и скрытое меню. */

.burger { display: none; }
html.menu-ready .burger { display: inline-flex; }
html.menu-ready .site-menu { display: none; }

html:not(.menu-ready) .site-header { flex-wrap: wrap; }
html:not(.menu-ready) .site-menu { flex: 1 0 100%; }
html:not(.menu-ready) .site-menu ul { justify-content: flex-start; }/* ── Утилиты ── */

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
[hidden] { display: none !important; }/* ── Статичные тарифные планы (.plans) - общий компонент для /pricing/ и лендингов.
   Всегда развернут, не сворачивается. Данные - из concept §4 / assets/js/tariffs.js. ── */
@media (min-width: 720px) { }
@media (min-width: 720px) { }
.plans__note { font-size: var(--fs-small); line-height: 1.55; color: var(--ink-2); text-align: center; margin: var(--space-4) auto 0; max-width: 640px; }/* ════ Значки оплаты (trust-pay) ════ *//* Зазор 28px - снят с эталона подай-жалобу.рф (там 29px между всеми элементами
   строки: замок→подпись→СБП→МИР→VISA→MC→3-D Secure). Было var(--space-3)=12px,
   из-за чего значки читались как слипшиеся. По вертикали при переносе - 12px. */

.trust-pay { display:flex; flex-wrap:wrap; align-items:center; justify-content:center; gap:12px 28px; margin:var(--space-5) auto 0; }
.trust-pay__label { font-family:var(--sans); font-size:var(--fs-small); font-weight:var(--fw-semibold); color:var(--ink-2); }
.paylogos { display:flex; flex-wrap:wrap; align-items:center; gap:12px 28px; margin:0; padding:0; list-style:none; }
.paylogo { display:inline-flex; align-items:center; justify-content:center; }/* Размеры сняты пиксельно с эталона подай-жалобу.рф (замер bounding box краски на
   скрине оператора): СБП 65×30, МИР 59×17, VISA 53×17, Mastercard 34×27.
   SVG-файлы на обоих сайтах одни и те же - пропорции сходятся до третьего знака
   (2.160 / 3.508 / 3.084 / 1.286), поэтому достаточно задать высоту, ширина следует за ней.
   Единая height для всех - ошибка: компактная марка Mastercard (1.286:1) на одной
   высоте с широкой МИР (3.508:1) выглядит вдвое легче. В эталоне это решено именно
   РАЗНОЙ высотой: компактные выше, широкие словесные ниже. */

.paylogo img { width:auto; object-fit:contain; display:block; }
.paylogo img[src*="pay-sbp"]        { height:30px; }/* → 65×30 */
.paylogo img[src*="pay-mir"]        { height:17px; }/* → 60×17 */
.paylogo img[src*="pay-visa"]       { height:17px; }/* → 52×17 */
.paylogo img[src*="pay-mastercard"] { height:27px; }/* → 35×27 */
.trust-pay__secure { font-family:var(--sans); font-size:var(--fs-kicker); font-weight:var(--fw-semibold); color:var(--ink-2); border:1px solid var(--line); border-radius:var(--radius-sm); padding:3px 8px; }/* Замочек перед «Защищенная оплата» - как в эталоне. */

.trust-pay__label { display:inline-flex; align-items:center; gap:6px; }
.trust-pay__label::before { content:""; width:16px; height:16px; flex:0 0 auto; background:currentColor;
  -webkit-mask:url("/assets/icons/lock.e49a4ff9.svg") center/contain no-repeat; mask:url("/assets/icons/lock.e49a4ff9.svg") center/contain no-repeat; }/* /pricing/: значки платежек и примечание «Разовый платеж…» стояли впритык
   (margin-bottom у .trust-pay нет, margin-top у .legal-note нет → зазор 0).
   Разводим только в этой паре - на лендингах .trust-pay замыкает секцию,
   и собственный margin там менять нельзя, чтобы не сдвинуть согласованный десктоп. */

.trust-pay + .legal-note { margin-top: var(--space-5); }/* ════ Cookie-баннер (компактная карточка) ════ */

.cookie-banner[hidden]{ display:none; }
.cookie-banner { --fon-tihiy:var(--bg); --fon-navedeniya:var(--karta); position:fixed; left:var(--gutter); right:var(--gutter); bottom:var(--gutter); z-index:var(--z-banner); max-width:430px; margin-inline:auto; background:var(--surface); color:var(--ink); border:1px solid var(--line); border-radius:var(--radius); box-shadow:0 8px 28px rgba(44,39,35,.18); padding:var(--space-4); }
@media (min-width:560px){ .cookie-banner { left:auto; margin-inline:0; } }
.cookie-banner__text { font-size:var(--fs-small); line-height:1.5; color:var(--ink); margin:0 0 var(--space-3); }
.cookie-banner__text a { color:var(--teal); }
.cookie-banner__actions { display:flex; gap:var(--space-2); }/* Кнопки баннера. Кнопки модалки сюда НЕ входят: там теперь общий компонент .cta,
   а селектор .cookie-modal__actions button (0,1,1) перебил бы .cta (0,1,0) по специфичности. */

.cookie-banner__actions button { min-height:44px; padding:0 var(--space-4); border-radius:var(--radius); font-family:var(--sans); font-weight:var(--fw-semibold); font-size:var(--fs-small); cursor:pointer; border:1px solid transparent; }
[data-cookie="all"] { background:var(--cta); color:var(--cta-ink); }
[data-cookie="details"] { background:transparent; color:var(--ink); border-color:var(--field-border); }/* ════ Cookie-модалка ════ */

.cookie-modal[hidden]{ display:none; }
.cookie-modal { position:fixed; inset:0; z-index:var(--z-modal); display:flex; align-items:center; justify-content:center; padding:var(--gutter); }
.cookie-modal__overlay { position:absolute; inset:0; background:var(--overlay); }
.cookie-modal__panel { position:relative; z-index:1; width:100%; max-width:460px; max-height:90dvh; overflow-y:auto; background:var(--bg); border-radius:var(--radius-lg); box-shadow:0 12px 40px rgba(44,39,35,.28); padding:var(--space-6) var(--space-5); }
.cookie-modal__title { font-family:var(--serif); font-size:var(--fs-h2); margin:0 0 var(--space-2); }
.cookie-cats { list-style:none; margin:0 0 var(--space-4); padding:0; display:grid; gap:var(--space-3); }
.cookie-cat label { display:flex; gap:var(--space-3); align-items:flex-start; cursor:pointer; }
.cookie-cat input { margin-top:2px; width:20px; height:20px; flex:0 0 auto; accent-color:var(--teal); }
.cookie-cat span { font-size:var(--fs-small); line-height:1.45; color:var(--ink-2); }
.cookie-cat b { color:var(--ink); font-weight:var(--fw-semibold); }/* «Необходимые» - отмечены и заблокированы: категория показана честно, но не выключается. */

.cookie-cat--always label { cursor:default; }
.cookie-cat input:disabled { accent-color:var(--ink-2); opacity:.55; cursor:default; }/* Действия модалки (эталон - подай-жалобу.рф): крупная основная кнопка + текстовая ссылка рядом. *//* justify-content виден только когда строка переносится: пока кнопка и ссылка стоят
   в ряд, .cta с flex-grow:1 съедает весь свободный зазор, и центрировать нечего.
   На узких экранах ссылка уезжает под кнопку - там центр ее и подхватывает. */

.cookie-modal__actions { display:flex; flex-wrap:wrap; align-items:center; justify-content:center; gap:var(--space-4); }
.cookie-modal__actions .cta { flex:1 1 200px; width:auto; }
.cookie-modal__link { flex:0 0 auto; min-height:var(--tap-min); display:inline-flex; align-items:center;
  background:none; border:0; padding:0; font-family:var(--sans); font-size:var(--fs-small); font-weight:var(--fw-medium);
  color:var(--ink-2); text-decoration:underline; cursor:pointer; }
.cookie-modal__link:hover { color:var(--ink); }
.cookie-modal__close { position:absolute; top:8px; right:10px; width:40px; height:40px; border:0; background:transparent; color:var(--ink-2); cursor:pointer; display:inline-flex; align-items:center; justify-content:center; }
.cookie-modal__close::before { content:""; width:20px; height:20px; background:currentColor;
  -webkit-mask:url("/assets/icons/close.42095ac3.svg") center/contain no-repeat; mask:url("/assets/icons/close.42095ac3.svg") center/contain no-repeat; }/* ════ Футер: кнопка cookie + РКН + разделы ════ */
.footer-cookie-btn { display:inline-flex; align-items:center; min-height:40px; background:transparent; border:1px solid var(--field-border); border-radius:var(--radius); padding:0 var(--space-4); font-family:var(--sans); font-size:var(--fs-small); font-weight:var(--fw-semibold); color:var(--ink); cursor:pointer; margin:var(--space-2) 0; }
.footer-cookie-btn:focus-visible, .cookie-banner button:focus-visible, .cookie-modal button:focus-visible, .cookie-cat input:focus-visible { outline:var(--focus-width) solid var(--focus-ring); outline-offset:var(--focus-offset); border-radius:6px; }/* ════ Hero главной страницы (фото + текст поверх) ════ *//* Высота считается от ШИРИНЫ (42vw), а не от высоты окна: 42vw < 1/2.334 - пропорции
   фото (1916×821), поэтому кадр никогда не режется по горизонтали и сцена видна целиком.
   82svh - страховка для низких окон (тогда режется по вертикали, что безопасно). *//* --vs - насколько окно ниже опорных 800px (тот же прием, что на лендингах, см.
   components.css «HERO»). При высоте ≥800px --vs = 0 и все ниже равно прежнему
   ДО ПИКСЕЛЯ. Потолок calc(100svh - --header-h) нужен потому, что нижний край
   clamp() был 420px и не зависел от высоты окна: на 1280x440 хиро 420px + шапка 64px
   давали 484px - низ блока уезжал за первый экран (замер до правки: худший перелив
   134px, 28 битых размеров). Шапка на главной в потоке, поэтому вычитаем ее. */

.home-hero--photo { --vs:max(0px, calc(800px - 100svh)); position:relative; width:100%; min-height:min(clamp(420px,min(42vw,82svh),760px), calc(100svh - var(--header-h) - 2px)); display:flex; overflow:hidden; }
.home-hero__media { position:absolute; inset:0; z-index:0; }/* <picture> по умолчанию inline и без высоты - из-за этого height:100% у img не разрешался,
   фото рисовалось в натуральной пропорции и под ним оставалась пустая полоса. */

.home-hero__media picture { display:block; width:100%; height:100%; }/* Ревизия 10, 2026-08-12. Новый горизонтальный кадр 1916x1095 (пропорция 1.75).
   Замерено по самому файлу сеткой в 1 процент (кадр от 12.08, вторая редакция -
   люди подвинуты ближе к центру): макушки 16.8% высоты, подбородки 44%, руки на
   столе 64..68%; люди по X занимают 17.5..83%, центр группы ровно на 50%.
   Пропорция файла выбрана не произвольно: высота секции на десктопе задана как
   min(100vh, 58vw), поэтому пропорция окна не бывает уже 1.724 - а значит при
   1.75 у файла на типовом десктопе виден почти весь кадр целиком, и обрезать по
   бокам просто нечего. Прежний кадр 2.334 при том же окне показывал только 74%
   ширины, отсюда и брались вечные проблемы с крайними людьми.
   По X ЦЕНТР (люди стоят по центру, стены слева больше нет), по Y 18% - середина
   полосы [14.7..23.0], допустимой на всех окнах с пропорцией до 5. Проверка -
   hero_polosa.js, 243 сочетания. */

.home-hero__media img { width:100%; height:100%; object-fit:cover; object-position:50% 18%; display:block; }
.home-hero--photo::before { content:""; position:absolute; inset:0; z-index:1;
  background:linear-gradient(90deg, rgba(251,246,238,.92) 0%, rgba(251,246,238,.78) 28%, rgba(251,246,238,.25) 52%, rgba(251,246,238,0) 72%); }
.home-hero__inner { position:relative; z-index:2; width:100%; max-width:var(--container-wide); margin:0 auto; padding:max(20px, calc(var(--space-8) - var(--vs) * 0.10)) var(--gutter); display:flex; flex-direction:column; justify-content:center; }/* Мера расширяется на низком окне (+0.45px на каждый недостающий пиксель высоты,
   потолок 56vw): 56% - граница, за которой светлое затемнение слабее .25 и темный
   текст ложится на людей. Разбивку заголовка на высоких окнах это не меняет. */

.home-hero__text { max-width:max(min(560px,47vw), min(calc(30rem + var(--vs) * 0.45), 56vw)); }
.home-hero__text h1 { font-family:var(--serif); font-weight:600; font-size:max(24px, calc(clamp(1.75rem,3.6vw,2.9rem) - var(--vs) * 0.050)); line-height:1.14; color:var(--ink); margin:0 0 max(6px, calc(14px - var(--vs) * 0.014)); }
.home-hero__text .home-sub { font-size:max(13px, calc(var(--fs-body) - var(--vs) * 0.010)); line-height:1.5; color:var(--ink-2); margin:0; max-width:480px; }

@media (min-width:641px) and (max-width:1023px){/* Планшет: колонки рядом с людьми уже нет - текста и сцены не хватает по ширине.
     Поэтому берем тот же прием, что и на мобилке: фото во всю ширину, текст снизу
     на темной подложке. Шапка остается обычной. Десктоп (≥1024) не затрагивается. *//* 60vw - предел, при котором обрез идет только по пустой стене слева (0..32%),
     и все четверо остаются в кадре целиком. Выше - начинает резать людей.
     calc(100svh - 73px) - потолок по высоте окна: шапка в этом диапазоне ровно 73px
     (замерено на 641…1023), и без этого ограничения хиро в 600px + шапка вылезали
     за первый экран на невысоких окнах - лид обрезался нижней кромкой.
     Обрез по вертикали безопасен: сверху потолок, снизу стол. */

  .home-hero--photo { min-height:min(clamp(380px,60vw,600px), calc(100svh - var(--header-h) - 2px)); align-items:flex-end; }
  .home-hero--photo::before { background:linear-gradient(180deg,
    rgba(20,17,14,0) 30%, rgba(20,17,14,.30) 52%, rgba(20,17,14,.74) 80%, rgba(20,17,14,.93) 100%); }
  .home-hero__inner { justify-content:flex-end; padding:max(14px, calc(var(--space-6) - var(--vs) * 0.05)) var(--gutter) max(16px, calc(var(--space-7) - var(--vs) * 0.07)); }
  .home-hero__text { max-width:none; }
  .home-hero__text h1 { color:var(--ink-on-dark); font-size:max(22px, calc(clamp(1.7rem,3.5vw,2.25rem) - var(--vs) * 0.045)); margin-bottom:max(5px, calc(10px - var(--vs) * 0.010)); }
  .home-hero__text .home-sub { color:var(--ink-on-dark-2); max-width:62ch; }
}

@media (max-width:640px){/* Главная использует общий компонент шапки лендингов без локальных переопределений. *//* Ревизия 3.5. Было min-height:100svh; min-height:100dvh - вторая строка перебивала
     первую, и в браузерах с поддержкой dvh (все актуальные) высота хиро становилась
     ДИНАМИЧЕСКОЙ: при прокрутке в iOS Safari и Android Chrome адресная строка уезжает,
     dvh растет на 60-100px, блок тянется - а текст прижат к низу (align-items:flex-end),
     поэтому заголовок и лид физически ползут вниз прямо под пальцем. Это же скачок
     в CLS. Единственный dvh на всем сайте был здесь: планшетный диапазон 641-1023
     (строки 367-369) уже жил на svh. Убираем dvh, оставляем стабильный svh
     и обычный vh как запасной для браузеров без svh (Safari < 15.4) -
     ровно тот же двухстрочный прием, что в строках 66-67, 329-330, 368-369. */

  .home-hero--photo { min-height:100vh; min-height:100svh; aspect-ratio:auto; align-items:flex-end; }
  .home-hero__media { position:absolute; inset:0; }/* Ревизия 9. ВЕРТИКАЛЬНЫЙ кадр 941x1672: макушки на 15.2% высоты, подбородки
     около 30%, кромка стола 40%. На телефоне в портрете кадр виден по высоте
     целиком (окно уже, чем 1:1.777) и значение ни на что не влияет; оно работает
     только в низком окне - ландшафт или подъехавшие панели браузера. Прежние 44%
     там опускали верх видимого окна ниже макушек. 16% - единственное значение,
     которое держит и верх, и низ на всей сетке от 320x360 до 1023x1440. */

  .home-hero__media img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:50% 16%; }
  .home-hero--photo::before { background:linear-gradient(180deg,
    rgba(20,17,14,0) 34%, rgba(20,17,14,.34) 56%, rgba(20,17,14,.76) 82%, rgba(20,17,14,.93) 100%); }/* Нижний отступ 24px вместо 48px - по просьбе оператора текст опущен ниже:
     блок съезжает вниз ровно на 24px и меньше наезжает на лица нижнего ряда.
     Отличие от лендингов (там 48px) сделано намеренно и только для главной. *//* padding-top резервирует шапку: на главной мобилке она тоже position:absolute
     и лежит НА фото. На высоком окне резерв невидим (блок прижат вниз), на низком -
     не дает первой строке уехать под логотип. */

  .home-hero__inner { justify-content:flex-end; max-width:none; padding:calc(var(--header-h) + var(--space-2)) var(--gutter) max(14px, calc(var(--space-5) - var(--vs) * 0.030)); }
  .home-hero__text { max-width:none; }
  .home-hero__text h1 { color:var(--ink-on-dark); font-size:max(20px, calc(clamp(1.55rem,6vw,2rem) - var(--vs) * 0.040)); line-height:1.16; margin-bottom:max(5px, calc(10px - var(--vs) * 0.010)); }
  .home-hero__text .home-sub { color:var(--ink-on-dark-2); max-width:none; }
}/* Ревизия 10: здесь стоял кремовый горизонтальный градиент для низкого окна на
   десктопе - остаток той поры, когда текст хиро был темным. С ревизии 8 текст на
   десктопе белый, а подложку дает .home-page .home-hero--photo::before, у которой
   специфичность выше (два класса против одного). То есть правило было мертвым:
   ни на одном размере оно не применялось. Снято как рудимент. *//* ─────────────────────────────────────────────────────────────
   Ревизия 7, 2026-08-08, по просьбе оператора: текстовый блок хиро опущен ВНИЗ,
   как это уже сделано на планшете и мобилке.

   Порог 1024: после пересъемки лица поднялись в верхнюю половину кадра, а низ
   занял стол. Поэтому опущенный блок ложится на столешницу, а не на людей,
   и это верно на всех десктопных ширинах, включая 1024x768. Замерено на стенде:
   люди занимают 14-58% высоты кадра, ниже - только стол. */

@media (min-width: 1024px) {
  .home-page .home-hero__inner { justify-content: flex-end; }
}/* Hyphen markers for unclassed textual lists outside legal documents. */

.todo__block ul { list-style: none; padding-left: 0; }
.todo__block ul > li { position: relative; padding-left: 1.15em; }
.todo__block ul > li::before { content: "-"; position: absolute; left: 0; }/* ── STABILITY PASS v55: touch target for cookie settings on every page ── */

.footer-cookie-btn { min-height: var(--tap-min); }
.cookie-banner__actions button { min-height: var(--tap-min); }/* INPUT MODALITY STABILITY - одинаковая работа мышью, клавиатурой и касанием. */

:where(a, button, input, textarea, select, summary, [role="button"], [role="tab"]) {
  touch-action: manipulation;
}/* V118 - восстановление согласованной геометрии hero главной.
   Десктоп снова занимает первый экран; узкий планшет использует мобильную
   композицию, чтобы четыре человека и контент не конфликтовали. */

@media (min-width: 1024px) {
  /* Ревизия 8, 2026-08-08. Потолок высоты 58vw.
     Кадр прижат вправо, а масштаб при object-fit:cover задается ВЫСОТОЙ окна.
     Поэтому на узком окне картинка не уменьшается, показывается меньший ее кусок,
     и группа уезжает влево - прямо под текст. Замер левого края группы:
     3440 - 50% ширины экрана, 1920 - 33%, 1280 - 25%, 1024 - всего 10%.
     Потолок 58vw связывает высоту с шириной, и масштаб перестает скакать:
     1024 - 30%, 1280 - 30%, 1440 - 30%, от 1600 - 33%. Композиция одна на всех
     десктопах. Там, где 58vw и так больше высоты окна (все обычные 16:9 от 1600),
     значение не меняется вовсе. */
  .home-page .home-hero--photo {
    /* Ревизия 11, 2026-08-12. Потолок высоты был 58vw и делал хиро главной ниже
       хиро лендингов на одном и том же окне (замер 1440x900: 835 против 900).
       Оператор потребовал одинаковую высоту. Совсем снять потолок нельзя: он
       ограничивает пропорцию окна снизу, а при узком окне кадр 1.75 обрезается
       по бокам и крайние люди уходят за кромку (замер: на 1024x1440 видно всего
       40% ширины кадра). Потолок поднят до 70vw - это ровно та величина, при
       которой пропорция окна не бывает уже 1.43, а при 1.43 видно 81.7% ширины
       кадра (X 9.1..90.9%) против людей на 17.5..83%.
       Практический итог: на любом обычном десктопе (16:9, 16:10, окно оператора
       1344x940) потолок не срабатывает и высота равна высоте лендинга; работает
       он только на непривычно высоком окне, где иначе поехала бы композиция. */
    /* Ревизия 12, 2026-08-13. Потолок снят совсем: оператор второй раз потребовал,
       чтобы высота хиро главной СОВПАДАЛА с высотой хиро лендингов на одном и том
       же окне. Любой потолок по ширине эту задачу ломает по определению - на узком
       окне он делает секцию ниже. Плата за снятие: на непривычно высоком и узком
       окне кадр 1.75 обрезается по бокам сильнее. Замер после правки - ниже в
       отчете hero_polosa; на всех обычных десктопах (16:9, 16:10, 3:2) разницы нет,
       потому что там 100svh и так было меньше потолка. */
    min-height: 100vh;
    min-height: 100svh;
  }
  .home-page .home-hero__inner {
    padding-top: calc(var(--header-h) + clamp(1rem, 3vh, 2.5rem));
    padding-bottom: clamp(1.5rem, 5vh, 4rem);
  }
  .home-page .home-hero__text {
    max-width: min(660px, 54vw);
  }
  .home-page .home-hero__text .home-sub {
    max-width: 58ch;
  }/* Ревизия 7, 2026-08-08. Вуаль переложена под опущенный вниз текст.
     Было: только горизонтальный ход, слева направо. Он рассчитан на текст по центру
     высоты - там заголовок ложился на пустую стену. После переноса блока вниз под
     ним оказался крайний мужчина, а к его лицу горизонтальная вуаль ослабевала уже
     до .25, и темный заголовок ложился прямо на лицо.
     Стало: два слоя. Вертикальный уплотняет НИЗ кадра - ровно там, где стоит текст;
     до 34% высоты он полностью прозрачен, поэтому лица, стоящие выше, не гасятся.
     Горизонтальный слой сохранен, чтобы правая часть кадра осталась открытой. *//* Ревизия 7, 2026-08-08. Общей заливки кадра на десктопе больше НЕТ.

     Было: сплошной градиент на всю секцию. Сначала горизонтальный (он выбеливал
     людей - на 1024x768 видно только правые 57% кадра, и люди идут уже с 10%
     экрана), потом вертикальный - тот залил кремом всю нижнюю половину страницы.
     Оба варианта гасили фотографию целиком ради трех строк текста.

     Стало: подложка привязана к самому текстовому блоку и живет вместе с ним -
     см. .home-hero__text::before ниже. Фотография остается нетронутой везде,
     кроме пятна под текстом. *//* Ревизия 8, 2026-08-08. Хиро главной приведен к схеме лендингов: тот же токен
     --hero-scrim (темный градиент к низу) плюс белый текст поверх него. Так уже
     сделано на /men-me/, /decision/ и на мобильной версии самой главной.

     Почему это лучше кремовой вуали: на светлой подложке темный текст требует
     плотности .72 и выше, и она ложится на людей. Темный градиент, наоборот,
     садится на столешницу внизу кадра, где людей уже нет, а белый текст на нем
     читается с большим запасом. Верх кадра остается нетронутым - до 38% высоты
     градиент почти прозрачен. */

  .home-page .home-hero--photo::before { background: var(--hero-scrim); }
  .home-page .home-hero__text h1 { color: var(--ink-on-dark); }
  .home-page .home-hero__text .home-sub { color: var(--ink-on-dark-2); }
}/* Ревизия 10, 2026-08-12. Короткая секция на десктопе: текст стоит ВЫШЕ по кадру.
   Высота секции = min(100vh, 58vw), поэтому на узком или низком окне она мала, а
   текстовый блок в ней тот же - и заголовок начинается уже с 39% высоты вместо 61%
   на 1920x1080. Базовый --hero-scrim там дает всего .17, а новый кадр под текстом
   светлый (столешница и бежевый свитер вместо прежней темной стены): замерено на
   чистом фото, контраст без вуали 1.35 у заголовка и 1.26 у подзаголовка.
   Требуемая плотность посчитана из композита фото*(1-a) + (20,17,14)*a по 95-му
   перцентилю яркости под каждым блоком: заголовку нужно .37 с отметки 39%,
   подзаголовку .58 с отметки 61%. Отсюда стопы ниже. Верхние 30% кадра не
   затрагиваются - лица остаются нетронутыми.
   Ревизия 11: после снятия потолка 58vw высота секции равна высоте окна, поэтому
   условие теперь только по высоте - до 900px включительно. */

@media (min-width: 1024px) and (max-height: 900px) {
  .home-page .home-hero--photo::before {
    background: linear-gradient(180deg,
      rgba(20,17,14,0) 0%,
      rgba(20,17,14,.10) 30%,
      rgba(20,17,14,.38) 39%,
      rgba(20,17,14,.60) 61%,
      rgba(20,17,14,.88) 100%);
  }
}/* 641-1023 px использует вертикальную композицию: широкое фото при высоте
   первого экрана неизбежно обрезало крайнего левого человека. Вертикальный
   исходник сохраняет всех четверых и тот же дизайн hero. */

@media (min-width: 641px) and (max-width: 1023px) {
  .home-page .site-header {
    position: absolute;
    inset: 0 0 auto;
    width: 100%;
    background: linear-gradient(180deg, rgba(20,17,14,.46) 0%, rgba(20,17,14,.18) 58%, rgba(20,17,14,0) 100%);
    border-bottom-color: transparent;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .home-page .site-header .logo { color: var(--ink-on-dark); }
  .home-page .site-header .burger span { background: var(--ink-on-dark); }
  .home-page .site-header .site-menu a { color: var(--ink-on-dark); }
  .home-page .home-hero--photo {
    min-height: 100vh;
    min-height: 100svh;
    align-items: flex-end;
  }
  .home-page .home-hero__media img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Ревизия 9: то же значение, что и в диапазоне до 640px. Разные значения по
       поддиапазонам были источником срезанных макушек - см. комментарий выше. */
    object-position: 50% 16%;
  }
  .home-page .home-hero--photo::before {
    background: linear-gradient(180deg,
      rgba(20,17,14,0) 28%,
      rgba(20,17,14,.32) 50%,
      rgba(20,17,14,.76) 78%,
      rgba(20,17,14,.94) 100%);
  }
  .home-page .home-hero__inner {
    justify-content: flex-end;
    max-width: none;
    padding: calc(var(--header-h) + var(--space-2)) var(--gutter) var(--space-5);
  }
  .home-page .home-hero__text { max-width: none; }
  .home-page .home-hero__text h1 {
    color: var(--ink-on-dark);
    font-size: clamp(1.45rem, 4.2vw, 1.9rem);
    line-height: 1.16;
  }
  .home-page .home-hero__text .home-sub {
    color: var(--ink-on-dark-2);
    max-width: 62ch;
  }
}/* Ревизия 9, 2026-08-12. Здесь стояли два подгоночных блока: 36% для планшета
   701-1023 и 25% для низкого окна телефона. Оба сняты. Причина: подгонка по
   поддиапазонам ширины не работает в принципе - вертикальный сдвиг кадра зависит
   не от ширины окна, а от его ПРОПОРЦИИ, и одна и та же ширина при разной высоте
   требует разных значений. Отсюда и брались срезанные макушки на 1002x905 при
   формально «настроенном» диапазоне. Вместо трех подогнанных значений - одно,
   выведенное расчетом на всей сетке (см. комментарии у самих правил). *//* ═══════════════════════════════════════════════════════════
   Хиро главной, ширины до 1023px: затемнение привязано к ТЕКСТОВОМУ БЛОКУ.
   Тот же прием, что уже принят на лендингах (components.css, «HERO», правило
   .hero__overlay ниже 701px) - оператор просил довести главную «так же».

   Почему прежнего затемнения не хватало. Градиент .home-hero--photo::before
   привязан к контейнеру: он начинает темнеть с 34% высоты хиро. А сам блок
   .home-hero__inner на этих ширинах - flex-элемент с align-items:flex-end,
   его высота равна высоте содержимого, поэтому верх блока гуляет: замер по
   сетке 11 ширин x 6 высот дал верх от 0 до 0.58 высоты хиро. На низких окнах
   (400-598px) содержимое перестает помещаться, блок начинается от самой верхней
   кромки, и заголовок оказывается в той части кадра, где затемнения еще нет
   вообще. Замер до правки: h1 минимум 1.01 (то есть текста на фоне физически
   не видно), подзаголовок 0.73; ниже цели 129 ячеек из 150.
   Ровно эта же причина была на лендингах, и решение то же: градиент, привязанный
   к блоку, едет вместе с текстом сам.

   Кривая: 0.66 * smoothstep(u / 0.20), дальше полка 0.66 (u - доля высоты блока,
   smoothstep(x) = x^2*(3-2x)). Smoothstep - нулевая производная на обоих концах,
   поэтому у верхней кромки блока нет излома и не появляется полоса Маха.
   Параметры не назначены, а найдены перебором A от 0.30 до 0.86 и колена k от
   0.08 до 0.46 по критерию «минимальная средняя альфа при выполнении цели»
   на всех 132 замерах (11 ширин x 6 высот x 2 элемента). Двухсегментный вариант
   с доходом до B у нижней кромки просчитан отдельно и сошелся в ту же полку
   (B = A), то есть дополнительного затемнения внизу не требуется.
   Цель - линейка лендингов: h1 >= 4.6, подзаголовок >= 4.2 по WCAG на 99-м
   процентиле яркости фона под маской глифов.
   Композит с ::before считается как 1-(1-a1)(1-a2).

   Правило живет строго до 1023px. Утвержденный десктоп (>=1024px) не затронут:
   там .home-hero__inner растянут на всю высоту хиро и «привязка к тексту»
   вырождается в привязку к контейнеру - это отдельный случай, вынесен в отчет.
   ═══════════════════════════════════════════════════════════ */

@media (max-width: 1023px) {
  .home-hero__inner {
    background: linear-gradient(180deg,
      rgba(20,17,14,0)      0%,
      rgba(20,17,14,.040)   3%,
      rgba(20,17,14,.143)   6%,
      rgba(20,17,14,.281)   9%,
      rgba(20,17,14,.428)  12%,
      rgba(20,17,14,.557)  15%,
      rgba(20,17,14,.632) 17.5%,
      rgba(20,17,14,.66)   20%,
      rgba(20,17,14,.66)  100%);
  }
}/* ═══════════════════════════════════════════════════════════
   ПЕЧАТЬ (ревизия 3.6). Раньше печатных стилей на сайте не было вообще:
   grep "@media print" по assets/css давал ноль.

   Почему это не косметика. Согласие на обработку ПДн, политика и оферта -
   документы, которые человек по закону вправе получить в читаемом виде, и их
   печатают (или сохраняют в PDF) в спорах, при подаче обращения в РКН и просто
   «чтобы было». На экранных стилях распечатка ломается тремя способами, и все
   три проверены на бумажном рендере:
     1) .legal-table-wrap имеет overflow-x:auto, а .legal-table - min-width:520px.
        На экране лишнее прокручивается, на бумаге прокрутки нет: то, что не
        влезло в ширину страницы, просто ОБРЕЗАЕТСЯ и в распечатке отсутствует.
        Плюс первая колонка объявлена white-space:nowrap и не дает таблице сжаться.
     2) .legal-page - флекс-колонка с min-height:100svh и .legal-main{flex:1 0 auto}.
        В печатном контексте svh равен высоте страницы, и колонка тянется на всю
        страницу целиком, добавляя пустой лист.
     3) шапка, футер, баннер и модалка cookie печатаются как есть и съедают
        первую страницу; ссылки уходят на бумагу бирюзовыми и без адресов,
        то есть распечатку нельзя проверить.

   Правила живут только внутри @media print и на экранный рендер не влияют
   ни на одном разрешении - утвержденный десктоп не затронут по определению.
   ═══════════════════════════════════════════════════════════ */

@media print {
  @page { size: A4 portrait; margin: 18mm 16mm 20mm; }

  html, body { background: #fff; color: #000; }
  body { font-size: 11pt; line-height: 1.45; }/* Заливки, тени и подложки на бумаге снижают контраст текста и тратят тонер.
     Гасим централизованно, а не перечислением селекторов: список компонентов
     будет расти, а правило должно продолжать работать. */

  *, *::before, *::after {
    background: transparent !important;
    box-shadow: none !important;
    text-shadow: none !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }/* Служебная обвязка. */

  .site-header, .site-footer, .cookie-banner, .cookie-modal,
  .footer-cookie-btn, .burger, .site-menu { display: none !important; }/* Возврат в обычный поток - иначе пустая страница-хвост (причина 2 выше). */

  .legal-page { display: block; min-height: 0; }
  .legal-main { max-width: none; margin: 0; padding: 0; }
  .balanced-page-spacing .legal-main { padding-bottom: 0; }/* Таблицы: распускаем прокручиваемую обертку и снимаем nowrap с первой
     колонки, иначе часть содержимого не попадает на лист (причина 1 выше). */

  .legal-table-wrap { overflow: visible !important; border: 0 !important; }
  .legal-table { min-width: 0 !important; width: 100% !important; font-size: 9.5pt; }
  .legal-table th, .legal-table td { border: 1px solid #888 !important; padding: 5pt 6pt; }
  .legal-page.legal-document .legal-table th:first-child,
  .legal-page.legal-document .legal-table td:first-child { white-space: normal !important; }
  thead { display: table-header-group; }/* Разрывы страниц: заголовок не должен оставаться один в конце листа,
     строка таблицы и врезка не должны разрываться пополам. */

  h1, h2, h3 { break-after: avoid-page; page-break-after: avoid; }
  h1, h2, h3, tr, li, .legal-note{
    break-inside: avoid; page-break-inside: avoid;
  }
  p, li { orphans: 3; widows: 3; }/* Ссылки на бумаге не кликаются: снимаем цвет и подчеркивание, но раскрываем
     адрес - распечатка юридического документа должна быть проверяемой. */

  a { color: #000 !important; text-decoration: none !important; }
  .legal-main a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 8.5pt; word-break: break-all; }
  .legal-main a[href^="/"]::after   { content: " (persavel.ru" attr(href) ")"; font-size: 8.5pt; }
  .legal-main a[href^="#"]::after,
  .legal-main a[href^="mailto:"]::after,
  .legal-main a[href^="tel:"]::after{ content: none; }/* Рамки, несущие смысл (врезка, дисклеймер, оглавление), сохраняем -
     они отделяют вспомогательный текст от тела документа. */

  .legal-note { border-left: 2pt solid #888 !important; padding: 7pt 9pt; }

  .legal-head h1 { font-size: 18pt; }
  .legal-section h2 { font-size: 13pt; }
  .legal-section h3 { font-size: 11.5pt; }
  .legal-meta, .legal-note{ font-size: 9.5pt; }/* overflow-wrap:anywhere из экранных стилей рвет слово в произвольном месте;
     на бумаге это читается плохо - оставляем перенос только длинных токенов. */

  .legal-page.legal-document .legal-main > p,
  .legal-page.legal-document .legal-section p,
  .legal-page.legal-document .legal-section li { overflow-wrap: break-word; }

  img, picture, svg { max-width: 100% !important; break-inside: avoid; }
}/* ═══════════════════════════════════════════════════════════
   Ревизия 11, 2026-08-12. Три правки по разбору боевого сайта.
   ═══════════════════════════════════════════════════════════ *//* 1. Вторая кнопка хиро главной приведена к кнопке лендингов - правка сделана
   там, где живет каноническое объявление: landing-pages.css грузится последним и
   перебивал бы любое правило равной специфичности, поставленное здесь. *//* 2. Якорные цели не должны уезжать под шапку.
   На главной шапка position:absolute и после перехода уходит вверх со скроллом -
   поэтому #directions живет с scroll-margin-top:0 и это правильно. На лендингах
   шапка position:fixed, ее низ на 64px, а верх целевого блока встает на 0 -
   заголовок раздела оказывается под шапкой. Замерено на /men-me/#tarify.
   Правило чинит и переход по ссылке с другой страницы, и клик внутри страницы. *//* Ревизия 2, 2026-08-13. Прежнее правило вешало отступ на ВСЕ якорные цели
   одинаково, и на продуктовых страницах (about, how, pricing, faq) это давало
   80px пустоты сверху: шапка там при прокрутке вниз прячется, перекрывать нечему,
   а отступ все равно резервировался. Замер после перехода: верх цели 80, низ
   шапки 0. Эталон оператора - /#directions на главной, где верх цели 0.
   Стало: отступ ровно там, где шапка после перехода реально видна, и ровно на ее
   высоту, без добавочных 16px.
     главная (шапка absolute, уезжает) - 0, как эталон;
     продуктовые (шапка прячется при прокрутке вниз) - 0;
     лендинги (шапка видна, низ на 64) - 64, заголовок встает вплотную под ней. */

/* Ревизия 3, 2026-08-15. Прежнее правило ограничивалось лендингами, потому что было
   замерено утверждение «на продуктовых страницах шапка при прокрутке вниз прячется,
   перекрывать нечему». Утверждение неверно: у продуктовых и юридических страниц шапка -
   обычная position:sticky с top:0, она видна ВСЕГДА. Замер на /how/#report-examples:
   верх цели 0, низ шапки 73 - то есть 73 пикселя блока уезжали под шапку, и человек
   после перехода видел обрезанный заголовок. Поймано на боевом 15.08.2026.

   Стало: отступ у всех якорных целей, кроме главной. Правило по [id], а не по списку
   идентификаторов: список ровно этим и провинился - новый якорь в него не попадал, и
   поломка возвращалась молча. scroll-margin действует только в момент прокрутки к
   элементу, поэтому распространить его на все элементы с id безвредно.

   Главная - исключение и это правильно: там шапка position:absolute и после перехода
   уходит вверх вместе со страницей, перекрывать действительно нечем. Эталон оператора -
   /#directions с верхом цели в 0. */
body [id] {
  scroll-margin-top: var(--header-h);
}/* Ревизия 4, 2026-08-17. Правило выше ставит под шапку ВЕРХНИЙ КРАЙ блока-цели, а
   идентификатор обычно висит на секции, у которой свой верхний отступ. Замеры до
   правки: просвет между низом шапки и заголовком 89 на /men-me/#tarify, 115 на
   /how/#report-examples, 116 на /pricing/#plans и /about/#why-persavel, 117 на
   /pricing/#premium-examples - против эталонных 41 у /#directions, где идентификатор
   стоит на блоке заголовка, а не на секции. Экран открывался пустотой.

   Лечение - вычесть собственный отступ секции. Прочитать padding в calc() нельзя,
   поэтому он продублирован переменной --sec-pad-top в том же правиле, где задается:
   в product-pages.css у .product-section (включая все медиазапросы) и в tarify.css
   у #tarify. Секция без переменной ведет себя как раньше, хуже не становится.

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

   Главная больше НЕ исключение. Исключение имело смысл, пока шапка главной уезжала со
   скроллом навсегда: перекрывать было нечем. Теперь на главной подключен site.js, и
   после первого экрана шапка закрепляется - то есть ведет себя ровно как на остальных
   страницах, и правило должно быть общим. */

body section[id] {
  scroll-margin-top: calc(var(--header-h) - var(--sec-pad-top, 0px));
}/* ═══════════════════════════════════════════════════════════
   ЗАМОК ПРОКРУТКИ ПОД ВСПЛЫВАЮЩИМИ ОКНАМИ (v127)
   Было: скрипты ставили inline overflow:hidden на html и body. Полоса прокрутки
   исчезала, ширина области содержимого росла на ее ширину (замер: 15px в Chrome
   на Windows), и вся страница дергалась вправо в момент открытия окна. Видно на
   любом окне с прокруткой: модалка «Скоро», меню-бургер, настройки cookie.
   Стало: замок через класс. scrollbar-gutter резервирует желоб полосы, пока окно
   открыто, поэтому ширина содержимого не меняется и дорожка остается на месте.
   Для браузеров без scrollbar-gutter (Safari до 18.2) скрипт добавляет
   компенсирующий padding-right той же ширины - эффект тот же.
   На обычный рендер правило не влияет: класса нет - ничего не применяется. *//* Замок прокрутки. Ревизия 17.08.2026: снят position:fixed у body и scrollbar-gutter
   у html - оба давали видимые дефекты.

   Что было не так с position:fixed. Прокрутку страницы держит html
   (document.scrollingElement === html, у body scrollTop всегда 0) - прежний
   комментарий про «прокрутку отдает body» верен не был. Как только body получал
   position:fixed, он выходил из потока, и вместе с ним ломалась шапка:
   .site-header стоит на position:sticky, а sticky считает свое положение от
   ближайшего прокручиваемого предка. Предком становился сам body с
   overflow:hidden и scrollTop 0, поэтому шапка вставала не у верха окна, а у
   верха документа - то есть уезжала на -N пикселей за экран. Замер на /faq/ при
   прокрутке 1500: до открытия модалки верх шапки 0, после открытия -1500.
   Отсюда и «пропадает верхнее меню», и ощущение, что интерфейс уехал вверх.

   Что было не так со scrollbar-gutter. Правило включалось только на время
   замка, вместе с overflow:hidden. Там, где полосы прокрутки накладные
   (macOS, мобильные, headless), желоб до замка не резервировался, а с замком
   резервировался - и в момент открытия окна по краю появлялась полоса шириной
   в полосу прокрутки, залитая фоном холста, а содержимое переезжало. Замер:
   правые 15px кадра становились цвета --bg (251,246,238) вместо затемнения
   модалки. Chrome при overflow:hidden резервирует желоб по обеим осям, поэтому
   та же полоса вылезала и снизу.

   Стало: замок - это только overflow:hidden у html. Позицию прокрутки html при
   этом не теряет (проверено: 1500 до замка, 1500 после), body остается в потоке,
   sticky-шапка держится у верха окна. Ширину исчезнувшей полосы прокрутки
   компенсирует скрипт: padding-right у body ровно на ширину полосы, теперь
   безусловно, а не только там, где нет scrollbar-gutter. Там, где полосы
   накладные, ширина выходит 0 и правило вхолостую. */

html.is-scroll-locked {
  overflow: hidden !important;
}/* Компенсация исчезнувшей полосы прокрутки для того, что стоит НЕ в потоке тела.
   Отступ у body, который ставит скрипт, чинит только содержимое страницы. Шапка на
   главной и на лендингах стоит на absolute (data-variant=on-hero) или на fixed
   (data-scrolled=true) - ее containing block окно, а не тело, поэтому она ловит
   выросшую ширину окна целиком. Содержимое шапки центрируется по --container-wide,
   и рост ширины на 14-15 пикселей сдвигал логотип и меню вправо на половину этой
   величины. Замер оператора на главной: логотип 413 -> 420, «Контакты» 1489 -> 1497.
   Ширину шапки не трогаем - фон и граница обязаны тянуться на всю ширину окна.
   Правим ТОЛЬКО ее поля: они заданы процентом, а процент у элемента вне потока
   считается от окна, а не от тела, поэтому поля вырастали на 7 пикселей с каждой
   стороны и содержимое шапки съезжало. Переменная --zhelob-shapki объявляется здесь
   и вычитается в формуле полей в components.css; у липкой шапки продуктовых страниц
   ее нет, и та остается нетронутой - она лежит в потоке тела и уже скомпенсирована
   его отступом.
   Баннер cookie тоже fixed и прижат к правому краю - его двигаем отступом справа.
   Подложку модалки НЕ трогаем сознательно: она обязана закрывать все окно целиком,
   иначе по правому краю останется полоса незакрытой страницы. */

html.is-scroll-locked .site-header[data-variant="on-hero"],
html.is-scroll-locked .site-header[data-scrolled="true"] {
  --zhelob-shapki: var(--zamok-zhelob, 0px);
}
html.is-scroll-locked .cookie-banner {
  right: calc(var(--gutter) + var(--zamok-zhelob, 0px));
}

/* ════ ОБХОД НАВИГАЦИИ (skip-link) ════
   Первый элемент body, до шапки. Человеку с клавиатуры и в экранной читалке иначе
   приходится проходить логотип и все пункты меню на КАЖДОЙ странице, прежде чем
   добраться до текста, - на пятидесяти страницах это пятьдесят повторов.

   Прячем сдвигом, а не display:none и не visibility:hidden: скрытый этими способами
   элемент выпадает из порядка обхода, и до ссылки нельзя добраться Tab-ом, то есть
   обход перестает существовать. Сдвиг оставляет ссылку в потоке фокуса.

   Цель обхода - первый блок содержимого после шапки, ему проставлены id и tabindex="-1"
   (без tabindex браузер прокрутит к якорю, но фокус останется на ссылке, и дальнейший
   Tab снова уйдет в меню). scroll-margin-top уводит цель из-под липкой шапки. */
.skip-link {
  position: fixed; top: 8px; left: 8px; z-index: calc(var(--z-header) + 10);
  display: inline-flex; align-items: center; min-height: 44px;
  padding: 10px 16px; border-radius: 10px;
  background: var(--bg); color: var(--ink);
  border: 1px solid var(--line);
  box-shadow: 0 6px 18px rgba(44,39,35,.18);
  font-size: var(--fs-small); font-weight: 600; text-decoration: none;
  transform: translateY(calc(-100% - 24px));
  transition: transform calc(140ms * var(--motion)) ease;
}
.skip-link:focus {
  transform: none;
  outline: 2px solid var(--focus-ring); outline-offset: 2px;
}
#soderzhanie { scroll-margin-top: calc(var(--header-h) + 8px); }
#soderzhanie:focus { outline: none; }

@media (hover:hover) and (pointer:fine) {
  /* Общее правило наведения вторичных кнопок красило и главную кнопку баннера:
     селектор :where(...):not(:disabled):hover весит 0,2,0, а [data-cookie="all"] -
     0,1,0, поэтому коралл на наведении пропадал и кнопка становилась песочной,
     то есть цветом самого баннера. Возвращаем ей нажимной оттенок коралла. */
  .cookie-banner__actions [data-cookie="all"]:not(:disabled):hover {
    background-color: var(--cta-press); color: var(--cta-ink); border-color: transparent;
  }
}
