picture{display:contents}
@font-face{font-family:'Bounded';src:url(../fonts/bounded-900.woff2) format('woff2');font-weight:900;font-display:swap}
@font-face{font-family:'Bounded';src:url(../fonts/bounded-700.woff2) format('woff2');font-weight:700;font-display:swap}
@font-face{font-family:'Bounded';src:url(../fonts/bounded-700.woff2) format('woff2');font-weight:800;font-display:swap}
@font-face{font-family:'Involve';src:url(../fonts/involve-400.woff2) format('woff2');font-weight:400;font-display:swap}
@font-face{font-family:'Involve';src:url(../fonts/involve-500.woff2) format('woff2');font-weight:500;font-display:swap}
@font-face{font-family:'Involve';src:url(../fonts/involve-600.woff2) format('woff2');font-weight:600;font-display:swap}


:root{
  /* Единственная тема — тёмная. Крем стал цветом текста, чёрный — фоном,
     оранжевый акцент прежний. Всё через токены: хардкод цветов не добавлять. */
  /* Тема одна — тёмная. Без color-scheme браузер рисует системные элементы
     (раскрытый список select, полосы прокрутки, автозаполнение) по светлой
     схеме: получался светлый текст на белом фоне и список было не прочесть. */
  color-scheme: dark;
  /* Системный акцент у ползунков, флажков и переключателей — иначе браузер
     красит их своим фиолетовым, мимо палитры сайта. */
  accent-color: #F0611A;

  --cream:#0D0D0D;        --cream-rgb:13,13,13;      /* фон страницы */
  --surface:#141414;      /* подложки чуть светлее фона: карточки, плейсхолдеры */
  --ink:#F8F4EC;          --ink-rgb:248,244,236;     /* текст и светлые полосы */
  --ink-2:#1E1E1E;        /* подложка внутри блоков поверх фона */
  --accent:#F0611A;       --accent-rgb:240,97,26;
  --accent-dark:#D34F0E;  /* ховер оранжевой кнопки */
  /* В палитре проекта нет красного — этот токен только для ошибок валидации
     формы конструктора (найдено в аудите 2026-09-07: было захардкожено
     напрямую в constructor.css в 5 местах, без единого источника). */
  --danger:#c0392b;
  --placeholder:#1C1C1C;  /* фон под ещё не загруженной картинкой */
  --map-fill:#1A1A1A;     --map-stroke:#F8F4EC;      /* карта России */

  /* Подвал и финальный CTA — тот же тёмный, но своими токенами: они не зависят
     от темы страницы, ими же красятся оверлеи поверх фотографий и lightbox. */
  --dark-bg:#0D0D0D;      --dark-bg-rgb:13,13,13;
  --dark-fg:#F8F4EC;      --dark-fg-rgb:248,244,236;

  /* Тёплое свечение сверху у завершающих призывов: финал главной (.fin) и
     «Следующий проект — ваш» в галерее (.gal-cta). Один токен на оба блока —
     заказчику эффект понравился, и если его подправят, блоки не разъедутся.
     Прозрачное ниже 62%, поэтому фоновое зерно под ним сохраняется. */
  --glow-warm:radial-gradient(120% 95% at 50% 0%,rgba(var(--accent-rgb),.12),transparent 62%);

  --muted:rgba(var(--ink-rgb),.62);
  --rule:rgba(var(--ink-rgb),.18);
  --pad:clamp(20px,5vw,72px);
  /* Высота шапки вынесена в токен: шапка теперь лежит поверх контента,
     и этот же размер отдаётся <main> как отступ сверху. */
  --hdr-h:74px;
}

*{box-sizing:border-box}
/* Шапка фиксированная и перекрывает верх страницы — без этого отступа
   переход по якорю (#tech, #faq) прятал заголовок секции под неё. */
html{scroll-behavior:smooth;scroll-padding-top:calc(var(--hdr-h) + 12px)}
body{margin:0;background:var(--cream);color:var(--ink);font-family:'Involve',system-ui,sans-serif;-webkit-font-smoothing:antialiased;overflow-x:hidden}
/* Тонкое зерно поверх фона: убирает ощущение «плоской заливки», на глаз почти
   не читается, но страница перестаёт выглядеть как пустой лист. */
body::before{content:"";position:fixed;inset:0;z-index:0;pointer-events:none;opacity:.5;
  background-image:radial-gradient(rgba(var(--ink-rgb),.16) .6px,transparent .6px);
  background-size:3px 3px}
body>*{position:relative;z-index:1}
/* ЗЕРНО И ЗАЛИВКИ — правило, которое нельзя нарушать при добавлении блоков.
   Зерно выше лежит ПОД содержимым (z-index:0 против 1), поэтому любой блок с
   непрозрачной заливкой его закрывает. А так как --cream и --dark-bg — это
   ровно тот же #0D0D0D, что и фон страницы, такой блок не выглядит «другим
   цветом»: он выглядит прямоугольником, в котором выключили текстуру. Именно
   это заказчик и увидел как «у каких-то блоков чёрный фон» (13.09).
   Отсюда три правила:
   1. Секция во всю ширину НЕ красится вообще — зерно идёт через всю страницу.
   2. Карточке нужна своя заливка (иначе не карточка) — она берёт --surface,
      он на тон светлее фона и читается как поднятая плашка, а не как дыра.
   3. Непрозрачный --cream оправдан только там, где под блоком физически
      что-то проезжает (липкие панели) или он лежит поверх затемнения. */
img{max-width:100%;display:block}
/* Блоки во всю ширину экрана: колонка 1240px оставляла на широких мониторах
   пустые поля по бокам и делала страницу «недозаполненной». Остаётся только
   отступ --pad, чтобы текст не прилипал к краю. */
.wrap{width:100%;margin:0 auto;padding:0 var(--pad)}
/* Длина строки ограничивается у самого текста, а не у контейнера. */
.lede,.sec-note,.inner-lede p{max-width:64ch}
section{position:relative}

/* ---------- ПОЯВЛЕНИЕ ПРИ СКРОЛЛЕ ---------- */
.reveal{opacity:0;transform:translateY(26px);transition:opacity .65s ease,transform .65s cubic-bezier(.22,1,.36,1)}
.reveal.on{opacity:1;transform:none}
.reveal-l{opacity:0;transform:translateX(-34px);transition:opacity .7s ease,transform .7s cubic-bezier(.22,1,.36,1)}
.reveal-l.on{opacity:1;transform:none}
.reveal-r{opacity:0;transform:translateX(34px);transition:opacity .7s ease,transform .7s cubic-bezier(.22,1,.36,1)}
.reveal-r.on{opacity:1;transform:none}
/* Карточки: подъём, тень и акцентная кромка сверху.
   Подъём делаем отдельным свойством translate, а не transform: у этих же
   элементов transform занят появлением по скроллу (.reveal), и два перехода
   на одном свойстве с разной длительностью давали двойную анимацию на ховере. */
.cols .c,.org .o{position:relative;
  transition:translate .4s cubic-bezier(.22,1,.36,1),box-shadow .4s ease,background .4s ease}
/* Анимированная кромка — только там, где нет своей постоянной. У .org .o уже есть
   статичный border-top:3px accent; добавлять поверх него ещё и скользящий бар того
   же цвета — та самая «двойная анимация» одной и той же полосы. */
.cols .c::after{content:"";position:absolute;left:0;right:0;top:0;height:3px;
  background:var(--accent);transform:scaleX(0);transform-origin:left;
  transition:transform .45s cubic-bezier(.22,1,.36,1)}
/* Ховер уводит на --ink-2: сами карточки теперь лежат на --surface, и подсветка
   в тот же --surface была бы подсветкой в собственный цвет, то есть никакой. */
.cols .c:hover,.org .o:hover{translate:0 -7px;
  box-shadow:0 22px 44px -18px rgba(var(--ink-rgb),.35);background:var(--ink-2)}
.cols .c:hover::after{transform:scaleX(1)}
.tstats .st{transition:background .3s ease,translate .3s ease}
.tstats .st:hover{background:rgba(var(--accent-rgb),.06);translate:0 -3px}

/* ---------- ОЖИВШАЯ ШАПКА ---------- */
.hdr{transition:background .35s ease,backdrop-filter .35s ease,
  border-color .35s ease,box-shadow .35s ease}
.brand img.lockup{transition:transform .3s ease}
.brand:hover img.lockup{transform:scale(1.04)}

/* ---------- ОЖИВШАЯ НИЖНЯЯ НАВИГАЦИЯ ---------- */
.bnav{position:fixed}
/* Оранжевой точки-индикатора над активным пунктом больше нет: активный пункт
   теперь сам залит оранжевой капсулой (см. блок @media ниже), и точка поверх
   заливки только зашумляла бы её. */
.bnav a{position:relative;transition:color .25s ease}
.bnav a svg{transition:transform .25s cubic-bezier(.34,1.56,.64,1)}
.bnav a.on svg{transform:translateY(-2px) scale(1.08)}

@media (prefers-reduced-motion:reduce){
  .reveal,.reveal-l,.reveal-r{opacity:1!important;transform:none!important;transition:none!important}
  .cols .c,.org .o,.tstats .st{transition:none!important}
  .cols .c:hover,.org .o:hover,.tstats .st:hover{translate:none}
  .cols .c::after{display:none}
}

/* ---------- РАЗНЫЕ ЭФФЕКТЫ ПО РАЗНЫМ БЛОКАМ ---------- */

/* заголовок "протирается" маской, а не сдвигается */
.mask-h{position:relative}
.mask-h>span{display:block;clip-path:inset(0 100% 0 0);transition:clip-path 1s cubic-bezier(.65,0,.35,1)}
.mask-h.on>span{clip-path:inset(0 0 0 0)}

/* счётчики цифр */
.cnt{font-variant-numeric:tabular-nums}

/* непрерывный медленный зум фото в конструкторе (Ken Burns) */
/* Кадры горизонтальные и по пропорциям почти совпадают с блоком, фигура
   стоит в центре — поэтому масштабируем от центра, запаса хватает со всех
   сторон. С портретными фото так было нельзя: наезд срезал голову. */
.cyc-img{animation:kenBurns 9s ease-in-out infinite alternate;transform-origin:center}
@keyframes kenBurns{from{transform:scale(1)}to{transform:scale(1.055)}}

/* галерея — увеличение вместо сдвига */
.reveal-zoom{opacity:0;transform:scale(.88);transition:opacity .6s ease,transform .6s cubic-bezier(.22,1,.36,1)}
.reveal-zoom.on{opacity:1;transform:scale(1)}

/* свой плавный аккордеон FAQ (вместо резкого нативного) */
.faq-item summary{cursor:pointer}
.faq-item .body{overflow:hidden;max-height:0;transition:max-height .4s cubic-bezier(.22,1,.36,1)}
.faq-item .body p{margin:0 0 22px;font-size:14.5px;line-height:1.65;color:var(--muted);max-width:70ch}
.faq-item summary::after{transition:transform .3s ease}
.faq-item.faq-open summary::after{transform:rotate(45deg)}

@media (prefers-reduced-motion:reduce){
  .mask-h>span{clip-path:inset(0 0 0 0)!important;transition:none!important}
  .cyc-img{animation:none!important}
  .reveal-zoom{opacity:1!important;transform:none!important;transition:none!important}
  .faq-item .body{transition:none!important}
}

