/* ============================================================
   ASTROLABS — components
   Шапка, мобильное меню, кнопки, карточки, секции, hero,
   bento-сетка, бейджи, статистика, таймлайн, аккордеон,
   футер, формы.
   ============================================================ */

/* ============================================================
   Layout helpers
   ============================================================ */
.container{
  width:100%; max-width:1280px; margin-inline:auto;
  padding-inline:var(--sp-5);
}
.section{ padding-block:var(--sp-9); position:relative; }
.section-head{ max-width:640px; margin-bottom:var(--sp-7); }
.section-head .eyebrow{ margin-bottom:var(--sp-3); }
/* Ритм внутри шапки секции. Раньше отступ лида задавался инлайновым
   style="margin-top:var(--sp-4)" на каждой странице — правило переехало
   в CSS, разметка чистая, ритм одинаковый на всех 19 страницах. */
.section-head .lead{ margin-top:var(--sp-4); }
.section-head p + p{ margin-top:var(--sp-4); }
/* Юридическая/уточняющая приписка под лидом — мельче лида, но с той же мерой */
.section-head .meta-value{ font-size:var(--fs-sm); max-width:var(--measure-text); }

/* ============================================================
   Header — sticky, blur, состояние при скролле
   ============================================================ */
.header{
  position:sticky; top:0; z-index:var(--z-header);
  display:flex; align-items:center; justify-content:space-between;
  padding:var(--sp-4) var(--sp-5);
  background:rgba(5,7,13,.4);
  backdrop-filter:blur(14px) saturate(140%);
  -webkit-backdrop-filter:blur(14px) saturate(140%);
  border-bottom:1px solid transparent;
  transition:background var(--dur-base) var(--ease-out),
             border-color var(--dur-base) var(--ease-out),
             padding var(--dur-base) var(--ease-out);
}
.header.is-scrolled{
  background:rgba(5,7,13,.78);
  border-bottom-color:var(--line);
  padding-block:var(--sp-3);
}
.header__logo{
  font-family:var(--font-display); font-weight:600;
  font-size:var(--fs-md); letter-spacing:var(--ls-normal);
  display:flex; align-items:center; gap:var(--sp-2);
  flex-shrink:0;
}
.header__logo span{ color:var(--accent); }
.header__logo-img{
  display:block; width:93px; height:44px; max-width:32vw;
}

.header__nav{ display:flex; align-items:center; gap:var(--sp-6); }
.header__nav ul{ display:flex; gap:var(--sp-5); }
.header__nav a{
  font-size:var(--fs-sm); color:var(--muted);
  transition:color var(--dur-fast) var(--ease-out);
  position:relative; padding-block:var(--sp-1);
}
.header__nav a::after{
  content:''; position:absolute; left:0; bottom:-2px;
  width:0; height:1px; background:var(--accent);
  transition:width var(--dur-base) var(--ease-out);
}
.header__nav a:hover, .header__nav a[aria-current="page"]{ color:var(--text); }
.header__nav a:hover::after, .header__nav a[aria-current="page"]::after{ width:100%; }

.header__actions{ display:flex; align-items:center; gap:var(--sp-4); }

.lang-switch{
  display:flex; gap:var(--sp-1); font-family:var(--font-mono); font-size:var(--fs-xs);
}
.lang-switch button{
  padding:var(--sp-1) var(--sp-2); border-radius:var(--r-sm); color:var(--muted);
  transition:color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
  /* min-height было 32px. Этот же переключатель продублирован в подвале
     мобильного меню (.mobile-menu__footer), где он — основная тач-цель:
     32px ниже рекомендованных 44px, промах пальцем по соседней кнопке.
     44px помещаются в шапку без её роста: логотип рядом и так 44px. */
  min-width:44px; min-height:44px;
}
.lang-switch button[aria-current="true"]{ color:var(--accent); background:var(--surface); }
.lang-switch button:hover{ color:var(--text); }

/* Гамбургер — только для мобильного меню */
.burger{
  display:none; position:relative; width:44px; height:44px;
  align-items:center; justify-content:center;
}
.burger__box{ width:22px; height:14px; position:relative; }
.burger__line{
  position:absolute; left:0; width:100%; height:1.5px; background:var(--text);
  transition:transform var(--dur-base) var(--ease-move), opacity var(--dur-fast) var(--ease-out), top var(--dur-base) var(--ease-move);
}
.burger__line:nth-child(1){ top:0; }
.burger__line:nth-child(2){ top:6px; }
.burger__line:nth-child(3){ top:12px; }
.burger[aria-expanded="true"] .burger__line:nth-child(1){ top:6px; transform:rotate(45deg); }
.burger[aria-expanded="true"] .burger__line:nth-child(2){ opacity:0; }
.burger[aria-expanded="true"] .burger__line:nth-child(3){ top:6px; transform:rotate(-45deg); }

@media (max-width:1000px){
  .header__nav > ul{ display:none; }
  .burger{ display:flex; }
}

/* ============================================================
   Мобильное меню — полноэкранное, доступное, trap focus
   ============================================================ */
.mobile-menu{
  position:fixed; inset:0; z-index:var(--z-overlay);
  background:var(--void);
  display:flex; flex-direction:column;
  padding:var(--sp-6) var(--sp-5);
  opacity:0; visibility:hidden; transform:translateY(-8px);
  transition:opacity var(--dur-base) var(--ease-out),
             transform var(--dur-base) var(--ease-out),
             visibility 0s linear var(--dur-base);
}
.mobile-menu.is-open{
  opacity:1; visibility:visible; transform:none;
  transition:opacity var(--dur-base) var(--ease-out),
             transform var(--dur-base) var(--ease-out),
             visibility 0s linear 0s;
}
.mobile-menu__head{ display:flex; justify-content:flex-end; margin-bottom:var(--sp-7); }
.mobile-menu__close{ width:44px; height:44px; display:flex; align-items:center; justify-content:center; }
.mobile-menu nav ul{ display:flex; flex-direction:column; gap:var(--sp-4); }
.mobile-menu nav a{
  font-family:var(--font-display); font-size:var(--fs-2xl); font-weight:500;
  color:var(--text); display:block; padding-block:var(--sp-2);
}
.mobile-menu nav a:hover, .mobile-menu nav a:focus-visible{ color:var(--accent); }
.mobile-menu__footer{ margin-top:auto; display:flex; flex-direction:column; gap:var(--sp-3); }

/* ============================================================
   Кнопки — primary (ember), ghost, magnetic
   ============================================================ */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:var(--sp-2);
  min-height:44px; padding:var(--sp-3) var(--sp-6);
  border-radius:var(--r-full); font-size:var(--fs-sm); font-weight:500;
  border:1px solid transparent; cursor:pointer; white-space:nowrap;
  /* Асимметрия нажатия: вниз — почти мгновенно (--dur-press), обратно —
     пружиной с лёгким отскоком. Так кнопка ощущается физической: палец
     получает отклик сразу, а «возврат» несёт инерцию жеста. */
  transition:transform var(--dur-base) var(--ease-spring),
             border-color var(--dur-fast) var(--ease-out),
             background var(--dur-fast) var(--ease-out),
             box-shadow var(--dur-fast) var(--ease-out);
}
.btn:active{ transform:scale(.97); transition-duration:var(--dur-press); }