/* ---------- ССЫЛКА ДЛЯ КЛАВИАТУРЫ ---------- */
.skip{position:absolute;left:-9999px;top:0;z-index:200;background:var(--accent);color:var(--cream);
  padding:12px 20px;font-weight:600;font-size:14px;text-decoration:none;border-radius:0 0 6px 0}
.skip:focus{left:0}

/* ---------- ФИРМЕННАЯ ПРОШИВКА ---------- */
.stitch{display:block;width:100%;height:14px;overflow:visible;margin:clamp(24px,4vh,48px) 0}
.stitch line{stroke:var(--accent);stroke-width:2.5;stroke-linecap:round;stroke-dasharray:11 9;
  opacity:0;transition:opacity .6s ease}
.stitch.on line{opacity:1;animation:stitchRun 1.4s linear infinite}
@keyframes stitchRun{to{stroke-dashoffset:-40}}
@media (prefers-reduced-motion:reduce){
  .stitch.on line{animation:none}
}
.seam{margin:0;border:0;height:1px;background:var(--rule)}
.eyebrow{display:inline-flex;align-items:center;gap:10px;font-weight:600;font-size:11.5px;
  text-transform:uppercase;letter-spacing:.14em;color:var(--accent);margin-bottom:18px}
.eyebrow::before{content:"";width:26px;height:2px;background:var(--accent);
  -webkit-mask:repeating-linear-gradient(90deg,#000 0 5px,transparent 5px 9px);
  mask:repeating-linear-gradient(90deg,#000 0 5px,transparent 5px 9px)}
h2.h{font-family:'Bounded';font-weight:800;font-size:clamp(30px,4.2vw,54px);line-height:1.04;
  /* 26ch, а не 20ch: при 20 знаках заголовки дробились на 3–5 коротких строк
     даже на широком экране (замер 13.09 на 1440px: 63 строки на все
     заголовки главной, с 26ch и выравниванием ниже — 56). */
  letter-spacing:-.025em;margin:0 0 14px;max-width:26ch;
  /* Страховка от длинных русских слов: «Профессиональная» на 30px занимает
     379px и на телефоне 360px вылезала за экран — вместе с ней горизонтально
     разъезжалась вся страница, из-за чего у шапки уходили за край мессенджеры,
     а у нижней панели — пункт «Заявка». overflow-wrap остаётся: он рвёт слово
     только если оно физически не влезает в колонку.
     Перенос по слогам (hyphens:auto) снят по просьбе заказчика: мобильный
     кегль ниже подобран так, что самое длинное слово помещается целиком, и
     замер на 360/375/768/1440 не нашёл ни одного слова, которому перенос был
     бы нужен. */
  overflow-wrap:break-word;hyphens:manual}

/* ---------- ПЕРЕНОСЫ СТРОК ---------- */
/* Заказчик (13.09): «на сайте очень много переносов». Разрывов по слогам при
   замере не нашлось — «переносами» выглядели ВИСЯЧИЕ СЛОВА: последнее слово
   заголовка одно на строке («Победа до начала / игры», «Что говорят /
   команды»). На 1440px таких заголовков было 7, на телефоне — 12.

   balance выравнивает длину строк заголовка, и одиночное слово внизу
   исчезает; pretty делает то же для последней строки абзаца, но дешевле —
   балансировать длинный текст целиком браузеру дорого. Старые браузеры
   правило молча пропускают и показывают как раньше — ломаться нечему.
   Замер после: висячих слов в заголовках 0 и на 1440, и на 375. */
h1,h2,h3,summary{text-wrap:balance}
p,li,.lede{text-wrap:pretty}

/* Заголовки в узких колонках. Кегль 54px рассчитан на заголовок во всю
   ширину, а три заголовка стоят в колонках на 500–680px — там в строку
   влезало по одному-два слова, и «Создай дизайн не такой, как у всех»
   занимал 4 строки. Только для широкого экрана: на телефоне эти колонки и так
   во всю ширину, и там работает свой мобильный кегль ниже — без
   ограничения это правило перебивало его и добавляло строк. */
@media (min-width:901px){
  .ctor-info h2.h,.rev-side h2.h,#quiz h2.h{font-size:clamp(28px,3.1vw,44px);max-width:none}
}
/* На узких экранах уменьшаем кегль до размера, при котором самое длинное слово
   в заголовках помещается в колонку без переноса: 6.4vw на 360px — это 23px,
   слово занимает ~290px при доступных 320px. */
@media (max-width:600px){
  h2.h{font-size:clamp(22px,6.4vw,30px)}
}
/* `.inner-lede p` — то же правило для абзаца внутри виджета Elementor.
   Перенос класса внутрь (хук igoshi_elementor_inner_classes) работает для
   заголовков и кнопок, но НЕ для текстового редактора: в Elementor 4.x
   с оптимизированной разметкой содержимое печатается без обёртки, и
   render-атрибут `editor`, которому хук дописывает класс, никуда не
   попадает. Значение одно, селектора два — дубля стилей нет. */
.lede,.inner-lede p{font-size:17px;line-height:1.62;color:var(--muted);max-width:52ch;margin:0 0 36px}
.pad{padding:clamp(56px,7vh,92px) 0}
/* Кнопки-призывы: подъём + тень + световой блик, пробегающий по диагонали.
   Один компонент на все три страницы — правится один раз, работает везде. */
/* Кнопки: заливка «наливается» снизу вверх, стрелка выезжает справа.
   Никаких бликов и подпрыгиваний — движение читается как заполнение, а не как
   мигание. Один компонент на все три страницы. */
.btn{position:relative;overflow:hidden;isolation:isolate;
  font-weight:600;font-size:15px;padding:15px 30px;border-radius:5px;text-decoration:none;
  display:inline-flex;align-items:center;gap:8px;border:1.5px solid transparent;cursor:pointer;font-family:'Involve';
  transition:color .3s ease,border-color .3s ease,box-shadow .35s ease}
.btn::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  transform:scaleY(0);transform-origin:bottom;
  transition:transform .42s cubic-bezier(.65,0,.35,1)}
.btn:hover::before,.btn:focus-visible::before{transform:scaleY(1)}
/* стрелка: ширины нет, пока не навели — текст не «прыгает» при появлении */
.btn::after{content:"→";font-size:1.05em;line-height:1;width:0;opacity:0;
  transform:translateX(-6px);
  transition:width .35s cubic-bezier(.22,1,.36,1),opacity .3s ease,transform .35s cubic-bezier(.22,1,.36,1)}
.btn:hover::after,.btn:focus-visible::after{width:1em;opacity:1;transform:translateX(0)}
.btn:active{transform:scale(.985);transition-duration:.1s}

/* Белый текст на акценте — 3.03:1, не проходит AA (нужно 4.5:1) для
   15px/600. Тёмный текст на этом же оранжевом даёт ~6.4:1 — стандартный
   паттерн для ярких/тёплых акцентов (найдено в аудите 2026-09-07). */
.btn.solid{background:var(--accent);color:var(--cream)}
.btn.solid::before{background:var(--ink)}
.btn.solid:hover,.btn.solid:focus-visible{color:var(--cream);
  box-shadow:0 12px 30px -14px rgba(var(--ink-rgb),.6)}

.btn.line{background:transparent;color:var(--ink);border-color:rgba(var(--ink-rgb),.3)}
.btn.line::before{background:var(--accent)}
.btn.line:hover,.btn.line:focus-visible{color:var(--cream);border-color:var(--accent)}
/* В hero кнопка «Получить каталог» лежит на фото/видео, а не на ровном
   тёмном фоне, как у .fin/.ctor-info. Полупрозрачная подложка (даже с
   блюром) на пёстром кадре всё равно терялась — пользователь дважды
   отмечал, что её не видно (2026-09-07). Сплошная светлая заливка —
   единственный вариант, который заметен на любом кадре карусели без
   исключений; ховор — обычная заливка акцентом снизу, как у остальных
   .btn.line на сайте. */
.hero .btn.line{border-width:1.5px;border-color:var(--ink);
  background:var(--ink);color:var(--cream)}

.btn:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
@media (prefers-reduced-motion:reduce){
  .btn::before{display:none}
  .btn::after{display:none}
  .btn.solid:hover{background:var(--accent-dark);color:var(--cream)}
  .btn.line:hover{border-color:var(--accent);color:var(--accent)}
}
/* flex-direction и второй селектор — из-за Elementor: его контейнер ставит
   .e-con{flex-direction:var(--flex-direction)} со значением column, и в
   финальном блоке кнопки «Создать форму» и «Стать партнёром» вставали одна
   под другой вместо строки. Направление задано явно, вес поднят до двух
   классов — правило перестаёт зависеть от порядка подключения файлов. */
.acts,.e-con.acts{display:flex;flex-direction:row;gap:12px;flex-wrap:wrap}
/* Отбивка перед тремя колонками. Тоже была инлайном в статике. */
#why .acts{margin-bottom:40px}

/* ---------- ШАПКА ---------- */
/* Шапка не занимает места в потоке, а лежит поверх контента: за счёт этого
   видео в hero видно под ней до самого верха экрана. Отступ, который она
   раньше занимала, отдан <main> ниже. Плёнка почти прозрачная — плотнеет
   только после ухода с hero (.scrolled). */
.hdr{position:fixed;top:0;left:0;right:0;z-index:90;
  background:rgba(var(--cream-rgb),.26);
  backdrop-filter:blur(18px) saturate(140%);
  -webkit-backdrop-filter:blur(18px) saturate(140%);
  border-bottom:1px solid rgba(var(--ink-rgb),.08)}
/* .82 не хватало на галерее: светлые фото просвечивали сквозь шапку
   и зашумляли капсулу меню. На hero плёнка по-прежнему .26. */
.hdr.scrolled{background:rgba(var(--cream-rgb),.92);
  border-bottom-color:rgba(var(--ink-rgb),.14);
  box-shadow:0 8px 30px rgba(0,0,0,.35)}
/* Шапка вынута из потока — отступ под неё держит main.
   Hero этот отступ гасит отрицательным margin и подкладывает его себе
   внутрь, поэтому фон уходит под шапку, а заголовок — нет. */
main{padding-top:var(--hdr-h)}
.hero{margin-top:calc(-1 * var(--hdr-h));padding-top:var(--hdr-h)}
/* Сетка 1fr auto 1fr: навигация стоит ровно по центру экрана независимо от
   того, насколько широки логотип слева и группа кнопок справа. */
/* Сетка 1fr auto 1fr: навигация ровно по центру экрана, слева логотип
   с телефоном, справа мессенджеры и кнопка — вес по краям одинаковый. */
.hdr .row{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:24px;
  height:var(--hdr-h);transition:height .3s ease}
.hdr.scrolled .row{height:64px}
/* Без min-width:0 — иначе колонка сжимается уже своего содержимого, и логотип
   с телефоном вылезают за её границы поверх меню. Колонка 1fr по умолчанию
   не уже max-content, и это ровно то поведение, которое здесь нужно:
   при нехватке места ужимается навигация (у неё auto), а не логотип. */
.hdr-left{display:flex;align-items:center;gap:clamp(12px,1.6vw,26px);justify-self:start}
.hdr-left .brand,.hdr-left .brand img{flex:0 0 auto}
.hdr nav{justify-self:center}
.hdr-actions{justify-self:end}
.brand{display:flex;align-items:center;gap:10px;text-decoration:none}
.brand img{height:30px;filter:invert(1)}
.brand img.lockup{height:32px;width:auto;filter:none}
.brand b{font-family:'Bounded';font-weight:900;font-size:15px;color:var(--ink);letter-spacing:-.01em}
.brand b i{color:var(--accent);font-style:normal}
/* --- навигация: капсула с подсветкой, которая скользит между пунктами --- */
/* Капсула — «стекло в стекле»: чуть темнее шапки, поэтому читается
   как отдельный элемент даже поверх светлых кадров видео. */
.hdr nav{position:relative;display:flex;align-items:center;gap:2px;
  background:rgba(var(--cream-rgb),.34);border:1px solid rgba(var(--ink-rgb),.13);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  border-radius:999px;padding:5px}
.hdr nav a{position:relative;z-index:1;font-weight:600;font-size:13.5px;
  color:rgba(var(--ink-rgb),.72);
  text-decoration:none;white-space:nowrap;padding:9px 16px;border-radius:999px;
  transition:color .25s ease}
.hdr nav a:hover,.hdr nav a.on{color:var(--cream)}
.hdr nav a:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* Конструктор — флагманская фича, а не рядовой пункт меню: лёгкая рамка
   держит его заметным даже когда капсула наведения не над ним. Ховер и
   .on всё равно перекрывают рамку заливкой — border остаётся виден по
   краям капсулы, конфликта с ::before (z-index:-1) нет. */
.hdr nav a.nav-cta{border:1px solid rgba(var(--accent-rgb),.55)}
/* Текущая страница залита постоянно — ховерная капсула ездит поверх неё. */
.hdr nav a.on::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:999px;
  background:rgba(var(--accent-rgb),.9)}
/* Подсветка — один элемент, который JS передвигает под наведённый пункт
   (main.js, блок «капсула навигации»), а не отдельная анимация на каждой ссылке. */
.nav-pill{position:absolute;z-index:0;top:5px;left:0;height:calc(100% - 10px);
  border-radius:999px;background:var(--accent);
  box-shadow:0 4px 16px rgba(var(--accent-rgb),.42);
  opacity:0;transform:translateX(0);width:0;pointer-events:none;
  transition:transform .3s cubic-bezier(.22,1,.36,1),width .3s cubic-bezier(.22,1,.36,1),opacity .2s ease}
.nav-pill.on{opacity:1}
@media (prefers-reduced-motion:reduce){
  .nav-pill{transition:opacity .2s ease}
}

/* --- правая группа: соцсети, телефон, CTA --- */
.hdr-actions{display:flex;align-items:center;gap:14px}

.hdr-social{display:flex;align-items:center;gap:6px}
.hdr-social a{width:34px;height:34px;display:flex;align-items:center;justify-content:center;
  border-radius:999px;color:rgba(var(--ink-rgb),.72);border:1.5px solid transparent;
  transition:color .25s ease,border-color .25s ease,transform .3s cubic-bezier(.34,1.56,.64,1)}
.hdr-social a svg{width:17px;height:17px;fill:currentColor}
.hdr-social a:hover{color:var(--accent);border-color:rgba(var(--accent-rgb),.45);transform:translateY(-2px)}
.hdr-social a:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

.hdr-tel{display:inline-flex;align-items:center;gap:8px;text-decoration:none;color:var(--ink);
  padding:8px 12px;border-radius:8px;transition:background .25s ease,color .25s ease}
.hdr-tel svg{width:16px;height:16px;fill:currentColor;color:var(--accent);flex:0 0 auto;
  transition:transform .4s cubic-bezier(.34,1.56,.64,1)}
.hdr-tel b{font-family:'Bounded';font-weight:700;font-size:13.5px;white-space:nowrap;letter-spacing:-.01em}
.hdr-tel:hover{background:rgba(var(--accent-rgb),.1);color:var(--accent)}
.hdr-tel:hover svg{transform:rotate(-14deg) scale(1.1)}
.hdr-tel:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* Кнопка в шапке: не переносится на две строки и не даёт стрелке раздвигать
   ширину — из-за этого при наведении вся шапка «дышала». */
.hdr-cta{padding:12px 24px;font-size:13.5px;white-space:nowrap;flex:0 0 auto;border-radius:6px}
.hdr-cta::after{display:none}

/* Шапка ужимается по приоритету. На планшете уходит текст телефона,
   на мобильном — кнопка заявки: она и так продублирована в нижней навигации,
   а вместо неё в шапку возвращаются мессенджеры. */
/* Шапка ужимается по приоритету, и пороги подобраны по реальной ширине
   содержимого: на 1160px логотип с телефоном требовали 220px, а сетка
   отдавала им 110 — номер наезжал на меню. Текст телефона уходит раньше
   всего, потому что он же продублирован в подвале и в мессенджерах. */
/* 1560, а не 1280: замер показал, что с полным меню номер телефона ложится
   поверх капсулы на всей полосе до ~1480px (на 1285px — на 70px, на 1410px —
   на 44px), а порог стоял на 1280 и эту полосу не закрывал. Уступает меню:
   оно занимает 681px из 1281px строки, то есть половину, и это самый дешёвый
   источник места. Запас до 1560, чтобы на границе не сходилось впритык. */
@media (max-width:1560px){
  .hdr nav a{padding:9px 12px;font-size:13px}
  .hdr-social a{width:30px;height:30px}
}
/* Ниже 1440px даже уплотнённое меню не спасает: левой колонке нужно 309px
   (логотип 94 + отступ + номер 192), а сетка отдаёт меньше. Уходит текст
   номера, остаётся иконка — сам номер продублирован в мессенджерах рядом
   и в подвале.
   1439, а не 1440: ровно на 1440 номер ещё помещается (замер — 14px зазора
   до капсулы меню), а 1440 — одна из самых ходовых ширин ноутбука, терять
   на ней телефон незачем. */
@media (max-width:1439px){
  .hdr-tel b{display:none}
  .hdr-tel{padding:8px}
}
/* 1200, а не 1100: на 1160px левой колонке не хватало ровно 40px, и телефон
   заезжал на капсулу меню. Здесь уплотняются меню, отступы строки и кнопка —
   вместе это освобождает около 70px. */
@media (max-width:1200px){
  .hdr nav a{padding:8px 9px;font-size:12.5px}
  .hdr .row{gap:14px}
  .hdr-actions{gap:10px}
  .hdr-cta{padding:10px 16px;font-size:13px}
}
/* Ниже 1060px шесть пунктов меню, логотип, телефон, мессенджеры и кнопка
   уже не помещаются — на 960px телефон заезжал на меню на 80px.
   Первой уходит кнопка: она продублирована в финальном CTA и в нижней
   мобильной панели, а навигация нужнее. */
@media (max-width:1060px){
  .hdr-cta{display:none}
  .hdr-social{gap:2px}
}
/* Последние 60px до мобильной раскладки (меню уезжает в нижнюю панель на 900):
   даже одна иконка телефона не оставляла места, и номер налезал на меню.
   Убираем её целиком — позвонить можно из мессенджеров рядом и из подвала. */
@media (max-width:1000px){
  .hdr-tel{display:none}
}
@media (max-width:900px){
  /* Навигация уезжает в нижнюю панель, поэтому шапка становится двухчастной:
     логотип с телефоном слева, мессенджеры справа. Кнопка заявки не нужна —
     она продублирована в нижней навигации. */
  :root{--hdr-h:64px}
  .hdr.scrolled .row{height:var(--hdr-h)}
  .hdr .row{grid-template-columns:auto 1fr;gap:10px}
  .hdr-cta{display:none}
  .hdr-left{gap:4px}
  .hdr-social{gap:2px}
  .hdr-social a{width:36px;height:36px}
  .hdr-social a svg{width:18px;height:18px}
  /* Возвращаем телефон: выше он скрыт правилом ≤1000px, где место занимала
     навигация. Здесь она уехала в нижнюю панель, и место освободилось —
     а звонок в мобильной шапке нужен. */
  .hdr-tel{display:inline-flex;padding:8px 6px}
  .hdr-tel svg{width:18px;height:18px}
}

/* ---------- HERO ---------- */
.hero{position:relative;min-height:88svh;display:flex;align-items:center;overflow:hidden;background:var(--placeholder)}
/* Постер лежит base-слоем и остаётся видимым, пока видео не решило грузиться —
   на мобильном или при экономии трафика оно так и останется единственным кадром. */
.hero .bg{position:absolute;inset:0;overflow:hidden}
.hero .bg picture,.hero .bg img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center 35%}
.hero-video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center 35%;
  opacity:0;transition:opacity 1s ease}
.hero-video.on{opacity:1}
.hero .veil{position:absolute;inset:0;
  background:linear-gradient(95deg,rgba(var(--cream-rgb),.97) 0%,rgba(var(--cream-rgb),.9) 30%,rgba(var(--cream-rgb),.45) 55%,rgba(var(--cream-rgb),.12) 78%)}
/* Затемнение только под шапкой: справа кадр светлый, и без него логотип
   с мессенджерами теряются на ярких кадрах видео. */
.hero .scrim-top{position:absolute;top:0;left:0;right:0;height:calc(var(--hdr-h) + 70px);
  background:linear-gradient(to bottom,rgba(var(--cream-rgb),.45),rgba(var(--cream-rgb),0));
  pointer-events:none;z-index:2}
.hero .inner{position:relative;z-index:3;width:100%}
.hero-wordmark{font-family:'Bounded';font-weight:900;font-size:clamp(15px,2.1vw,20px);
  letter-spacing:.22em;text-transform:uppercase;color:rgba(var(--ink-rgb),.75);margin-bottom:18px}
.eyebrow-strong{font-size:13px;font-weight:800;color:var(--ink);background:rgba(var(--accent-rgb),.14);
  padding:8px 16px;border-radius:100px;letter-spacing:.08em}
.eyebrow-strong::before{display:none}
.hero h1{font-family:'Bounded';font-weight:900;font-size:clamp(32px,5vw,64px);line-height:1;
  letter-spacing:-.032em;margin:0 0 18px;max-width:15ch}
.hero h1 em{font-style:normal;color:var(--accent)}
.hero .sub{font-size:17px;line-height:1.6;color:var(--muted);max-width:40ch;margin:0 0 30px}
.hstats{display:flex;gap:34px;flex-wrap:wrap;margin-top:44px;padding-top:24px;border-top:1px solid var(--rule)}
.hstats div b{display:block;font-family:'Bounded';font-weight:900;font-size:22px;line-height:1}
.hstats div b i{color:var(--accent);font-style:normal}
.hstats div span{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}

/* ---------- 3 КОЛОНКИ ---------- */
/* Второй селектор — не опечатка. В WordPress этот блок собран контейнером
   Elementor, а тот объявляет `.e-con{display:var(--display)}` в своём CSS,
   который подключается ПОСЛЕ нашего. Вес одинаковый (один класс), поэтому
   выигрывает порядок, и сетка молча становится колонкой флексов с чужим
   отступом 20px. Дублировать значения в elementor-bridge.css было бы хуже:
   разъедутся при первой правке. Поэтому не копия правила, а тот же самый
   блок объявлений с добавленным селектором. */
.cols,.e-con.cols{display:grid;grid-template-columns:repeat(3,1fr);gap:2px;background:var(--rule);border-block:1px solid var(--rule)}
/* display:block — по той же причине: контейнер Elementor сделал бы карточку
   флексом и добавил свой gap поверх margin у h3 и p. Вес здесь и так выше
   `.e-con` (два класса), отдельный селектор не нужен. */
.cols .c{background:var(--surface);padding:38px 28px;display:block}
.cols h3{font-family:'Bounded';font-weight:700;font-size:19px;margin:0 0 10px;line-height:1.2}
.cols p{font-size:14px;line-height:1.6;color:var(--muted);margin:0}