.btn--primary{
  background:linear-gradient(135deg, var(--ember), #ffab6b);
  color:#170B03; font-weight:600;
}
.btn--primary:hover{ box-shadow:var(--glow-ember); }

.btn--ghost{
  background:transparent; color:var(--text); border-color:var(--line);
}
.btn--ghost:hover{ border-color:var(--accent); color:var(--accent); }

.btn--sm{ min-height:36px; padding:var(--sp-2) var(--sp-4); font-size:var(--fs-xs); }

/* Magnetic: контейнер притягивается к курсору, .btn__label — сильнее (см. app.js) */
.magnetic{ position:relative; will-change:transform; }
.magnetic .btn__label{ display:inline-block; will-change:transform; }

/* ============================================================
   Карточки — glass: тонкая рамка + подсветка на hover
   ============================================================ */
.card{
  position:relative; overflow:hidden;
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  padding:var(--sp-6);
  transition:border-color var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.card::before{
  content:''; position:absolute; inset:0; pointer-events:none; opacity:0;
  background:radial-gradient(320px circle at var(--mx,50%) var(--my,50%),
    rgba(var(--accent-rgb),.12), transparent 60%);
  transition:opacity var(--dur-base) var(--ease-out);
}
.card:hover{ border-color:rgba(var(--accent-rgb),.4); }
.card:hover::before{ opacity:1; }
.card__icon{
  width:44px; height:44px; border-radius:var(--r-md);
  background:var(--elevated); border:1px solid var(--line);
  display:flex; align-items:center; justify-content:center;
  color:var(--accent); margin-bottom:var(--sp-5);
}
/* sp-2 (8px) под заголовком было теснее, чем sp-3 (12px) над ним
   у .card__label: подпись «прилипала» к чужому блоку. Ритм лейбл →
   заголовок → текст теперь ровный. */
.card h3{ font-size:var(--fs-lg); margin-bottom:var(--sp-3); }
/* Мера внутри карточки. Без max-width текст в .card--wide (полная
   ширина bento, до 1232px) набирался в ~150 знаков в строке —
   вдвое больше читаемого предела. */
.card p{
  color:var(--muted); font-size:var(--fs-sm); line-height:var(--lh-loose);
  max-width:var(--measure-card);
}
.card p + p{ margin-top:var(--sp-4); }
.card .checklist{ max-width:var(--measure-card); }

/* ============================================================
   Hero
   ============================================================ */
.hero{
  position:relative; min-height:92svh;
  display:flex; flex-direction:column; justify-content:center;
  overflow:hidden; padding:var(--sp-9) var(--sp-5);
}
.hero__canvas-wrap{ position:absolute; inset:0; z-index:0; }
.hero__canvas-wrap canvas{ width:100%; height:100%; display:block; }
.hero__glow{
  position:absolute; inset:0; z-index:1; pointer-events:none;
  background:radial-gradient(50% 40% at 50% 40%, rgba(var(--deep-rgb),.25), transparent 70%);
  filter:blur(40px);
}
.hero__content{ position:relative; z-index:2; max-width:900px; }
.hero__eyebrow{ margin-bottom:var(--sp-5); }
.hero h1{ margin-bottom:var(--sp-5); }
.hero h1 em{
  font-style:normal;
  background:linear-gradient(135deg, var(--accent), var(--violet));
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.hero__lead{ max-width:var(--measure-lead); margin-bottom:var(--sp-7); }
.hero__actions{ display:flex; gap:var(--sp-4); flex-wrap:wrap; }
/* Длинные CTA-подписи в герое переносятся, а не выезжают за экран */
.hero__actions .btn{ white-space:normal; text-align:center; max-width:100%; }

/* ============================================================
   Секции / eyebrow / бейджи-пилюли
   ============================================================ */
.eyebrow{
  display:inline-flex; align-items:center; gap:var(--sp-2);
  font-family:var(--font-mono); font-size:var(--fs-xs);
  letter-spacing:var(--ls-wider); text-transform:uppercase;
  color:var(--accent);
}
.eyebrow::before{
  content:''; width:6px; height:6px; border-radius:50%;
  background:var(--accent); box-shadow:0 0 8px var(--accent);
}

.pill{
  display:inline-flex; align-items:center; gap:var(--sp-2);
  padding:var(--sp-1) var(--sp-4); border-radius:var(--r-full);
  background:var(--elevated); border:1px solid var(--line);
  font-size:var(--fs-xs); color:var(--muted);
}
.pill--accent{ border-color:rgba(var(--accent-rgb),.4); color:var(--accent); }

/* ============================================================
   Bento-сетка
   ============================================================ */
.bento{
  display:grid; gap:var(--sp-4);
  grid-template-columns:repeat(4, 1fr);
  grid-auto-rows:minmax(160px, auto);
}
.bento > .card{ grid-column:span 2; }
.bento > .card--wide{ grid-column:span 4; }
.bento > .card--tall{ grid-row:span 2; }
@media (max-width:900px){
  .bento{ grid-template-columns:repeat(2, minmax(0,1fr)); }
  .bento > .card{ grid-column:span 2; }
}
@media (max-width:560px){
  .bento{ grid-template-columns:minmax(0,1fr); }
  .bento > .card, .bento > .card--wide{ grid-column:span 1; }
}

/* ============================================================
   Статистика — крупные цифры
   ============================================================ */
.stats{
  display:grid; grid-template-columns:repeat(auto-fit, minmax(180px, 1fr));
  gap:var(--sp-6);
}
.stat{ border-left:1px solid var(--line); padding-left:var(--sp-5); }
.stat__value{
  font-family:var(--font-display); font-weight:700;
  /* Было --fs-3xl — ровно кегль h2: цифра и заголовок секции читались
     как один уровень, иерархия «заголовок → доказательство» пропадала.
     --fs-2xl оставляет цифру крупной, но подчинённой заголовку.
     Крупный вариант (.stat--lg) ниже не тронут. */
  font-size:var(--fs-2xl); line-height:1; letter-spacing:var(--ls-tight);
  /* Табличные цифры: столбцы значений выравниваются по разряду */
  font-variant-numeric:tabular-nums;
  color:var(--text); display:flex; align-items:baseline; gap:var(--sp-1);
}
.stat__value .unit{ font-size:var(--fs-lg); color:var(--accent); }
.stat__label{ margin-top:var(--sp-2); font-size:var(--fs-sm); color:var(--muted); }

/* ============================================================
   Таймлайн (для страницы метода)
   ============================================================ */
.timeline{ position:relative; padding-left:var(--sp-7); }
.timeline::before{
  content:''; position:absolute; left:9px; top:6px; bottom:6px; width:1px;
  background:linear-gradient(var(--line), transparent);
}
.timeline__item{ position:relative; padding-bottom:var(--sp-8); }
.timeline__item:last-child{ padding-bottom:0; }
.timeline__dot{
  position:absolute; left:calc(-1 * var(--sp-7) + 4px); top:4px;
  width:12px; height:12px; border-radius:50%;
  background:var(--void); border:2px solid var(--accent);
  box-shadow:0 0 0 4px var(--void), 0 0 16px rgba(var(--accent-rgb),.5);
}
.timeline__step{ font-family:var(--font-mono); font-size:var(--fs-xs); color:var(--accent); margin-bottom:var(--sp-2); }
.timeline__item h3{ font-size:var(--fs-lg); margin-bottom:var(--sp-2); }
.timeline__item p{ color:var(--muted); max-width:var(--measure-text); }

/* ============================================================
   Аккордеон
   ============================================================ */
.accordion{ border-top:1px solid var(--line); }
.accordion__item{ border-bottom:1px solid var(--line); }
.accordion__trigger{
  width:100%; display:flex; align-items:center; justify-content:space-between;
  padding:var(--sp-5) var(--sp-2); text-align:left;
  font-family:var(--font-display); font-size:var(--fs-md); font-weight:500;
  min-height:44px;
}
.accordion__trigger:hover{ color:var(--accent); }
.accordion__icon{
  flex-shrink:0; width:24px; height:24px; position:relative;
  transition:transform var(--dur-base) var(--ease-move);
}
.accordion__icon::before, .accordion__icon::after{
  content:''; position:absolute; top:50%; left:50%; background:currentColor;
  transform:translate(-50%,-50%);
}
.accordion__icon::before{ width:14px; height:1.5px; }
.accordion__icon::after{ width:1.5px; height:14px; transition:opacity var(--dur-fast) var(--ease-out); }
.accordion__trigger[aria-expanded="true"] .accordion__icon::after{ opacity:0; }
.accordion__trigger[aria-expanded="true"] .accordion__icon{ transform:rotate(180deg); color:var(--accent); }

/* Свёрнутая панель имела только height:0 + overflow:hidden. Этого мало:
   ссылки внутри неё оставались в порядке обхода Tab — фокус уезжал в
   невидимый блок, и пользователь клавиатуры терял его из виду
   (нарушение WCAG 2.4.7 «Focus Visible» и 2.4.3 «Focus Order»).
   На странице метода в свёрнутых панелях лежат ссылки на кейсы.
   visibility:hidden убирает содержимое и из обхода, и из дерева
   доступности; класс is-open вешает JS (см. initAccordion).
   Задержка visibility на длительность анимации — чтобы содержимое
   не пропадало мгновенно при закрытии. */
.accordion__panel{
  overflow:hidden; height:0; visibility:hidden;
  transition:height var(--dur-base) var(--ease-out),
             visibility 0s linear var(--dur-base);
}
.accordion__panel.is-open{
  visibility:visible;
  transition:height var(--dur-base) var(--ease-out),
             visibility 0s linear 0s;
}
.accordion__panel-inner{ padding:0 var(--sp-2) var(--sp-5); color:var(--muted); max-width:var(--measure-text); }

/* ============================================================
   Футер
   ============================================================ */
.footer{
  border-top:1px solid var(--line); padding-block:var(--sp-8);
  background:var(--surface);
}
.footer__grid{
  display:grid; gap:var(--sp-7);
  grid-template-columns:1.4fr repeat(3, 1fr);
}
.footer__brand{ font-family:var(--font-display); font-size:var(--fs-lg); margin-bottom:var(--sp-3); }
.footer h4{
  font-family:var(--font-mono); font-size:var(--fs-xs); text-transform:uppercase;
  letter-spacing:var(--ls-wider); color:var(--muted); margin-bottom:var(--sp-4); font-weight:500;
}
.footer ul{ display:flex; flex-direction:column; gap:var(--sp-3); }
.footer a{ color:var(--text); font-size:var(--fs-sm); }
.footer a:hover{ color:var(--accent); }
.footer__bottom{
  margin-top:var(--sp-8); padding-top:var(--sp-5); border-top:1px solid var(--line);
  display:flex; justify-content:space-between; flex-wrap:wrap; gap:var(--sp-3);
  font-size:var(--fs-xs); color:var(--muted);
}
@media (max-width:800px){
  .footer__grid{ grid-template-columns:minmax(0,1fr) minmax(0,1fr); }
  /* Колонка бренда — на всю ширину: в половине колонки словесный знак
     ASTROLABS (Unbounded — широкая гарнитура) ломался переносом на
     «ASTROLAB / S», а таглайн рвался по слову на каждой строке. */
  .footer__grid > div:first-child{ grid-column:1 / -1; }
}
/* На 320px две колонки подвала не ужимались (min-width:auto у грид-элементов
   держал их по min-content) и давали горизонтальный скролл. Ниже 380px —
   одна колонка. */
@media (max-width:380px){
  .footer__grid{ grid-template-columns:minmax(0,1fr); gap:var(--sp-6); }
}

/* ============================================================
   Формы
   ============================================================ */
.field{ margin-bottom:var(--sp-5); position:relative; }
.field label{
  display:block; font-size:var(--fs-xs); font-family:var(--font-mono);
  letter-spacing:var(--ls-wider); text-transform:uppercase; color:var(--muted);
  margin-bottom:var(--sp-2);
}
.field input, .field textarea{
  width:100%; min-height:48px; padding:var(--sp-3) var(--sp-4);
  background:var(--surface); border:1px solid var(--line-control); border-radius:var(--r-sm);
  color:var(--text); font-size:var(--fs-base);
  /* Кольцо состояния распускается пружиной — короткий «поп», который
     читается как отклик материала, а не как перерисовка. Цвет рамки
     при этом идёт ровным ease-out: пружинить обе величины — перебор. */
  transition:border-color var(--dur-fast) var(--ease-out),
             background var(--dur-fast) var(--ease-out),
             box-shadow var(--dur-base) var(--ease-spring);
}
.field textarea{ min-height:140px; resize:vertical; }
/* Было opacity:.7 — плейсхолдер складывался в #646E81 и давал на фоне
   поля (--surface) контраст 3.73:1, ниже порога WCAG AA 4.5:1 для
   обычного текста. Плейсхолдеры здесь несут смысл («Почта, телефон
   или Telegram для ответа»), поэтому читаемость обязательна.
   Без opacity --muted даёт 6.50:1. */
.field input::placeholder, .field textarea::placeholder{ color:var(--muted); opacity:1; }
/* --line (1.3:1 к фону) годится для декоративных разделителей, но не
   для границы поля ввода: WCAG 1.4.11 требует 3:1, иначе поле
   не отличить от фона. Ховер — на ступень светлее границы покоя. */
.field input:hover, .field textarea:hover{ border-color:#6C7B9E; }
.field input:focus, .field textarea:focus{
  outline:none; border-color:var(--accent);
  /* Фокус должен читаться сам по себе, без сравнения с соседями: кольцо
     плотнее (.22 вместо .15) и поле поднимается на --elevated. Одной
     смены цвета рамки на тёмном фоне для этого мало. */
  background:var(--elevated);
  box-shadow:0 0 0 3px rgba(var(--accent-rgb),.22);
}
/* Селектор `.field input:focus` (0,2,1) перебивает базовый
   `:focus-visible` (0,1,0) из base.css, то есть outline:none снимается
   и с клавиатурного фокуса. Для обычного режима это в порядке: рамка,
   фон и кольцо остаются. Но в режиме принудительных цветов ОС
   (Windows High Contrast) box-shadow не рисуется, а border и background
   подменяются системными — от индикатора не остаётся ничего, и поле в
   обходе Tab становится неотличимо от соседних. Возвращаем outline
   системным цветом Highlight. */
@media (forced-colors:active){
  .field input:focus, .field textarea:focus{
    outline:3px solid Highlight; outline-offset:2px;
  }
}
.field__hint{ margin-top:var(--sp-2); font-size:var(--fs-xs); color:var(--muted); }

/* Маркер обязательного поля. Обязательность для скринридера несёт атрибут
   required на самом input, поэтому звёздочка помечена aria-hidden в
   разметке — иначе лейбл читался бы как «Имя звёздочка». */
.field__req{ color:var(--ember); margin-left:.35em; }
/* Необязательное поле помечено словом, а не отсутствием звёздочки:
   отсутствие признака заметить труднее, чем его наличие. */
.field__opt{
  margin-left:.5em; color:var(--muted);
  text-transform:none; letter-spacing:var(--ls-normal);
}
/* Легенда формы — объясняет звёздочку до того, как пользователь на неё
   наткнётся. Подтягивается вверх под лид карточки. */
.form-legend{
  margin:calc(var(--sp-4) * -1) 0 var(--sp-6);
  font-size:var(--fs-xs); color:var(--muted);
}
.form-legend b{ color:var(--ember); font-weight:400; }

/* Живой счётчик символов (сейчас — поле «Задача»). Один узел одновременно
   визуальный счётчик и aria-live="polite" регион; JS обновляет его с
   задержкой (debounce), не на каждый символ. */
.field__counter{
  margin-top:var(--sp-2); font-size:var(--fs-xs); font-family:var(--font-mono);
  color:var(--muted); text-align:right;
  transition:color var(--dur-fast) var(--ease-out);
}
.field__counter.is-warn{ color:var(--ember); }
.field__counter.is-limit{ color:var(--danger); }

.field.is-error input, .field.is-error textarea{
  border-color:var(--danger); box-shadow:0 0 0 3px rgba(251,113,133,.22);
  /* Один затухающий толчок в момент, когда поле стало ошибочным. Класс
     навешивается один раз, поэтому анимация не зацикливается и не
     повторяется на каждый символ. Смысл несут цвет и текст ошибки —
     движение только привлекает взгляд. */
  animation:field-nudge 300ms var(--ease-move);
}
.field__error{
  margin-top:var(--sp-2); font-size:var(--fs-xs); color:var(--danger); display:none;
}
.field.is-error .field__error{
  display:block;
  animation:msg-in 240ms var(--ease-out);
}
@keyframes field-nudge{
  0%{ transform:translateX(0); }   22%{ transform:translateX(-4px); }
  55%{ transform:translateX(3px); } 80%{ transform:translateX(-1px); }
  100%{ transform:translateX(0); }
}
@keyframes msg-in{
  from{ opacity:0; transform:translateY(-3px); }
  to{ opacity:1; transform:none; }
}

/* Успех поля: тот же вес кольца, что у ошибки, — состояние «принято»
   должно читаться так же уверенно, как «не принято». Навешивается из JS
   на blur, когда поле заполнено и прошло проверку. */
.field.is-success input, .field.is-success textarea{
  border-color:var(--success); box-shadow:0 0 0 3px rgba(74,222,128,.22);
}

/* Чекбокс */
.checkbox{ display:flex; align-items:flex-start; gap:var(--sp-3); cursor:pointer; }
.checkbox input{
  appearance:none; width:20px; height:20px; min-width:20px; margin-top:2px;
  border:1px solid var(--line); border-radius:6px; background:var(--surface);
  display:inline-flex; align-items:center; justify-content:center;
  transition:border-color var(--dur-fast) var(--ease-out),
             background var(--dur-fast) var(--ease-out),
             transform var(--dur-base) var(--ease-spring);
}
/* Та же асимметрия, что у кнопки: вжимается мгновенно, отпускается пружиной.
   Ловим :active на всём лейбле — кликают обычно по тексту, а отклик должен
   прийти от квадратика, по которому пользователь целится глазами. */
.checkbox:active input{ transform:scale(.9); transition-duration:var(--dur-press); }
.checkbox input:checked{ background:var(--accent); border-color:var(--accent); }
.checkbox input:checked::after{
  content:''; width:10px; height:6px; border-left:2px solid var(--void); border-bottom:2px solid var(--void);
  transform:rotate(-45deg) translate(1px,-1px);
  animation:tick-in 280ms var(--ease-spring);
}
/* Галочка «прилетает» из уменьшенного состояния. Конечный transform обязан
   совпадать с базовым, иначе после анимации она прыгнет. */
@keyframes tick-in{
  from{ opacity:0; transform:rotate(-45deg) translate(1px,-1px) scale(.4); }
  to{   opacity:1; transform:rotate(-45deg) translate(1px,-1px) scale(1); }
}
.checkbox span{ font-size:var(--fs-sm); color:var(--muted); line-height:var(--lh-normal); }
.checkbox a{ color:var(--text); text-decoration:underline; text-underline-offset:2px; }

/* Состояние загрузки кнопки формы */
.btn.is-loading{ position:relative; color:transparent; pointer-events:none; }
.btn.is-loading::after{
  content:''; position:absolute; width:16px; height:16px;
  border:2px solid rgba(0,0,0,.25); border-top-color:#170B03; border-radius:50%;
  animation:spin .7s linear infinite;
}
@keyframes spin{ to{ transform:rotate(360deg); } }

/* Honeypot-поле формы — визуально скрыто, но доступно ботам-парсерам DOM */
.field--hp{
  position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden;
}

/* Общий баннер результата формы.
   Важно: базовое состояние display:none. Значит модификатор ОБЯЗАТЕЛЕН —
   без него текст и не виден, и не объявляется скринридером (содержимое
   display:none выпадает из дерева доступности, aria-live не спасает).
   Поэтому у «отправляем…» есть собственный класс is-pending. */
.form-status{
  margin-top:var(--sp-5); padding:var(--sp-4) var(--sp-5); border-radius:var(--r-sm);
  font-size:var(--fs-sm); line-height:var(--lh-normal); display:none;
}
.form-status.is-pending{ display:block; background:rgba(var(--accent-rgb),.08); color:var(--accent); border:1px solid rgba(var(--accent-rgb),.28); }
.form-status.is-success{ display:block; background:rgba(74,222,128,.1); color:var(--success); border:1px solid rgba(74,222,128,.3); }
.form-status.is-error{ display:block; background:rgba(251,113,133,.1); color:var(--danger); border:1px solid rgba(251,113,133,.3); }
/* Баннер приходит пружиной — движению предшествовало нажатие «Отправить». */
.form-status.is-pending, .form-status.is-success, .form-status.is-error{
  animation:status-in 300ms var(--ease-spring);
}
@keyframes status-in{
  from{ opacity:0; transform:translateY(-6px) scale(.985); }
  to{   opacity:1; transform:none; }
}

/* ============================================================
   Скролл-reveal (используется app.js)
   ============================================================ */
[data-reveal]{
  opacity:0; transform:translateY(24px); filter:blur(6px);
  transition:opacity var(--dur-slow) var(--ease-out),
             transform var(--dur-slow) var(--ease-out),
             filter var(--dur-slow) var(--ease-out);
  transition-delay:var(--d, 0ms);
}
[data-reveal].is-in{ opacity:1; transform:none; filter:none; }

/* ============================================================
   ДОБАВЛЕНО ДЛЯ СТРАНИЦ САЙТА (RU/EN) — 2026-07-20
   Ничего выше не переписано; только новые классы,
   нужные для вёрстки 7 страниц + 404.
   ============================================================ */

/* --- Шапка страницы (внутренние страницы, без 3D) --- */
.page-hero{
  position:relative;
  padding-block:calc(var(--sp-9) + var(--sp-8)) var(--sp-8);
  border-bottom:1px solid var(--line);
}
.page-hero__inner{ max-width:62ch; }
.page-hero h1{ margin-bottom:var(--sp-5); }
.page-hero .lead{ color:var(--muted); }

/* --- Ограничение ширины текстового блока --- */
.prose{ max-width:var(--measure-text); }
.prose p + p{ margin-top:var(--sp-4); }

/* --- Половинная карточка в bento: сетка четырёхколоночная,
       половина ряда = span 2 (столько же, сколько у обычной .card) --- */
.bento > .card--half{ grid-column:span 2; }
@media (max-width:640px){ .bento > .card--half{ grid-column:span 1; } }

/* --- Мини-лейбл над заголовком карточки --- */
.card__label{
  font-family:var(--font-mono); font-size:var(--fs-xs);
  font-weight:400; line-height:var(--lh-normal);
  letter-spacing:var(--ls-wider); text-transform:uppercase;
  color:var(--muted); margin-bottom:var(--sp-3); display:block;
}
.card__label--accent{ color:var(--accent); }

/* --- Примечание под цифрой в блоке статистики ---
   Было opacity:.85 — по той же причине, по которой его убрали у
   плейсхолдера поля. --muted складывается в #778195: на чистом --void
   это 5.14:1, но блок «Цифры» лежит на голом фоне страницы, а .mesh
   зафиксирован во вьюпорте — при прокрутке под текст уезжает пик
   синего градиента (rgba(--deep,.28) ≈ #102351), и контраст падает до
   4.14:1, ниже порога WCAG AA 4.5:1. Кегль здесь --fs-xs (12–13px),
   послабления для крупного текста не действуют. Без opacity --muted
   даёт 6.84:1 на --void и 5.16:1 на пике градиента. */
.stat__note{
  margin-top:var(--sp-3); font-size:var(--fs-xs);
  color:var(--muted); line-height:var(--lh-loose);
}
.stat--lg .stat__value{ font-size:clamp(2rem, 4.5vw, 3.25rem); }

/* Во всех одноколоночных мобильных раскладках ниже дорожка задана как
   minmax(0,1fr), а не 1fr. Это не косметика: `1fr` — сокращение от
   `minmax(auto,1fr)`, а `auto` в минимуме означает min-content, то есть
   дорожка отказывается сжиматься уже длинного неразрывного слова и
   растягивает грид шире вьюпорта. Десктопные правила здесь всегда
   писались через minmax(0,…), а мобильные переопределения этот ноль
   теряли — отсюда горизонтальная прокрутка на 320px на страницах
   «О компании» (+12px) и «Продукты» (+9px). minmax(0,1fr) разрешает
   дорожке быть уже содержимого, а перенос длинных слов берут на себя
   правила overflow-wrap ниже. */

/* --- Двухколоночная раскладка «текст + список» --- */
.split{
  display:grid; grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
  gap:var(--sp-8); align-items:start;
}
@media (max-width:900px){ .split{ grid-template-columns:minmax(0,1fr); gap:var(--sp-6); } }

/* --- Список с акцентными маркерами --- */
/* Мера строки для маркированных списков: в правой колонке .service
   (≈0.58fr от 1232px) пункт набирался в ~90 знаков. */
.checklist{ list-style:none; display:grid; gap:var(--sp-3); max-width:var(--measure-text); }
.checklist li{
  position:relative; padding-left:var(--sp-5);
  color:var(--muted); line-height:var(--lh-loose);
}
.checklist li::before{
  content:''; position:absolute; left:0; top:.62em;
  width:7px; height:7px; border-radius:50%;
  background:var(--accent); box-shadow:0 0 10px rgba(var(--accent-rgb),.6);
}
.checklist--tight li{ padding-left:var(--sp-4); }

/* --- Выделенный блок-предупреждение / правило --- */
.callout{
  position:relative; border:1px solid var(--line);
  border-left:2px solid var(--ember);
  background:linear-gradient(180deg, rgba(var(--ember-rgb),.06), transparent 70%);
  border-radius:var(--r-md); padding:var(--sp-6);
}
.callout h2, .callout h3{ font-size:var(--fs-xl); margin-bottom:var(--sp-4); }
.callout p{ color:var(--muted); max-width:var(--measure-text); line-height:var(--lh-loose); }
.callout p + p{ margin-top:var(--sp-4); }

/* --- Направление услуг --- */
.service{
  display:grid; grid-template-columns:minmax(0,.42fr) minmax(0,.58fr);
  gap:var(--sp-8); padding-block:var(--sp-8);
  border-top:1px solid var(--line);
}
.service:first-of-type{ border-top:none; padding-top:var(--sp-6); }
@media (max-width:900px){ .service{ grid-template-columns:minmax(0,1fr); gap:var(--sp-5); } }
.service__aside{ position:sticky; top:calc(var(--sp-9) + var(--sp-2)); align-self:start; }
@media (max-width:900px){ .service__aside{ position:static; } }
.service__num{
  font-family:var(--font-mono); font-size:var(--fs-sm); color:var(--accent);
  letter-spacing:var(--ls-wider); display:block; margin-bottom:var(--sp-3);
}
/* --fs-2xl (44px) — размер для полноширинного заголовка секции, а в
   колонке .service__aside (~376px на 1024px) в него не помещались
   «Автоматизация», «безопасность». Заголовку узкой колонки хватает
   --fs-xl; заодно чище иерархия относительно h1 страницы. */
.service__aside h2{ font-size:var(--fs-xl); margin-bottom:var(--sp-4); }
.service__essence{ color:var(--muted); line-height:var(--lh-loose); max-width:var(--measure-text); }
.service__meta{
  margin-top:var(--sp-6); display:grid; gap:var(--sp-4);
  border-top:1px dashed var(--line); padding-top:var(--sp-5);
}
.meta-label{
  font-family:var(--font-mono); font-size:var(--fs-xs);
  text-transform:uppercase; letter-spacing:var(--ls-wider);
  color:var(--accent); display:block; margin-bottom:var(--sp-2);
}
.meta-value{ color:var(--muted); line-height:var(--lh-loose); max-width:var(--measure-text); }

/* --- Кейс --- */
.case{
  border:1px solid var(--line); border-radius:var(--r-lg);
  background:linear-gradient(180deg, rgba(255,255,255,.02), transparent);
  padding:var(--sp-7); margin-bottom:var(--sp-6);
}
.case__num{
  font-family:var(--font-mono); font-size:var(--fs-xs); color:var(--muted);
  letter-spacing:var(--ls-wider);
}
.case h2{ font-size:var(--fs-xl); margin:var(--sp-3) 0 var(--sp-5); max-width:56ch; }
/* min(280px,100%) вместо 280px: в узкой колонке жёсткий минимум в 280px
   делал дорожки шире родителя, и блоки вылезали в его паддинг. */
.case__grid{
  display:grid; grid-template-columns:repeat(auto-fit, minmax(min(280px,100%),1fr));
  gap:var(--sp-6);
}
.case__block h3{
  font-family:var(--font-mono); font-size:var(--fs-xs); font-weight:500;
  text-transform:uppercase; letter-spacing:var(--ls-wider);
  color:var(--accent); margin-bottom:var(--sp-3);
}
.case__block p{ color:var(--muted); line-height:var(--lh-loose); max-width:var(--measure-text); }
/* Строка стека — моноширинная, поэтому ch здесь равен реальному знаку.
   Без ограничения она тянулась на всю ширину кейса: на 1920px это
   ~140 знаков в одну строку, вдвое выше читаемого предела. */
.case__stack{
  margin-top:var(--sp-6); padding-top:var(--sp-4);
  border-top:1px dashed var(--line);
  font-family:var(--font-mono); font-size:var(--fs-xs); color:var(--muted);
  max-width:var(--measure-text); line-height:var(--lh-loose);
}
.case__stack b{ color:var(--accent); font-weight:500; }
/* Перелинковка кейса на релевантное направление и позицию прайса. */
.case__links{
  margin-top:var(--sp-3);
  font-family:var(--font-mono); font-size:var(--fs-xs); color:var(--muted);
  max-width:var(--measure-text); line-height:var(--lh-loose);
}

/* --- Текстовые ссылки внутри контента ---
   В base.css `a{color:inherit; text-decoration:none}` — это нужно навигации и
   кнопкам, но внутри абзаца превращает ссылку в неотличимый текст. Здесь цвет и
   подчёркивание возвращаются точечно, только для прозы. */
.prose a:not(.btn):not(.link-more),
.callout p a:not(.btn):not(.link-more),
.card p a:not(.btn):not(.link-more),
.case__block p a:not(.btn):not(.link-more),
.case__links a,
.meta-value a:not(.btn):not(.link-more),
.timeline__item p a:not(.btn):not(.link-more),
.accordion__panel-inner a:not(.btn):not(.link-more),
.cta-band p a:not(.btn):not(.link-more),
.legal__body a:not(.btn):not(.link-more),
.page-hero .lead a:not(.btn):not(.link-more){
  color:var(--accent);
  text-decoration:underline;
  text-decoration-thickness:1px;
  text-underline-offset:3px;
}
.prose a:not(.btn):not(.link-more):hover,
.callout p a:not(.btn):not(.link-more):hover,
.card p a:not(.btn):not(.link-more):hover,
.case__block p a:not(.btn):not(.link-more):hover,
.case__links a:hover,
.meta-value a:not(.btn):not(.link-more):hover,
.timeline__item p a:not(.btn):not(.link-more):hover,
.accordion__panel-inner a:not(.btn):not(.link-more):hover,
.cta-band p a:not(.btn):not(.link-more):hover,
.legal__body a:not(.btn):not(.link-more):hover,
.page-hero .lead a:not(.btn):not(.link-more):hover{
  text-decoration-thickness:2px;
}

/* --- Продукт --- */
.product{
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:var(--sp-8); align-items:start;
  padding-block:var(--sp-8); border-top:1px solid var(--line);
}
.product:first-of-type{ border-top:none; padding-top:var(--sp-6); }
@media (max-width:900px){ .product{ grid-template-columns:minmax(0,1fr); gap:var(--sp-5); } }
.product__tagline{
  font-family:var(--font-display); font-size:var(--fs-lg);
  color:var(--accent); margin-bottom:var(--sp-4);
}
.product h2{ font-size:var(--fs-xl); margin-bottom:var(--sp-3); } /* см. коммент к .service__aside h2 */
.product p{ color:var(--muted); line-height:var(--lh-loose); max-width:var(--measure-text); }
.product__proof{
  margin-top:var(--sp-5); padding:var(--sp-4) var(--sp-5);
  border-left:2px solid var(--violet); border-radius:var(--r-sm);
  background:rgba(var(--violet-rgb),.07);
  font-size:var(--fs-sm); color:var(--text);
  max-width:var(--measure-text); line-height:var(--lh-loose);
}

/* --- Список «ключ — значение» (реквизиты) --- */
.kv{ display:grid; gap:0; border-top:1px solid var(--line); }
.kv__row{
  display:flex; flex-wrap:wrap; gap:var(--sp-3) var(--sp-5);
  justify-content:space-between; align-items:baseline;
  padding-block:var(--sp-4); border-bottom:1px solid var(--line);
}
.kv__label{
  font-family:var(--font-mono); font-size:var(--fs-xs);
  text-transform:uppercase; letter-spacing:var(--ls-wider); color:var(--muted);
}
.kv__value{
  color:var(--text); font-weight:500;
  /* Цены и реквизиты стоят столбцом друг под другом — моноширинные
     цифры выравнивают разряды и убирают «дрожь» сумм. */
  font-variant-numeric:tabular-nums;
}

/* --- Финальный CTA-баннер --- */
.cta-band{
  position:relative; overflow:hidden;
  border:1px solid var(--line); border-radius:var(--r-lg);
  padding:var(--sp-8); text-align:center;
  background:
    radial-gradient(60% 120% at 50% 0%, rgba(var(--deep-rgb),.20), transparent 70%),
    var(--elevated);
}
.cta-band h2{ font-size:var(--fs-2xl); margin-bottom:var(--sp-4); }
.cta-band p{ color:var(--muted); max-width:var(--measure-lead); margin:0 auto var(--sp-6); line-height:var(--lh-loose); }

/* --- Каналы связи --- */
.channels{ display:grid; gap:var(--sp-4); }
.channel{
  display:block; border:1px solid var(--line); border-radius:var(--r-md);
  background:var(--elevated); padding:var(--sp-5);
  transition:border-color var(--dur-fast) var(--ease-out),
             transform var(--dur-fast) var(--ease-out);
}
.channel:hover{ border-color:rgba(var(--accent-rgb),.55); transform:translateY(-2px); }
.channel__label{
  font-family:var(--font-mono); font-size:var(--fs-xs);
  text-transform:uppercase; letter-spacing:var(--ls-wider);
  color:var(--muted); display:block; margin-bottom:var(--sp-2);
}
.channel__value{ font-family:var(--font-display); font-size:var(--fs-md); color:var(--text); }

/* --- Карточка формы заявки --- */
.form-card{
  border:1px solid var(--line); border-radius:var(--r-lg);
  background:var(--elevated); padding:var(--sp-7);
}
.form-card h2{ font-size:var(--fs-xl); margin-bottom:var(--sp-3); }
.form-card__lead{ color:var(--muted); margin-bottom:var(--sp-6); }
.form-success{
  display:none; border:1px solid rgba(74,222,128,.35); border-radius:var(--r-md);
  background:rgba(74,222,128,.08); padding:var(--sp-6);
}
/* Панель успеха занимает место формы. Приезжает пружиной снизу — это
   завершение действия, которое пользователь только что инициировал. */
.form-success.is-shown{ display:block; animation:success-in 420ms var(--ease-spring); }
@keyframes success-in{
  from{ opacity:0; transform:translateY(12px) scale(.985); }
  to{   opacity:1; transform:none; }
}
.form-success h2{ color:var(--success); font-size:var(--fs-lg); margin-bottom:var(--sp-3); }
.form-success p{ color:var(--muted); line-height:var(--lh-loose); }
.checkbox.is-error span{ color:var(--danger); }
.checkbox.is-error input{ outline:1px solid var(--danger); outline-offset:2px; }
.checkbox-error{
  display:none; margin-top:var(--sp-2);
  font-size:var(--fs-xs); color:var(--danger);
}
.checkbox.is-error + .checkbox-error{ display:block; }

/* --- Страница 404 --- */
.nf{
  min-height:72svh; display:flex; flex-direction:column;
  align-items:center; justify-content:center; text-align:center;
  padding-block:var(--sp-9);
}
.nf__code{
  font-family:var(--font-display); font-weight:800;
  font-size:clamp(4rem, 18vw, 11rem); line-height:.9;
  letter-spacing:var(--ls-tight);
  background:linear-gradient(180deg, var(--text), rgba(var(--accent-rgb),.35));
  -webkit-background-clip:text; background-clip:text; color:transparent;
  margin-bottom:var(--sp-5);
}
.nf p{ color:var(--muted); max-width:var(--measure-lead); margin:var(--sp-4) auto var(--sp-7); line-height:var(--lh-loose); }
.nf__actions{ display:flex; gap:var(--sp-4); flex-wrap:wrap; justify-content:center; }

/* --- Мелочи --- */
.section--tight{ padding-block:var(--sp-8); }
.link-more{
  display:inline-flex; align-items:center; gap:var(--sp-2);
  margin-top:var(--sp-6); color:var(--accent);
  font-family:var(--font-mono); font-size:var(--fs-sm);
}
.link-more:hover{ text-decoration:underline; }
.footer__note{ color:var(--muted); font-size:var(--fs-xs); line-height:var(--lh-loose); margin-top:var(--sp-3); }
.footer__legal{ display:flex; flex-wrap:wrap; gap:var(--sp-3) var(--sp-5); }

/* Заголовки колонок подвала — h2 вместо h4 ради корректной иерархии
   заголовков (без скачка h2 → h4). Вид не меняется. */
.footer h2{
  font-family:var(--font-mono); font-size:var(--fs-xs); text-transform:uppercase;
  letter-spacing:var(--ls-wider); color:var(--muted); margin-bottom:var(--sp-4); font-weight:500;
}

/* Русский h1 главной длиннее английского и при --fs-hero (до 9rem)
   не помещался в 92svh — герой обрезался сверху и снизу.
   Ограничиваем размер именно у h1 внутри .hero, токен не трогаем.

   Э2: заголовок главной стал длиннее (формула «оффер + срок»), при 5rem
   он занимал пять строк на 80px и уводил кнопки за первый экран —
   на 1366×768 на 193px ниже сгиба. Снижаем потолок до 3.5rem и слегка
   поджимаем вертикальные поля героя: кнопки снова видны без прокрутки
   на 1920×1080, 1440×900 и 1366×768. */
.hero h1{
  font-size:clamp(2.25rem, 1rem + 3.1vw, 3.5rem);
  line-height:1.05;
}
.hero{ padding-block:var(--sp-8); }
/* Более широкая шапка секции — заголовки на кириллице длиннее */
.section-head--wide{ max-width:820px; }

/* Кнопка-ссылка в шапке лежит внутри .header__nav, и правило
   `.header__nav a{color:var(--muted)}` перебивало цвет .btn--primary
   по специфичности — текст на оранжевой заливке был серым (плохой контраст).
   Возвращаем кнопкам их собственные цвета. */
.header__nav a.btn--primary{ color:#170B03; }
.header__nav a.btn--primary:hover{ color:#170B03; }
.header__nav a.btn--ghost{ color:var(--text); }
.header__nav a.btn::after{ content:none; }

/* h1 наследует --fs-hero (до 9rem) — на кириллице внутренние заголовки
   разваливались на 5 строк. Ограничиваем только в .page-hero. */
.page-hero h1{
  font-size:clamp(2.25rem, 1.2rem + 3.6vw, 4rem);
  line-height:1.06;
}

/* --- Доводка вертикального ритма внутренних страниц 2026-07-20 ---
   Было padding-block: calc(sp-9 + sp-8) → sp-8, т.е. 232px сверху
   и 88px снизу на 1440px, плюс следующая секция начиналась со
   своих sp-9 (144px). Итог: первый экран почти пустой, контент
   начинался ниже 750px. Сокращаем ~230px: воздух остаётся
   (120px сверху — с запасом над липкой шапкой), но на первом
   экране появляется содержательный контент.
   Полноэкранный герой главной (.hero, 92svh) не трогаем. */
.page-hero{
  padding-block:calc(var(--sp-8) + var(--sp-6)) var(--sp-7);
}
/* Секция сразу после шапки страницы не нуждается в полном
   межсекционном отступе — над ней уже есть разделитель и воздух. */
.page-hero + .section{ padding-top:var(--sp-7); }
/* Заголовок колонки прямых каналов — вровень с заголовком формы */
.channels-title{ font-size:var(--fs-2xl); margin-bottom:var(--sp-4); }

/* --- Внутренние отступы карточек на мобильном 2026-07-20 ---
   .case держал padding:var(--sp-7) (40px), .cta-band — var(--sp-8) (56px).
   На 390px это съедало 80 и 112px ширины: строка заголовка ужималась
   до 260 и 228px соответственно, и длинные русские слова переставали
   помещаться (отсюда разрывы «специализир|ованного», «познакоми|мся»).
   На узких экранах воздух нужен снаружи карточки, а не внутри неё. */
@media (max-width:560px){
  .case{ padding:var(--sp-5); }
  .cta-band{ padding:var(--sp-6) var(--sp-4); }
}

/* На мобильной ширине скрывался только список пунктов, а .header__actions
   (переключатель языка + CTA) оставался: он вылезал за вьюпорт
   (горизонтальный скролл) и перекрывал бургер — меню не открывалось.
   Ниже 900px десктопная навигация не нужна целиком: язык и CTA
   продублированы в мобильном меню.

   2026-07-20, доводка: порог подняли 900 → 1000px. Полная десктопная
   навигация (7 пунктов + язык + CTA) требует 1046px раскладки, поэтому
   на 901–1090px она вылезала за вьюпорт и давала горизонтальный скролл
   (планшет-ландшафт, небольшие ноутбуки). Ниже 1000px — бургер; на 1001–1120px
   ниже сжимаем гэпы, чтобы навигация помещалась с запасом. */
@media (max-width:1000px){
  .header__nav{ display:none; }
}
/* Промежуточная полоса: навигация ещё десктопная, но воздуха в ней
   меньше — иначе не влезает. Экономим ~90px на гэпах и паддинге CTA. */
@media (min-width:1001px) and (max-width:1120px){
  .header__nav{ gap:var(--sp-4); }
  .header__nav ul{ gap:var(--sp-3); }
  .header__actions{ gap:var(--sp-2); }
  .header__nav .btn--sm{ padding-inline:var(--sp-4); }
  .lang-switch button{ min-width:36px; }
}

/* Русские слова длиннее английских: на 390px «автоматизация»,
   «мультитенантного», «маркетплейсах» в крупных кеглях вылезали
   за вьюпорт и давали горизонтальный скролл.
   ВАЖНО (доводка 2026-07-20): здесь раньше стоял hyphens:auto, и он
   рвал по слогам ВСЕ заголовки на всех ширинах — «бизнес-про-цесс»,
   «жи-вотноводства», в EN «aud-it», «prod-uction». Для заголовков это
   читается как брак. Заголовки короткие, автоперенос им не нужен:
   оставляем только overflow-wrap:break-word как страховку от скролла —
   он срабатывает лишь тогда, когда слово физически не влезает в строку.
   Отсутствие переносов по слогам и скролла проверено на 17 страницах
   × 10 ширин (390…1920) скриптом check_hyphens.py. */
h1, h2, h3, h4,
.stat__value, .product__tagline, .channel__value, .footer__brand{
  overflow-wrap:break-word;
  hyphens:none;
  -webkit-hyphens:none;
}
/* На узких экранах (≤600px) несколько русских слов в 13–19 букв шире
   своей колонки при любом разумном кегле, и без переноса браузер рвал
   бы их посреди слова без дефиса. Там включаем hyphens:manual — это
   НЕ автоперенос по словарю, а перенос строго по мягким дефисам &shy;,
   расставленным вручную в заголовках (см. apply_shy.py). Полный
   контроль: где мы разрешили — там и переносится, с дефисом.
   Выше 600px действует hyphens:none — мягкие дефисы игнорируются,
   заголовки не переносятся по слогам вообще. */
@media (max-width:600px){
  h1, h2, h3, h4{ hyphens:manual; -webkit-hyphens:manual; }
}
.checklist li, .meta-value, .case__block p, .case__stack, .kv__value, .prose p{
  overflow-wrap:break-word;
}

/* --- Доводка типографики 2026-07-20 ---
   Правило выше давало hyphens:auto всем заголовкам, и в крупном
   дисплейном кегле это читалось как брак: «бизнес-про-цесс»,
   «конвейе-р», «pipel-ine». Для h1 в героях автоперенос выключаем
   совсем (hyphens:manual — мягкие переносы &shy; в разметке, если
   когда-нибудь понадобятся, продолжат работать).
   overflow-wrap:break-word остаётся страховкой от скролла: он
   срабатывает только если слово физически не влезает в строку —
   на текущих кеглях этого не происходит (проверено 390–1920px).
   text-wrap:balance выравнивает длины строк, чтобы заголовок
   не заканчивался одиноким словом-сиротой. */
.hero h1, .page-hero h1{
  hyphens:none;
  -webkit-hyphens:none;
  text-wrap:balance;
}

/* Русская фраза «Ваш бизнес-процесс. Рой ИИ-агентов.» в 900px
   не помещалась в две строки и рвалась по слогам. Дисплейному
   заголовку даём больше меры, чем лид-абзацу (у .hero__lead
   свои 56ch) — классическая пара «широкий заголовок + узкий лид».
   С 1180px на десктопе фраза ложится ровно в 2 строки
   по границе предложений. */
.hero__content{ max-width:1180px; }
.hero__eyebrow, .hero__lead, .hero__actions{ max-width:var(--measure-lead); }

/* ============================================================
   Бренд-локап (2026-07-20): эмблема рядом с eyebrow в hero
   главной + крупный бренд-блок (эмблема + глянцевый вордмарк)
   в начале страницы «О компании».
   ============================================================ */
.hero__brand-mark{
  display:flex; align-items:center; gap:var(--sp-3);
  margin-bottom:var(--sp-5);
}
.hero__brand-mark .hero__eyebrow{ margin-bottom:0; }
.hero__brand-mark img{
  width:56px; height:56px; flex-shrink:0; display:block;
}
@media (max-width:480px){
  .hero__brand-mark img{ width:40px; height:40px; }
}

.brand-lockup{
  display:flex; flex-direction:column; align-items:center;
  gap:var(--sp-5); text-align:center;
  padding-top:var(--sp-8); padding-bottom:var(--sp-3);
}
.brand-lockup__emblem{ width:64px; height:64px; display:block; }
/* <picture> вокруг вордмарка (WebP + PNG-фолбэк) — обёртка не должна
   вмешиваться во флекс-раскладку локапа. */
.brand-lockup picture{ display:block; max-width:100%; min-width:0; }
.brand-lockup__wordmark{
  width:380px; max-width:100%; height:auto; display:block;
}
@media (max-width:560px){
  .brand-lockup__wordmark{ width:300px; }
}

/* --- Прайс-карточка: таблица условий + список «что не входит» внутри .card.
       Раскладку даёт существующий bento/card/kv/checklist, здесь только
       вертикальные отступы стыков.
       Доводка ритма: было margin-block:sp-5/sp-4 у таблицы плюс sp-2 у
       следующего за ней подзаголовка — стык «таблица → Что не входит»
       получался 8px, а стык «список → подзаголовок» 24px, хотя это
       один и тот же уровень членения. Теперь оба зазора равны sp-5,
       и все прайс-карточки набираются одним ритмом. --- */
.card .kv{
  margin-block:var(--sp-5);
  /* В .card--wide (полная ширина bento, до 1232px) строка «ЦЕНА … 120 000 ₽»
     разносила подпись и значение на метр друг от друга: пара переставала
     читаться как пара. Таблица условий не должна быть шире текста
     карточки. На обычных карточках (≈590px) ограничение не срабатывает. */
  max-width:var(--measure-text);
}
.card .kv__row{ padding-block:var(--sp-3); }
.card .kv__value{ font-size:var(--fs-sm); }
.card .checklist li{ font-size:var(--fs-sm); }
.card .checklist + .card__label{ margin-top:var(--sp-5); }
.card .kv + .card__label{ margin-top:0; }
/* Подзаголовки блоков «Что входит» / «Что не входит» набраны <h4> ради
   корректного дерева заголовков внутри карточки прайса (h3 → h4).
   Специфичность класса .card__label (0,1,0) выше, чем у элементных
   правил h4 в base.css (0,0,1), поэтому <h4 class="card__label"> и
   <span class="card__label"> выглядят идентично — отдельное правило
   не нужно и только рассинхронизировало бы их. */

/* Итоговая плашка прайса идёт сразу за bento-сеткой карточек —
   раньше отступ ставился инлайном style="margin-top:var(--sp-7)". */
.bento + .callout{ margin-top:var(--sp-7); }

/* --- Подвал: подпись бренда. Была инлайновым style на всех 19 страницах
       (color/font-size/max-width), теперь класс. --- */
.footer__brand span{ color:var(--accent); }
.footer__tagline{
  color:var(--muted); font-size:var(--fs-sm);
  max-width:34ch; line-height:var(--lh-loose);
}

/* --- Заголовок текстовой колонки в .split: раньше отступы задавались
       инлайном style="margin:var(--sp-3) 0 var(--sp-5)". --- */
.split .eyebrow + h2{ margin:var(--sp-3) 0 var(--sp-5); }
.split__lead{
  color:var(--muted); line-height:var(--lh-loose);
  max-width:var(--measure-text);
}

/* --- Мелкий текст-оговорка под блоком (дисклеймер, «не является офертой»).
       Был инлайном на главной RU/EN. --- */
.note{
  margin-top:var(--sp-5); max-width:var(--measure-lead);
  color:var(--muted); font-size:var(--fs-sm); line-height:var(--lh-loose);
}
/* --- Вводный абзац колонки прямых каналов --- */
.channels-lead{
  color:var(--muted); line-height:var(--lh-loose);
  margin:var(--sp-4) 0 var(--sp-6); max-width:var(--measure-text);
}
/* --- Уточнение под значением канала связи --- */
.channel__note{
  display:block; margin-top:var(--sp-2);
  color:var(--muted); font-size:var(--fs-xs); line-height:var(--lh-loose);
}
/* --- Строка действия в карточке формы --- */
.form-card .row{ margin-top:var(--sp-6); }
/* --- Список после пилюли статуса продукта --- */
.pill + .checklist{ margin-top:var(--sp-5); }


/* ============================================================
   Юридические страницы (/privacy/, /consent/ + EN)
   Раньше эти правила лежали инлайновым <style> в каждой из четырёх
   страниц — с комментарием «идентичны друг другу». Идентичны они
   не были (RU-копии отстали от EN на блок .legal__prevails), и
   расходились бы дальше. Один источник правды — здесь.
   ============================================================ */
.legal{ padding-block:var(--sp-9); }
/* h1 юридической страницы уходит в 3–4 строки. Базовый --lh-tight (0.95)
   рассчитан на однострочный дисплейный заголовок героя; здесь строки
   сцеплялись. 1.05 — то же значение, что у .page-hero h1. */
.legal__header{ margin-bottom:var(--sp-7); max-width:var(--measure-text); }
.legal__header h1{ line-height:1.05; margin-bottom:var(--sp-4); }
.legal__updated{
  color:var(--muted); font-family:var(--font-mono);
  font-size:var(--fs-xs); margin-top:var(--sp-2);
}
.legal__body{ max-width:var(--measure-text); }
/* Юридический документ читают по оглавлению и по номерам пунктов,
   поэтому ритм заголовков здесь важнее, чем на маркетинговых
   страницах: sp-8 сверху отбивает новый раздел, sp-4 снизу
   привязывает заголовок к своему тексту, а не к предыдущему. */
.legal__body h2{
  font-family:var(--font-display); font-size:var(--fs-lg);
  margin-top:var(--sp-8); margin-bottom:var(--sp-4);
}
.legal__body h2:first-child{ margin-top:0; }
.legal__body p{ color:var(--muted); margin-bottom:var(--sp-4); line-height:var(--lh-loose); }
.legal__body ul, .legal__body ol{
  color:var(--muted); margin:0 0 var(--sp-4) var(--sp-5);
  line-height:var(--lh-loose);
}
/* base.css гасит маркеры у всех списков (`ul,ol{list-style:none}`) —
   это верно для навигации и карточек, но в юридическом тексте
   убивает нумерацию пунктов и маркеры перечислений: списки читались
   как слипшиеся абзацы с отступом. Здесь маркеры возвращаются. */
.legal__body ul{ list-style:disc; }
.legal__body ol{ list-style:decimal; }
.legal__body li{ margin-bottom:var(--sp-2); }
.legal__body li::marker{ color:var(--muted); }
.legal__body strong{ color:var(--text); font-weight:500; }

.legal__toc{
  border:1px solid var(--line); border-radius:var(--r-md);
  background:var(--surface);
  padding:var(--sp-5); margin-bottom:var(--sp-8);
  max-width:var(--measure-text);
}
/* Заголовок оглавления — служебный лейбл, а не ступень иерархии:
   моноширинный капс, как .card__label / .meta-label по всему сайту.
   Раньше он набирался пропорциональным fs-sm и читался как
   полноценный заголовок наравне с пунктами документа. */
.legal__toc h2{
  font-family:var(--font-mono); font-size:var(--fs-xs); font-weight:500;
  text-transform:uppercase; letter-spacing:var(--ls-wider);
  color:var(--muted); margin-bottom:var(--sp-4);
}
.legal__toc ol{ margin:0; padding-left:var(--sp-5); list-style:decimal; display:grid; gap:var(--sp-2); }
.legal__toc li::marker{ color:var(--muted); font-family:var(--font-mono); font-size:var(--fs-xs); }
.legal__toc a{ color:var(--text); }
.legal__toc a:hover{ color:var(--accent); }

/* Оговорка о преимущественной силе — единственный блок страницы,
   который нельзя пролистать: вынесен из потока абзацев. */
.legal__prevails{
  margin-top:var(--sp-7); padding:var(--sp-5);
  border:1px solid rgba(var(--ember-rgb),.35); border-radius:var(--r-md);
  background:rgba(var(--ember-rgb),.06);
  max-width:var(--measure-text);
}
.legal__prevails p{ color:var(--text); margin-bottom:0; }