/* ---------- ТЕХНОЛОГИИ ---------- */
/* ---------- ТЕХНОЛОГИИ И МАТЕРИАЛЫ ---------- */
/* Раньше блок прятал весь текст до наведения: три чёрных прямоугольника
   с вертикальными подписями и фото на 24% прозрачности. Теперь фотография
   изделия показана в полную силу, метки на ней указывают, ГДЕ работает
   технология, а описания видны всегда — без наведения и на телефоне. */
/* Заливки у секции нет намеренно: она занимает больше тысячи пикселей высоты,
   и сплошной --cream выключал зерно на целый экран подряд — самый заметный
   «чёрный прямоугольник» на странице. Карточки внутри и так на --surface. */
.tech .lede{margin-bottom:36px}

/* Высота строки: не меньше min(74vh,680px), но и не меньше, чем нужно трём
   карточкам. Раньше было minmax(0, min(74vh,680px)) — строка жёстко равнялась
   высоте окна, и на ноутбуках (1440×900, 1366×768, окно 1402×787) текст
   карточек вылезал за рамки сверху и снизу, у третьей обрезался (жалоба
   14.09: «слетел текст»; замер — карточке нужно ~234 px, давали 177–210).
   Фото строку не раздувает: все его слои позиционированы абсолютно. */
.tech-lab{display:grid;grid-template-columns:1.25fr .8fr;gap:clamp(20px,2.4vw,34px);
  align-items:stretch;grid-auto-rows:minmax(min(74vh,680px),auto)}

.tech-shot{position:relative;margin:0;border-radius:16px;overflow:hidden;background:var(--placeholder)}
/* Три фото лежат друг на друге и крест-накрест перетекают одно в другое —
   тот же приём кросс-фейда, что и в карточках проектов галереи.
   picture{display:contents} в начале файла иначе отключил бы тут и
   абсолютное позиционирование, и прозрачность — переопределяем на block. */
.tphoto{display:block;position:absolute;inset:0;opacity:0;transition:opacity .6s ease;z-index:0}
.tphoto.on{opacity:1;z-index:1}
.tech-shot img{width:100%;height:100%;object-fit:cover;display:block}
.tech-shot figcaption{position:absolute;left:16px;bottom:14px;z-index:3;
  font-size:11.5px;letter-spacing:.02em;color:rgba(var(--dark-fg-rgb),.72);
  background:rgba(var(--dark-bg-rgb),.55);backdrop-filter:blur(6px);
  padding:6px 12px;border-radius:999px;transition:opacity .25s ease}

/* Полоски-индикаторы прогресса автолистания — тот же язык, что у карточек
   проектов в галерее и у превью конструктора. */
.tshot-bars{position:absolute;left:16px;right:16px;top:14px;z-index:3;display:flex;gap:6px}
.tshot-bars i{flex:1;height:3px;border-radius:2px;background:rgba(var(--dark-fg-rgb),.28);
  overflow:hidden;position:relative}
.tshot-bars i::after{content:"";position:absolute;inset:0;background:var(--dark-fg);
  transform:scaleX(0);transform-origin:left}
.tshot-bars i.on::after{animation:techFill 5s linear forwards}
.tshot-bars i.done::after{transform:scaleX(1);animation:none}
@keyframes techFill{to{transform:scaleX(1)}}

/* Сетка из равных строк (1fr): все три карточки одной высоты — по самой
   длинной, но ни одна не короче своего текста. Раньше был flex с
   min-height:0 — он равнял карточки, но разрешал сжимать их ниже текста, и
   при низком окне текст выпадал за рамку. */
.tech-list{display:grid;grid-auto-rows:1fr;gap:clamp(12px,1.4vw,18px)}
.tcard{position:relative;display:flex;flex-direction:column;justify-content:center;
  background:var(--surface);border:1.5px solid var(--rule);border-left:3px solid var(--rule);
  border-radius:14px;padding:clamp(20px,2vw,28px);cursor:pointer;
  transition:border-left-color .35s ease,background .35s ease,translate .35s cubic-bezier(.22,1,.36,1)}
.tcard:hover,.tcard.on{border-left-color:var(--accent);background:var(--ink-2);translate:0 -3px}
.tcard:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* Involve, а не Bounded: у Bounded цифры разной ширины — «01» уже «02» и «03»
   на 1.4px, и у первой карточки номер заканчивался не там, где у остальных.
   Табличные цифры Bounded не спасают, разброс только растёт (замер: 20.4 против
   23.4). У Involve все пары цифр одинаковой ширины — 17.64px на 13px кегля. */
.tnum{font-family:'Involve';font-weight:700;font-size:13px;color:var(--accent);
  letter-spacing:.12em;margin-bottom:14px;display:block}
.tcard h3{font-family:'Bounded';font-weight:800;font-size:clamp(20px,2vw,26px);margin:0 0 10px;line-height:1.1}
.tcard h3 i{color:var(--accent);font-style:normal}
.tcard p{font-size:14px;line-height:1.6;color:var(--muted);margin:0 0 14px}
.ttag{align-self:flex-start;font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
  color:var(--accent);background:rgba(var(--accent-rgb),.12);padding:6px 12px;border-radius:999px}

@media (max-width:900px){
  .tech-lab{grid-template-columns:1fr;grid-auto-rows:auto}
  .tech-shot{aspect-ratio:4/3}
  /* flex:1 1 0 + min-height:0 требуют заданной высоты строки, чтобы разделить
     её поровну (так и есть на десктопе). Без неё (grid-auto-rows:auto) браузер
     схлопывает карточки почти до нуля, и текст трёх карточек накладывается
     друг на друга. На мобильном карточки просто идут одна под другой. */
  .tcard{flex:none;min-height:auto}
  /* На телефоне карточки идут одна под другой — равнять их по самой длинной
     незачем, у короткой появилась бы пустота внизу. */
  .tech-list{grid-auto-rows:auto}
}
@media (prefers-reduced-motion:reduce){
  .tphoto{transition:none}
  .tshot-bars i.on::after{animation:none;transform:scaleX(1)}
  .tcard:hover,.tcard.on{translate:none}
}

#flow{position:relative}
/* padding-top, а не top: высота блока остаётся ровно 100svh, и JS-математика
   ленты (flow.offsetHeight - innerHeight) не сбивается.
   Раскладка от верха, а не по центру: с justify-content:center содержимое
   переполняло блок и выезжало вверх — заголовок уходил под фиксированную шапку
   несмотря на отступ. */
#flow .pin{position:sticky;top:0;height:100svh;padding-top:calc(var(--hdr-h) + 18px);
  display:flex;flex-direction:column;justify-content:flex-start;overflow:hidden}
#flow .head{padding:0 var(--pad);margin-bottom:26px;flex-shrink:0}

/* Полоса прогресса вместо подменяющегося текста «01 Заявка»: цифра и слово
   перескакивали поверх едущей ленты — два движения в одной точке экрана.
   Здесь ничего не переписывается, просто заполняются сегменты. */
#flow .fsteps{display:flex;gap:6px;margin-top:22px;margin-bottom:14px;max-width:560px}
/* overflow:hidden отрезал бы номера под полосой — заливка и так делается
   через scaleX, обрезка не нужна */
#flow .fstep{position:relative;flex:1 1 0;height:3px;border-radius:2px;
  background:rgba(var(--ink-rgb),.16);transition:background .3s ease}
#flow .fstep::after{content:"";position:absolute;inset:0;background:var(--accent);
  transform:scaleX(0);transform-origin:left;transition:transform .45s cubic-bezier(.22,1,.36,1)}
#flow .fstep.done::after{transform:scaleX(1)}
#flow .fstep b{position:absolute;top:10px;left:0;font-family:'Bounded';font-weight:700;
  font-size:11px;letter-spacing:.06em;color:var(--muted);transition:color .3s ease}
#flow .fstep.on b{color:var(--accent)}

/* 64svh не оставляли места под отступ для шапки — лента переполняла блок. */
#flow .track{flex:1;max-height:60svh;position:relative;padding-left:var(--pad)}
#flow .rail{display:flex;gap:20px;height:100%;align-items:center;will-change:transform;transition:transform .1s linear}
/* Карточки не выцветают и не масштабируются: лента и так едет, вторая анимация
   поверх неё выглядела как наложение. Активная выделяется только кромкой. */
#flow .card{flex:0 0 400px;background:var(--surface);border:1.5px solid var(--rule);border-radius:14px;
  padding:34px;min-height:340px;border-left:3px solid var(--rule);
  transition:border-left-color .35s ease,background .35s ease}
#flow .card.on{border-left-color:var(--accent);background:var(--ink-2)}
#flow .card.wide{flex-basis:620px}
#flow .card .num{font-family:'Bounded';font-weight:900;font-size:34px;color:var(--accent);margin-bottom:16px;line-height:1}
#flow .card h3{font-family:'Bounded';font-weight:700;font-size:23px;margin:0 0 12px}
#flow .card p{font-size:15px;color:var(--muted);line-height:1.65;margin:0}
.forks{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:18px}
.fork{background:var(--cream);border-radius:9px;padding:15px;border-left:3px solid var(--accent)}
.fork.alt{border-left-color:var(--ink)}
.fork b{display:block;font-family:'Bounded';font-weight:700;font-size:12px;margin-bottom:9px}
.fork ul{list-style:none;padding:0;margin:0}
.fork li{font-size:12px;color:var(--muted);padding:4px 0 4px 15px;position:relative;line-height:1.4}
.fork li::before{content:"";position:absolute;left:0;top:11px;width:5px;height:5px;border-radius:50%;background:var(--accent)}
.fork.alt li::before{background:var(--ink)}

/* ---------- КОНСТРУКТОР ---------- */
/* Тизер конструктора — цельный баннер: фото на всю площадь, весь текст и кнопка
   лежат поверх него. Текст всегда светлый (это оверлей на фотографии, а не фон
   страницы), поэтому берёт постоянные --dark-fg, а не токены темы. */
/* Снимок работает фоном во всю ширину блока. Это возможно только потому,
   что кадры здесь горизонтальные (1600×962, вырезаны из студийных
   оригиналов 3334×5000). Портретные фото так использовать нельзя: при
   object-fit:cover от них остаётся 40% высоты, и форма уходит за нижний край. */
.ctor2{position:relative;border-radius:20px;overflow:hidden;isolation:isolate;
  min-height:min(76vh,720px);display:flex;align-items:center;
  background:var(--placeholder);color:var(--dark-fg)}
.ctor-photo{position:absolute;inset:0;z-index:0}
.cyc{position:relative;width:100%;height:100%}
/* Кадр и блок почти совпадают по пропорциям (1.66 против 1.66), поэтому
   обрезается минимум и центрирование безопасно. */
/* Селектор с родителем — из-за Elementor: у него в frontend.min.css есть
   `.elementor img{height:auto}`, а это на один вес больше, чем одиночный
   `.cyc-img`. Кадр переставал тянуться на высоту блока и схлопывался до
   своей пропорции (320x192 вместо 320x760): на телефоне фотография
   занимала верхнюю полоску, а текст уезжал на чёрный фон под ней. */
.cyc .cyc-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center;
  opacity:0;transition:opacity .8s ease}
.cyc-img.on{opacity:1}
/* Затемнение под колонкой текста — справа снимок остаётся открытым. */
.ctor2::before{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(100deg,rgba(var(--dark-bg-rgb),.95) 0%,rgba(var(--dark-bg-rgb),.86) 32%,
    rgba(var(--dark-bg-rgb),.45) 56%,rgba(var(--dark-bg-rgb),.08) 78%)}

.ctor-info{position:relative;z-index:2;min-width:0;max-width:640px;
  padding:clamp(34px,5vw,72px)}
.ctor-info .eyebrow{color:var(--accent)}
.ctor-info .h{color:var(--dark-fg)}
.ctor-info .lede{color:rgba(var(--dark-fg-rgb),.78)}

/* Прогресс автопрокрутки: только полоски-сегменты, без превью-фото. */
.cyc-dots{position:absolute;left:clamp(18px,2.4vw,32px);right:clamp(18px,2.4vw,32px);
  bottom:clamp(18px,2.4vw,28px);display:flex;gap:6px;z-index:3}
/* Кнопка — прозрачная полоса 30 px в высоту, а видимая дорожка 3 px рисуется
   внутри неё (i). Раньше кнопкой была сама дорожка 46×3, и пальцем по ней
   почти не попадали (замер 14.09). Невидимую область через ::before сделать
   не вышло: у дорожки overflow:hidden (он закругляет заливку прогресса) и
   обрезал её. Отрицательный margin возвращает раскладку к прежним 3 px. */
.cyc-dot{position:relative;flex:1;height:30px;margin:-13.5px 0;padding:0;border:0;cursor:pointer;
  background:transparent;opacity:.7;transition:opacity .25s ease}
.cyc-dot:hover{opacity:1}
.cyc-dot.on{opacity:1}
.cyc-dot:focus-visible{outline:none}
.cyc-dot:focus-visible i{outline:2px solid var(--accent);outline-offset:3px}
.cyc-dot i{position:absolute;left:0;right:0;top:50%;height:3px;margin-top:-1.5px;
  border-radius:2px;overflow:hidden;background:rgba(var(--dark-fg-rgb),.28)}
.cyc-dot i::after{content:"";position:absolute;inset:0;background:var(--accent);transform:scaleX(0);
  transform-origin:left}
.cyc-dot.on i::after{animation:cycFill 4s linear forwards}
@keyframes cycFill{to{transform:scaleX(1)}}

@media (prefers-reduced-motion:reduce){
  .cyc-img{transition:none}
  .cyc-dot.on i::after{animation:none;transform:scaleX(1)}
}

.ctor-feats{list-style:none;margin:0 0 34px;padding:0;
  display:grid;grid-template-columns:1fr 1fr;gap:18px 22px}
.ctor-feats li{display:flex;gap:14px;align-items:flex-start}
.ctor-feats b{font-family:'Bounded';font-weight:900;font-size:13px;color:var(--accent);
  flex-shrink:0;padding-top:2px}
.ctor-feats span{display:block;font-family:'Bounded';font-weight:700;font-size:15px;margin-bottom:3px;
  color:var(--dark-fg)}
.ctor-feats em{display:block;font-style:normal;font-size:12.5px;line-height:1.5;
  color:rgba(var(--dark-fg-rgb),.62)}
/* обводка вторичной кнопки поверх фото — светлая, а не по теме страницы */
.ctor-info .btn.line{color:var(--dark-fg);border-color:rgba(var(--dark-fg-rgb),.45)}
@media (max-width:900px){
  /* Текст лежит поверх снимка, градиент идёт снизу вверх — фигура остаётся
     видна в верхней половине кадра, текст читается в нижней. */
  /* Блок выше, чем нужно тексту: верхняя треть остаётся под снимок.
     На 620px текст съедал его целиком и фото было не разглядеть. */
  .ctor2{min-height:760px;border-radius:16px;align-items:flex-end}
  /* Фигура стоит в правой части кадра: замер по всем шести кадрам даёт
     центр фотографии на 76.4% ширины холста (tools/build_ctor_frames.py
     вписывает снимок по высоте и прижимает вправо, слева — ровная заливка).
     В узкое окно при cover попадает лишь 26% ширины кадра, и по центру туда
     приходится пустая заливка — на телефоне блок выглядел серым пятном.
     88% ставит фигуру по центру окна с небольшим сдвигом влево.

     Селектор обязан быть с родителем: одиночный `.cyc-img` легче, чем
     `.cyc .cyc-img` выше по файлу, и правило молча проигрывало — именно
     поэтому object-position оставался center, хотя правило тут было. */
  .cyc .cyc-img{object-position:88% center}
  .ctor2::before{background:linear-gradient(180deg,rgba(var(--dark-bg-rgb),.15) 0%,
    rgba(var(--dark-bg-rgb),.32) 22%,rgba(var(--dark-bg-rgb),.86) 48%,
    rgba(var(--dark-bg-rgb),.97) 72%)}
  .ctor-info{max-width:none;padding:clamp(22px,5vw,30px);padding-top:96px}
  /* Прогресс наверх: внизу его перекрыл бы текст с кнопкой. */
  .cyc-dots{right:clamp(16px,4vw,22px);left:clamp(16px,4vw,22px);top:clamp(14px,4vw,18px);bottom:auto}
  .ctor-feats{grid-template-columns:1fr;gap:14px;margin-bottom:24px}
  .ctor-feats em{font-size:12px}
}

/* Планшет: окно над кадром уже вдвое шире телефонного (53% холста против
   26%), и при 88% слева в него заходит ровная заливка — 148px на 768px.
   Прижимаем кадр к правому краю: фигура остаётся почти по центру окна
   (+39px на 768px), а заливки видно вдвое меньше, и та попадает под
   тёмный градиент с текстом. Полностью убрать её можно только другим
   холстом — фигура занимает лишь правые 46% кадра. */
@media (min-width:601px) and (max-width:900px){
  .cyc .cyc-img{object-position:100% center}
}

/* ---------- КВИЗ ---------- */
.quiz{background:var(--surface);border-radius:14px;padding:clamp(26px,4vw,44px);border:1.5px solid var(--ink)}
.qprog{display:flex;gap:6px;margin-bottom:26px}
.qprog i{flex:1;height:3px;border-radius:2px;background:var(--rule)}
.qprog i.on{background:var(--accent)}
.qstep{display:none}
.qstep.on{display:block}
.qstep h3{font-family:'Bounded';font-weight:700;font-size:20px;margin:0 0 18px}
.opts{display:flex;flex-wrap:wrap;gap:9px}
.opt{font-family:'Involve';font-weight:500;font-size:14px;padding:11px 18px;border-radius:100px;cursor:pointer;
  background:var(--cream);border:1.5px solid var(--rule);color:var(--ink);transition:.2s}
.opt:hover{border-color:var(--ink)}
.opt.sel{background:var(--accent);border-color:var(--accent);color:var(--cream)}
.qnav{display:flex;justify-content:space-between;align-items:center;margin-top:26px}
.qback{background:none;border:0;font-family:'Involve';font-weight:600;font-size:13px;color:var(--muted);cursor:pointer}
.qdone{display:none}
.qdone.on{display:block}
.qdone .res{background:var(--cream);border-radius:10px;padding:20px;margin-bottom:20px;font-size:14.5px;line-height:1.6}
.qdone .res b{color:var(--accent)}
.frm{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:14px}
/* Третье поле квиза (Telegram или MAX) — во всю ширину под именем и телефоном:
   в сетке на две колонки оно иначе встало бы одно слева с пустотой справа. */
.frm .frm-wide{grid-column:1 / -1}
/* border:var(--rule) давал ~1.62:1 к фону — ниже 3:1, положенных для границ
   полей ввода (найдено в аудите 2026-09-07). Своя, более контрастная
   граница вместо общего --rule, чтобы не менять его везде по сайту. */
.frm input{font-family:'Involve';font-size:14px;padding:13px 15px;border-radius:6px;
  border:1.5px solid rgba(var(--ink-rgb),.35);background:var(--cream)}
.frm input:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(var(--accent-rgb),.35)}

/* ---------- ГАЛЕРЕЯ ---------- */
.gal{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.gal a{position:relative;border-radius:10px;overflow:hidden;aspect-ratio:3/4;display:block;background:var(--placeholder)}
.gal img{width:100%;height:100%;object-fit:cover;transition:transform .5s}
.gal a:hover img{transform:scale(1.05)}

/* ---------- ОТЗЫВЫ ---------- */
/* Раньше здесь стоял iframe-виджет Яндекс.Карт: своей тёмной темы у него
   нет (Яндекс подтвердил в поддержке — кастомизации не будет), и он был
   чужеродной белой плашкой на чёрном фоне.

   Убран совсем 2026-09-05: понадобилась сортировка отзывов по дате, а у
   виджета нет ни одного параметра для этого — ни в query, ни в его
   markup (проверено — там нет даже JS, который читал бы sort/date).
   Полную страницу отзывов с сортировкой встроить тоже нельзя — у неё
   X-Frame-Options: DENY.

   Решение — перестать бороться с чужим iframe и просто оформить реальные
   отзывы своей вёрсткой: тот же текст, имена, даты и оценки, взятые из
   открытых данных карточки компании, но в тёмной теме и в нужном порядке.
   Карточка та же (акцентная кромка сверху — приём из .org .o), внутри —
   список вместо чужого фрейма. */
.rev-grid{display:grid;grid-template-columns:.85fr 1fr;gap:clamp(28px,4vw,56px)}

.rev-side{display:flex;flex-direction:column;align-items:flex-start;justify-content:space-between}
.rev-head .eyebrow{margin-bottom:14px}
.rev-head .h{margin-bottom:14px}
.rev-head .lede{margin-bottom:0}
.rev-note{font-size:14.5px;line-height:1.65;color:var(--muted);max-width:38ch;margin:0}

/* Сводная оценка вверху левой колонки — раньше это была верхняя строка
   самого виджета (мини-бейдж), потерялась бы вместе с ним. */
.rev-stat{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.rev-stat b{font-family:'Bounded';font-size:32px;line-height:1}
.rev-stat-stars{display:inline-flex;gap:2px}
.rev-stat-n{font-size:13px;color:var(--muted)}

.rev-card{background:var(--surface);border:1.5px solid var(--rule);border-top:3px solid var(--accent);
  border-radius:16px;padding:clamp(14px,1.8vw,22px);box-shadow:0 24px 60px -30px rgba(0,0,0,.55);
  display:flex;flex-direction:column;gap:14px}

/* Список отзывов: max-height + скролл держит карточку в габаритах прежнего
   640px-виджета — резкого скачка высоты блока при замене не случилось. */
.rev-list{max-height:640px;overflow-y:auto;display:flex;flex-direction:column;
  scrollbar-width:thin;scrollbar-color:rgba(var(--ink-rgb),.3) transparent}
.rev-list::-webkit-scrollbar{width:6px}
.rev-list::-webkit-scrollbar-thumb{background:rgba(var(--ink-rgb),.25);border-radius:3px}

.rev-item{padding:16px 4px;border-bottom:1px solid var(--rule)}
.rev-item:last-child{border-bottom:0}
.rev-item-h{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.rev-av{flex:none;width:34px;height:34px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;font-family:'Bounded';font-weight:700;font-size:13px;color:#fff}
.rev-who{display:flex;flex-direction:column;gap:2px;min-width:0}
.rev-who b{font-size:14px;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rev-stars{display:inline-flex;gap:1px}
.rev-date{margin-left:auto;flex:none;font-size:12px;color:var(--muted)}
.rev-text{font-size:14px;line-height:1.6;color:rgba(var(--ink-rgb),.85);margin:0}

/* Звёзды — залитый и пустой SVG-силуэт через currentColor, без картинок
   Яндекса (их и не отдать: img-src в CSP ограничен собственным доменом). */
.star{display:inline-block;width:13px;height:13px;color:var(--accent);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 21 12 17.77 5.82 21 7 14.14l-5-4.87 6.91-1.01L12 2z'/%3E%3C/svg%3E") center/contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 21 12 17.77 5.82 21 7 14.14l-5-4.87 6.91-1.01L12 2z'/%3E%3C/svg%3E") center/contain no-repeat;
  background:currentColor}
.rev-stat-stars .star{width:15px;height:15px}
.star._empty{color:rgba(var(--ink-rgb),.2)}

.rev-more{align-self:center;font:inherit;font-size:13px;color:var(--muted);background:transparent;
  border:1px solid var(--rule);border-radius:999px;padding:8px 18px;cursor:pointer;transition:.2s}
.rev-more:hover{color:var(--ink);border-color:rgba(var(--ink-rgb),.4)}
.rev-more[hidden]{display:none}

@media (max-width:900px){
  .rev-grid{grid-template-columns:1fr;gap:26px}
  /* Без центрирования: на всём сайте заголовки, подзаголовки и текст идут по
     левому краю, и блок отзывов был единственным, который на телефоне
     выбивался в центр. */
  .rev-side{gap:22px}
  .rev-note{max-width:46ch}
}
@media (max-width:640px){.rev-list{max-height:520px}}

/* ---------- ДОВЕРИЕ И ОХВАТ ---------- */
.tstats{display:grid;grid-template-columns:repeat(4,1fr);border-block:2px solid var(--ink);margin-bottom:56px}
.tstats .st{padding:38px 18px;border-right:1px solid var(--rule)}
.tstats .st:last-child{border-right:0}
.tstats .st b{display:flex;align-items:baseline;flex-wrap:nowrap;gap:2px;
  font-family:'Bounded';font-weight:900;font-size:clamp(34px,4.6vw,60px);line-height:1;letter-spacing:-.015em}
.tstats .st b i{color:var(--accent);font-style:normal;white-space:nowrap;flex-shrink:0}
.tstats .st b .cnt{white-space:nowrap}
.tstats .st>span{font-size:12.5px;color:var(--muted);margin-top:12px;display:block}
.geo{display:grid;grid-template-columns:1.15fr 1fr;gap:50px;align-items:center}
.geo svg{width:100%;height:auto}
.geo .tl{font-family:'Bounded';font-weight:700;font-size:13px;text-transform:uppercase;letter-spacing:.06em;color:var(--accent);margin-bottom:12px}
.geo .ad{font-family:'Bounded';font-weight:700;font-size:clamp(19px,2.2vw,26px);line-height:1.3;color:var(--ink);text-decoration:none;border-bottom:2px solid var(--accent);display:inline-block}
.geo .ad:hover{color:var(--accent)}
.geo .nt{font-size:13.5px;color:var(--muted);margin-top:14px;line-height:1.55}

.geomap{position:relative}
.geomap img{width:100%;display:block}
/* Контур России рисуется токенами, а не атрибутами в разметке — иначе карта
   не переключалась бы вместе с темой. */
.geomap svg path{fill:var(--map-fill);stroke:var(--map-stroke);stroke-width:1.5;
  vector-effect:non-scaling-stroke}
.dot{position:absolute;width:7px;height:7px;border-radius:50%;background:var(--accent);
  transform:translate(-50%,-50%);cursor:pointer;z-index:2}
.dot::before{content:"";position:absolute;inset:-7px;border-radius:50%}
.dot.showroom{width:13px;height:13px;background:var(--ink);z-index:3;box-shadow:0 0 0 4px rgba(var(--ink-rgb),.14)}
.dot:hover,.dot:focus-visible{z-index:10}
.dot:hover .dot-core,.dot:focus-visible .dot-core{transform:scale(1.6)}
.dot .lbl{position:absolute;bottom:calc(100% + 6px);left:50%;transform:translateX(-50%) translateY(4px);
  font-family:'Involve';font-weight:600;font-size:11px;color:var(--cream);white-space:nowrap;
  background:var(--ink);padding:4px 9px;border-radius:4px;pointer-events:none;line-height:1.3;
  opacity:0;transition:opacity .15s ease,transform .15s ease}
.dot .lbl::after{content:"";position:absolute;top:100%;left:50%;margin-left:calc(-1 * var(--sh,0px));transform:translateX(-50%);
  border:5px solid transparent;border-top-color:var(--ink)}
.dot .lbl.sr{background:var(--accent);font-weight:700}
.dot .lbl.sr::after{border-top-color:var(--accent)}
.dot:hover .lbl,.dot:focus-visible .lbl{opacity:1;transform:translateX(-50%) translateY(0)}
.citylist{margin:26px 0 0;font-size:12.5px;line-height:1.9;color:var(--muted)}
.citynote{margin:10px 0 0;font-size:12px;line-height:1.5;color:var(--muted);opacity:.85}
.citylist b{color:var(--ink);font-weight:700}
@media (max-width:900px){.citylist{font-size:11.5px;line-height:1.8}}

/* ---------- ДЛЯ ОРГАНИЗАЦИЙ ---------- */
.org,.e-con.org{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}
.org .o{background:var(--surface);border:1.5px solid var(--rule);border-radius:11px;padding:26px;border-top:3px solid var(--accent);display:block}
.org .o h3{font-family:'Bounded';font-weight:700;font-size:17px;margin:0 0 9px}
.org .o p{font-size:13.5px;color:var(--muted);line-height:1.6;margin:0}

/* ---------- ПАРТНЁРЫ ---------- */
/* ---------- КЛИЕНТЫ ПОД HERO ---------- */
/* Раньше строка висела в середине страницы без объяснения, что это за слова.
   Теперь она сразу под первым экраном и подписана. */
.clients{padding:28px 0 0}
.clients-head{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;margin-bottom:16px}
.clients-tag{font-family:'Bounded';font-weight:700;font-size:12px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--accent);white-space:nowrap}
.clients-tag::after{content:"";display:inline-block;width:22px;height:2px;margin-left:12px;
  vertical-align:middle;background:var(--accent);opacity:.5}
.clients-note{font-size:13px;color:var(--muted);line-height:1.5}

.marq{overflow:hidden;border-block:1px solid var(--rule);padding:22px 0;
  /* края растворяются, чтобы строка не обрывалась резко о край экрана */
  -webkit-mask:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent);
  mask:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent)}
.marq .in{display:flex;gap:56px;width:max-content;animation:slide 42s linear infinite}
.marq:hover .in{animation-play-state:paused}
@keyframes slide{to{transform:translateX(-50%)}}
.marq span{font-family:'Bounded';font-weight:700;font-size:17px;color:rgba(var(--ink-rgb),.34);
  white-space:nowrap;transition:color .3s ease}
.marq span:hover{color:var(--accent)}
@media (prefers-reduced-motion:reduce){
  .marq .in{animation:none}
  .marq{overflow-x:auto;scrollbar-width:none}
  .marq::-webkit-scrollbar{display:none}
}

/* ---------- FAQ ---------- */
/* Раньше здесь стоял .e-con#faq{padding-top:0} — он лечил тот же лишний
   воздух, но не с той стороны: общий размер стыка становился правильным,
   а сама прошивка оставалась не по центру пустоты (33px сверху против 98
   снизу). Настоящая причина и общее лечение — в правиле про .e-con.pad
   ниже по файлу. */


/* Ширину блока намеренно НЕ ограничиваем: по правилу проекта секции идут
   во всю ширину экрана, а длину строки держит сам текст — у ответов стоит
   max-width:70ch ниже. В статике на этом блоке висел инлайновый
   style="max-width:900px", он выбивался из общего ритма страницы
   и при сборке в Elementor всё равно потерялся. */
/* Отбивка между заголовком блока и первым вопросом. В статике это была
   распорка <div style="height:20px">, при сборке в Elementor она потерялась. */
#faq .faq{margin-top:6px}
.faq details{border-bottom:1px solid var(--rule)}
/* 19px — тот же размер, что у заголовков карточек (.cols h3): вопросы
   читаются как подзаголовки блока, а не как подписи. Отступ строки 16px
   вместо 20: с более крупным текстом прежний давал слишком воздушные
   строки. Значение продублировано в elementor-bridge.css
   (--n-accordion-padding) — держать синхронно. */
.faq summary{list-style:none;cursor:pointer;padding:16px 0;font-family:'Bounded';font-weight:700;font-size:19px;
  display:flex;justify-content:space-between;align-items:center;gap:20px}
.faq summary::-webkit-details-marker{display:none}
/* margin-left:auto прижимает «плюс» к правому краю строки сам по себе,
   не полагаясь на justify-content у родителя. Так надо из-за Elementor:
   виджет аккордеона задаёт `justify-content:var(--n-accordion-title-
   justify-content)` селектором в два класса — он весомее нашего
   `.faq summary`, переменная пустая, и выравнивание сбрасывается в normal:
   «плюс» прилипал к тексту вопроса вместо правого края. */
.faq summary::after{content:"+";color:var(--accent);font-size:22px;flex-shrink:0;margin-left:auto}
.faq details[open] summary::after{content:"–"}
.faq p{margin:0 0 22px;font-size:14.5px;line-height:1.65;color:var(--muted);max-width:70ch}

/* ---------- ФИНАЛ + ПОДВАЛ ---------- */
/* Финальный CTA отличается от страницы не заливкой, а светом: тёплое пятно
   сверху вместо плоского --dark-bg. Плоский совпадал с фоном страницы цвет
   в цвет и давал ровно тот же эффект «выключенного зерна», только под самым
   важным экраном; свечение и зерно сохраняет, и блок выделяет. */
.fin{background:var(--glow-warm);
  color:var(--dark-fg);text-align:center}
.fin h2{font-family:'Bounded';font-weight:900;font-size:clamp(28px,4.2vw,52px);line-height:1.04;margin:0 0 16px;letter-spacing:-.03em}
.fin p{color:rgba(var(--dark-fg-rgb),.72);font-size:16px;max-width:46ch;margin:0 auto 30px;line-height:1.6}
.fin .acts{justify-content:center}
.fin .btn.line{color:var(--dark-fg);border-color:rgba(var(--dark-fg-rgb),.45)}
/* Подвал — единственное место, где плотная заливка оставлена намеренно. Это
   «подошва» страницы: мелкий плотный текст в четыре колонки читается спокойнее
   на ровном фоне, чем на текстуре, а линия сверху объясняет, почему зерно здесь
   заканчивается — иначе обрыв текстуры читался бы как дефект, а не как приём. */
.ftr{background:var(--dark-bg);color:rgba(var(--dark-fg-rgb),.6);padding:clamp(50px,7vh,80px) 0 0;font-size:13.5px;
  border-top:1px solid rgba(var(--dark-fg-rgb),.12)}
.ftr-top{display:grid;grid-template-columns:1.6fr 1fr 1fr 1.2fr;gap:40px;padding-bottom:44px}
.ftr-col{display:flex;flex-direction:column;gap:12px}
.ftr-col a{color:rgba(var(--dark-fg-rgb),.6);text-decoration:none}
/* Текстовые ссылки подвала были 18 px в высоту — на телефоне мимо них легко
   промахнуться. Поле касания растягивается до 30 px отступом, а
   отрицательный margin съедает его в раскладке: внешне подвал не меняется.
   Только прямые дети колонки — кружки соцсетей лежат глубже и не задеты. */
.ftr-col > a{padding:6px 0;margin:-6px 0}
.ftr-col a:hover{color:var(--dark-fg)}
.ftr-h{font-family:'Bounded';font-weight:700;font-size:11.5px;text-transform:uppercase;letter-spacing:.08em;
  color:var(--dark-fg);margin-bottom:4px}
.ftr-brand .lockup{height:30px;width:auto;align-self:flex-start;flex:0 0 auto;margin-bottom:6px}
.ftr-brand p{font-size:13px;color:rgba(var(--dark-fg-rgb),.52);line-height:1.55;margin:0 0 6px;max-width:32ch}
.ftr-social{display:flex;gap:10px}
.ftr-social a{width:32px;height:32px;border-radius:50%;border:1px solid rgba(var(--dark-fg-rgb),.2);
  display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;color:rgba(var(--dark-fg-rgb),.65)!important}
.ftr-social a:hover{border-color:var(--accent);color:var(--accent)!important}
.ftr-hours{color:rgba(var(--dark-fg-rgb),.6);font-size:12.5px}
.ftr-bottom{display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;
  border-top:1px solid rgba(var(--dark-fg-rgb),.12);padding:20px 0;color:rgba(var(--dark-fg-rgb),.6);font-size:12px}
@media (max-width:900px){
  .ftr-top{grid-template-columns:1fr 1fr;gap:32px 20px}
  .ftr-brand{grid-column:1 / -1}
}

/* ---------- УВЕДОМЛЕНИЕ О COOKIE ----------
   Только при включённой Метрике (inc/launch.php). Информационное, сайт не
   закрывает. Над нижней панелью телефона (z-index 95), не под ней. */
.cookie-note{position:fixed;left:16px;bottom:16px;z-index:96;max-width:420px;
  display:flex;align-items:center;gap:14px;padding:14px 14px 14px 18px;border-radius:14px;
  background:var(--surface);border:1px solid var(--rule);box-shadow:0 18px 40px -16px rgba(0,0,0,.6)}
.cookie-note p{margin:0;font-size:12.5px;line-height:1.5;color:var(--muted)}
.cookie-note a{color:var(--ink)}
.cookie-note .btn{flex:none;padding:10px 16px;font-size:13px}
/* display:flex выше перебивает [hidden]: «Понятно» ставил атрибут, а уведомление
   оставалось на экране — и у согласившихся тоже (найдено в день запуска 17.09).
   Та же грабля, что у .cat и .tgp. */
.cookie-note[hidden]{display:none}

/* ---------- МОБИЛЬНАЯ НИЖНЯЯ НАВИГАЦИЯ ---------- */
.bnav{display:none}
@media (max-width:900px){
  .hdr nav{display:none}
  /* .e-con здесь обязателен: без него правило (один класс) слабее
     `.e-con.cols` выше, и на телефоне остались бы три колонки. */
  .cols,.org,.gal,.e-con.cols,.e-con.org{grid-template-columns:1fr}
  .gal{grid-template-columns:1fr 1fr}
  /* горизонтальные reveal на мобильном заменяем вертикальным — иначе смещение по X даёт горизонтальный скролл */
  .reveal-l,.reveal-r{transform:translateY(26px)}
  .tstats{grid-template-columns:1fr 1fr}
  .tstats .st:nth-child(2n){border-right:0}
  .tstats .st b{font-size:clamp(23px,7.2vw,34px)}
  .geo,.alt-box,.frm{grid-template-columns:1fr}
  .panels{flex-direction:column;height:auto}
  .panel{min-height:150px}
  .panels:hover .panel,.panels .panel:hover{flex-grow:1}
  .panel .vt{display:none}
  .panel .ex{position:relative;left:0;right:0;bottom:0;opacity:1;transform:none;margin-top:40px}
  .panel .ex b{white-space:normal}
  #flow .card{flex-basis:250px;min-height:auto;padding:22px}
  #flow .card.wide{flex-basis:300px}
  .forks{grid-template-columns:1fr}
  body{padding-bottom:72px}
  /* Шапка теперь лежит поверх hero, поэтому фиксированная высота в 88svh
     прижимала заголовок к ней сверху и прятала статистику под нижней
     панелью. Высоту задаёт содержимое, экран остаётся нижней границей. */
  /* Но совсем без нижней границы нельзя (замер Chrome 14.09): HTML по
     медленной сети приходит частями, браузер рисует hero, пока в нём ещё нет
     кнопок и цифр, — блок низкий, и постер попадает в метрику LCP заниженным
     в 5 раз (53 тыс. вместо 291 тыс.). Потом видео того же размера
     оказывалось «крупнее» и LCP съезжал на ~4 с. Граница ≈ высоте готового
     hero на обычном телефоне (747 px на 390×844), поэтому внешне ничего не
     меняет, а на коротких экранах 92svh её опускает и содержимое растёт
     само — старая проблема «прижимало к шапке» не возвращается. */
  .hero{min-height:min(760px,92svh);padding-top:calc(var(--hdr-h) + 30px);padding-bottom:44px}
  .hero-wordmark{margin-bottom:12px}
  /* На мобильном .acts переносит кнопки в столбец, но ширина каждой
     считалась по своему тексту — «Получить каталог» шире «Создать форму»,
     и пара выглядела неровной (жалоба пользователя 2026-09-08).
     display:inline-flex вместо flex — контейнер сжимается по самому
     широкому ребёнку, а не растягивается на всю колонку: кнопки выходят
     вровень друг с другом, но не во всю ширину экрана (первая правка была
     слишком широкой — замечание пользователя). */
  .hero .acts{display:flex;width:fit-content;flex-direction:column;align-items:stretch}
  .hero .acts .btn{justify-content:center}
  /* Тот же стеклянный язык, что у шапки: полупрозрачная плёнка с размытием,
     активный пункт получает оранжевую капсулу — как ховер на десктопе. */
  .cookie-note{left:10px;right:10px;max-width:none;bottom:calc(84px + env(safe-area-inset-bottom));
    gap:10px;padding:10px 10px 10px 14px}
  /* Плашка закрывала нижнюю треть первого экрана: текст мельче, кнопка компактнее (22.09, одобрено). */
  .cookie-note p{font-size:11.5px;line-height:1.4}
  .cookie-note .btn{padding:8px 12px;font-size:12px}
  .bnav{display:flex;position:fixed;bottom:0;left:0;right:0;z-index:95;
    background:rgba(var(--cream-rgb),.58);
    backdrop-filter:blur(20px) saturate(140%);
    -webkit-backdrop-filter:blur(20px) saturate(140%);
    border-top:1px solid rgba(var(--ink-rgb),.1);
    padding:8px 6px calc(8px + env(safe-area-inset-bottom));gap:4px}
  .bnav a{flex:1;text-align:center;text-decoration:none;color:rgba(var(--dark-fg-rgb),.62);
    font-size:10.5px;font-weight:600;border-radius:14px;
    display:flex;flex-direction:column;align-items:center;gap:4px;padding:7px 0 6px;
    transition:color .25s ease,background .25s ease}
  .bnav a.on{color:var(--dark-bg);background:var(--accent);
    box-shadow:0 4px 14px rgba(var(--accent-rgb),.4)}
  .bnav a:active{background:rgba(var(--accent-rgb),.2)}
  .bnav svg{width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:1.8}
}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .stitch line{transition:none;stroke-dashoffset:0}
  .marq .in{animation:none}
  #flow .pin{position:relative;height:auto}
  #flow .rail{flex-wrap:wrap;transform:none!important}
  #flow .card{opacity:1;transform:none}
}
/* ---- юридические страницы (privacy.html, offer.html) ---- */
.legal{max-width:76ch;padding:48px 0 96px}
.legal h1{margin:0 0 8px}
/* «Публичная оферта на изготовление спортивной экипировки» на 32 px вставала
   в 4 строки на телефоне. */
@media (max-width:600px){.legal h1{font-size:clamp(24px,7vw,28px)}}
.legal .legal-updated{color:rgba(var(--ink-rgb),.5);font-size:14px;margin:0 0 40px}
.legal h2{font-family:'Bounded';font-weight:700;font-size:clamp(19px,2.2vw,24px);
  line-height:1.25;margin:40px 0 14px}
.legal p{font-size:16px;line-height:1.7;color:rgba(var(--ink-rgb),.82);margin:0 0 16px}
.legal ul,.legal ol{margin:0 0 16px;padding-left:22px}
.legal li{font-size:16px;line-height:1.7;color:rgba(var(--ink-rgb),.82);margin:0 0 8px}
.legal .placeholder{color:var(--accent);background:rgba(var(--accent-rgb),.1);
  padding:1px 6px;border-radius:4px;font-weight:600}
.legal .legal-notice{background:rgba(var(--accent-rgb),.08);border:1px solid rgba(var(--accent-rgb),.3);
  border-radius:12px;padding:18px 20px;margin:0 0 40px;font-size:14.5px;line-height:1.6}
.legal .legal-notice b{color:var(--accent)}


/* ---------- СТЫК СЕКЦИЙ: прошивка внутри контейнера Elementor ---------- */
/* У части блоков корнем стал сам контейнер Elementor (#why, #org, #faq —
   у них класс .pad висит на .e-con), и прошивка-разделитель лежит ВНУТРИ
   него последним ребёнком. Из-за этого нижний отступ секции оказывается
   ПОД линией, а не над ней: линия прижимается к тексту, а под ней зияет
   полтора отступа. Замер на 375px: 62px сверху против 154px снизу, тогда
   как на нормальных стыках 89/89.

   В статике прошивка стоит МЕЖДУ секциями и воздух делится поровну —
   возвращаем то же самое, перенося нижний отступ контейнера на саму
   прошивку. Сумма стыка не меняется, меняется только положение линии.

   Оба правила закрыты одним :has(). Если браузер его не понимает, они
   отваливаются вместе и вёрстка остаётся сегодняшней — а не разъезжается
   сильнее, чем было. */
.e-con.pad:has(> .elementor-element:last-child .stitch){padding-bottom:0}
.e-con.pad:has(> .elementor-element:last-child .stitch) > .elementor-element:last-child .stitch{
  margin-top:calc(clamp(24px,4vh,48px) + clamp(56px,7vh,92px))}


/* ---------- ХЛЕБНЫЕ КРОШКИ ---------- */
/* Общие для всех страниц. Раньше жили только в gallery.css и constructor.css
   (две одинаковые копии), и на страницах документов, где этих файлов нет,
   «Главная» выводилась синей ссылкой браузера (замечено 13.09). Копии в тех
   файлах оставлены — они повторяют это правило и ничего не меняют. */
.crumbs{font-size:12.5px;color:var(--muted);margin-bottom:18px}
.crumbs a{color:var(--muted);text-decoration:none;border-bottom:1px solid var(--rule)}
.crumbs a:hover{color:var(--accent);border-bottom-color:var(--accent)}
.crumbs span{margin:0 6px;opacity:.5}

/* ---------- СТРАНИЦА 404 ---------- */
/* Слева текст и пути дальше, справа четыре последние работы. Цифры — контуром
   с оранжевым нулём-«мячом»: страница должна читаться как страница этого
   сайта, а не как системная ошибка сервера. */
.nf{min-height:calc(100svh - var(--hdr-h));display:flex;align-items:center}
.nf-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(28px,5vw,80px);align-items:center;width:100%}
.nf-code{font-family:'Bounded';font-weight:900;font-size:clamp(96px,15vw,220px);line-height:.9;letter-spacing:-.04em;
  color:transparent;-webkit-text-stroke:2px rgba(var(--ink-rgb),.55);margin:0 0 18px;user-select:none}
.nf-code span{color:var(--accent);-webkit-text-stroke:0}
.nf .h{max-width:18ch}
.nf-acts{margin-top:28px}
.nf-contacts{margin:26px 0 0;font-size:14px;line-height:1.7;color:var(--muted)}
.nf-contacts a,.nf-home a{color:var(--ink);text-decoration:underline;text-underline-offset:3px}
.nf-contacts a:hover,.nf-home a:hover{color:var(--accent)}
.nf-contacts span{margin:0 6px;opacity:.5}
.nf-home{margin:10px 0 0;font-size:14px}
.nf-works{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.nf-work{position:relative;display:block;aspect-ratio:4/5;border-radius:12px;overflow:hidden;background:var(--placeholder)}
.nf-work img{width:100%;height:100%;object-fit:cover;transition:transform .6s cubic-bezier(.22,1,.36,1)}
.nf-work:hover img{transform:scale(1.05)}
.nf-work span{position:absolute;left:10px;right:10px;bottom:10px;font-size:12px;line-height:1.3;color:var(--dark-fg);
  background:rgba(var(--dark-bg-rgb),.62);backdrop-filter:blur(8px);padding:6px 10px;border-radius:999px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:max-content;max-width:calc(100% - 20px)}
@media (max-width:900px){
  .nf{min-height:0}
  .nf-grid{grid-template-columns:1fr}
  .nf-works{grid-template-columns:repeat(4,1fr);gap:8px}
  .nf-work{aspect-ratio:3/4}
  .nf-work span{display:none}
}
@media (max-width:560px){
  .nf-works{grid-template-columns:1fr 1fr}
}

/* ---------- СНОСКА ПОД ФОРМАМИ ---------- */
/* Одна строка на все три формы сайта: согласие на обработку данных и — когда
   в wp-config.php заданы ключи — оговорка про SmartCaptcha. Раньше в квизе и
   каталоге это был текст без ссылки, а в конструкторе согласия не было вовсе. */
.form-legal{font-size:12px;line-height:1.55;color:var(--muted);margin:12px 0 0;text-align:center}
.form-legal a,.cat-legal a{color:var(--muted);text-decoration:underline;text-underline-offset:2px}
.form-legal a:hover,.cat-legal a:hover{color:var(--ink)}
.captcha-note{display:block;margin-top:4px;opacity:.8}

/* ---------- КАТАЛОГ: окно с формой перед скачиванием ---------- */
/* Кнопка «Скачать полный каталог» под сеткой готовой экипировки. */
.ready-cta{display:flex;justify-content:center;margin-top:38px}

.cat{position:fixed;inset:0;z-index:2200;display:flex;align-items:center;justify-content:center;
  padding:20px;background:rgba(var(--dark-bg-rgb),.82)}
/* Окно печатается в подвал и на странице лежит скрытым — без этого правила
   [hidden] проигрывает display:flex выше и форма видна всегда. */
.cat[hidden]{display:none}
.cat-card{position:relative;width:min(440px,100%);max-height:100%;overflow:auto;
  background:var(--surface);border:1px solid var(--rule);border-radius:16px;padding:30px 28px 26px}
.cat-close{position:absolute;top:12px;right:12px;width:36px;height:36px;border:0;border-radius:50%;
  background:rgba(var(--ink-rgb),.06);color:var(--ink);font-size:22px;line-height:1;cursor:pointer}
.cat-close:hover{background:var(--accent);color:var(--dark-fg)}
.cat-close:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.cat-h{font-family:'Bounded';font-weight:700;font-size:23px;line-height:1.18;margin:10px 0 10px}
.cat-note{font-size:14px;line-height:1.55;color:var(--muted);margin:0 0 20px}
.cat .frm{grid-template-columns:1fr}
.cat .errmsg{font-size:13px;color:var(--danger);margin:0 0 10px}
.cat-legal{font-size:12px;color:var(--muted);margin:12px 0 0;text-align:center}
.cat-done{font-size:14.5px;line-height:1.6;margin:0}
.cat-done b{color:var(--accent)}
.cat-file{display:inline-block;margin-top:14px;font-size:14px;color:var(--accent)}
/* display выше перебивает [hidden] — запасная ссылка на файл иначе видна
   сразу, до отправки формы. Та же грабля, что у .cat выше. */
.cat-file[hidden],.cat-done[hidden],.cat .errmsg[hidden],#catForm[hidden]{display:none}

@media (max-width:600px){
  .cat{padding:14px}
  .cat-card{padding:26px 20px 22px}
  .cat-h{font-size:20px}
}

/* ---------- ОКНО ПОДПИСКИ НА TELEGRAM-КАНАЛ ----------
   Разметка — inc/tg-popup.php, когда показывать — chrome.js. Вариант 2 из
   черновика dist/tg-popup/: две фотографии, аватар канала заходит на них. */
.tgp{position:fixed;inset:0;z-index:2200;display:flex;align-items:center;justify-content:center;
  padding:20px;background:rgba(var(--dark-bg-rgb),.78);-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
  opacity:0;transition:opacity .35s ease}
/* display:flex выше перебивает [hidden] — та же грабля, что у .cat. */
.tgp[hidden]{display:none}
.tgp.on{opacity:1}
.tgp-card{position:relative;width:min(460px,100%);max-height:100%;overflow:auto;overscroll-behavior:contain;
  background:var(--surface);border:1px solid var(--rule);border-radius:18px;
  box-shadow:0 30px 70px -20px rgba(var(--dark-bg-rgb),.9);
  translate:0 24px;transition:translate .5s cubic-bezier(.2,.8,.2,1)}
.tgp.on .tgp-card{translate:0 0}
.tgp-card:focus{outline:none}
/* Крестик лежит на фото, а у правого кадра белый фон — подложка тёмная. */
.tgp .tgp-x{z-index:2;background:rgba(var(--dark-bg-rgb),.62);color:var(--dark-fg)}
.tgp .tgp-x:hover{background:var(--accent)}
.tgp-photos{position:relative;display:grid;grid-template-columns:1fr 1fr;gap:3px;background:var(--dark-bg)}
/* С родителем: одиночный класс легче правил img из Elementor и сброса темы. */
.tgp .tgp-photos img{display:block;width:100%;height:320px;object-fit:cover;object-position:center top;background:var(--ink-2)}
/* На пиксель ниже края: при дробной высоте под градиентом оставалась тёмная полоска фона сетки. */
.tgp-photos::after{content:"";position:absolute;inset:auto 0 -1px 0;height:57px;pointer-events:none;
  background:linear-gradient(transparent,var(--surface))}
.tgp-body{padding:0 28px 20px;text-align:center}
.tgp-chan{position:relative;z-index:1;display:inline-flex;align-items:center;gap:10px;margin-top:-30px;text-align:left}
/* Как аватар канала: логотип на чёрном, оранжевая обводка. Тёмное кольцо снаружи
   отделяет обводку от белого кадра — без него они сливаются. */
.tgp .tgp-ava{flex:none;display:block;width:56px;height:56px;border-radius:50%;background:var(--dark-bg);
  border:2.5px solid var(--accent);box-shadow:0 0 0 3px var(--surface),0 6px 18px -6px rgba(var(--dark-bg-rgb),.9)}
.tgp-chan b{display:block;margin-top:22px;font-family:'Bounded';font-weight:700;font-size:14px;letter-spacing:.01em;color:var(--ink)}
.tgp-chan span{display:block;font-size:12px;color:var(--muted)}
.tgp-h{font-family:'Bounded';font-weight:700;font-size:24px;line-height:1.15;letter-spacing:-.01em;margin:10px 0 8px;color:var(--ink)}
.tgp-note{font-size:14.5px;line-height:1.55;color:var(--muted);margin:0 auto 20px;max-width:40ch}
.tgp-go{width:100%;justify-content:center;gap:10px}
.tgp-go svg{flex:none;width:17px;height:17px;fill:currentColor}
/* У <button> по умолчанию чёрный текст — на тёмном окне он невидим. */
.tgp-later{display:block;margin:8px auto 0;padding:8px 12px;border:0;background:none;cursor:pointer;
  font-family:'Involve';font-size:13.5px;color:var(--muted)}
.tgp-later:hover,.tgp-later:focus-visible{color:var(--ink)}

@media (max-width:600px){
  /* Снизу, над безопасной зоной — большой палец достаёт до кнопки. */
  .tgp{align-items:flex-end;padding:12px 12px calc(12px + env(safe-area-inset-bottom))}
  .tgp .tgp-photos img{height:210px}
  .tgp-body{padding:0 20px 14px}
  .tgp-h{font-size:20px}
}
/* Телефон боком и низкие окна: фото уменьшаются, чтобы кнопка осталась на экране. */
@media (max-height:620px){
  .tgp .tgp-photos img{height:150px}
}
@media (prefers-reduced-motion:reduce){
  .tgp,.tgp-card{transition:none}
}

/* ---------- Пометка «бета» у конструктора (28.09.2026, до переделки моделей) ---------- */
.hdr nav a .nav-beta{display:inline-block;margin-left:5px;padding:2px 5px;border-radius:999px;vertical-align:1px;
  font-size:9px;font-weight:700;line-height:1;letter-spacing:.04em;text-transform:uppercase;
  color:var(--accent);border:1px solid rgba(var(--accent-rgb),.6)}
.hdr nav a.on .nav-beta,.hdr nav a:hover .nav-beta,.hdr nav a:focus-visible .nav-beta{color:var(--cream);border-color:rgba(var(--cream-rgb),.7)}
/* На средних ширинах шапка уже ужата по лестнице брейкпоинтов, лишние 40px сжимали логотип. */
@media (max-width:1200px){.hdr nav a .nav-beta{display:none}}
.bnav a .bnav-beta{position:absolute;top:2px;right:calc(50% - 22px);font-size:9px;font-weight:700;line-height:1;
  padding:2px 3px;border-radius:6px;background:var(--accent);color:var(--dark-bg)}
.bnav a.on .bnav-beta{background:var(--dark-bg);color:var(--accent)}
.ctor-beta{margin:14px 0 0;max-width:62ch;font-size:13.5px;line-height:1.55;color:var(--muted);
  padding-left:12px;border-left:2px solid var(--accent)}

/* МОБИЛЬНАЯ ЧИТАЕМОСТЬ (12.10.2026). Яндекс Вебмастер 10.10 признал сайт
   недостаточно адаптированным: мелкий текст (10–11,5 px) и мелкие цели касания
   (ниже 32 px). Только ≤900px — на компьютере ничего не меняется. Размер
   подписей не ниже 12px, зона касания ссылок и кнопок не ниже 36px. */
@media (max-width:900px){
  .eyebrow,.hstats div span,.tech-shot figcaption,.ttag,#flow .fstep b,
  .dot .lbl,.citylist,.ftr-h,.cookie-note p,.ftr-social a,.bnav a{font-size:12px}
  .hdr nav a .nav-beta,.bnav a .bnav-beta{font-size:10px}
  .hdr-tel{min-width:40px;min-height:40px;justify-content:center}
  .cyc-dot{height:36px;margin:-16.5px 0}
  .qback{padding:10px 8px;margin:-10px -8px;min-height:36px}
  .ftr-col>a{display:inline-block;padding:10px 0;margin:-10px 0}
  .crumbs a{display:inline-block;padding:10px 4px;margin:-10px -4px}
}
