/* NextGen Robot — маркетплейс: каталог, карточка модели, решения, кейсы.
   Наследует токены и компоненты site.css; здесь только то, чего там нет. */

/* ---------- служебное ---------- */
/* Замечание Петра Костина: шрифт строки крошек («стрелка», «Главная»,
   «Роботы») крупнее. Уточнение разработчика: на 30%, а не вдвое - было 13px,
   стало 17px (13 x 1,3 = 16,9). Крошки одинаковы на всех страницах, поэтому
   кегль поднят у самого класса, а не только на каталоге роботов.
   Новая просьба Петра Костина: на 15% мельче - 17 x 0,85 = 14,45, округлили
   до 14px. */
.breadcrumbs { font: 400 14px/1.4 var(--font-body); color: var(--text-3); margin: 0 0 var(--space-4); display: flex; gap: 8px; flex-wrap: wrap; }
.breadcrumbs a { color: var(--text-2); text-decoration: none; }
.breadcrumbs a:hover { color: var(--text); }
/* разделитель светлее текста, но всё же виден: на цвете рамки он читался
   как 1.14:1 и на светлых экранах пропадал совсем */
.breadcrumbs span[aria-hidden] { color: var(--text-3); opacity: .6; }
/* стрелка «назад» перед первой крошкой (просьба с доски). Отрицательные поля
   по вертикали дают палец во всю кнопку, но не делают строку крошек выше.
   Вместе с кеглем крошек стрелка ужалась на те же 15%: значок 21px -> 18px
   (21 x 0,85 = 17,85), поле 29px -> 25px (29 x 0,85 = 24,65), поля -3px
   держат высоту строки в тех же 20px (14 x 1,4 = 19,6).
   Просьба Петра Костина: остриё стрелки должно стоять вровень с левым краем
   названия раздела. Значок центрирован в поле ((25 - 18) / 2 = 3,5px), а сам
   штрих начинается на 7,55 из 24 единиц вьюбокса (8,5 минус половина обводки
   1,9) - при масштабе 18/24 это ещё 5,7px. Итого пустоты 9px, их и снимаем
   полем слева; кнопка заходит в поле .wrap (24px), за край колонки не вылезая. */
.breadcrumbs__back {
  display: inline-flex; align-items: center; justify-content: center;
  width: 25px; height: 25px; margin: -3px 0 -3px -9px; flex: 0 0 auto;
}
.breadcrumbs__back svg { display: block; width: 18px; height: 18px; }
/* Замечание Петра Костина: на каталоге роботов расстояние от строки крошек
   до названия раздела сокращено вдвое - было 24px (--space-4), стало 12px.
   Отдельный модификатор, а не общее правило: под крошками на других
   страницах стоят другие блоки, там отступ пока прежний. */
.breadcrumbs--tight { margin-bottom: 12px; }

/* просьба с доски: расстояние от шапки меню до строки крошек («назад»,
   «главная» и далее) сокращено вдвое - сверху было 64px (--space-6), стало 32px.
   Значения нет в шкале отступов, поэтому число задано прямо. Нижний отступ не
   трогали: под ним на разных страницах стоят разные блоки. */
.page-head { padding: 32px 0 var(--space-5); }
.page-head__grid { display: grid; grid-template-columns: 1.1fr 1fr; gap: var(--space-6); align-items: center; }
.page-head h1 { max-width: 18ch; }
/* просьба с доски: название каталога стоит в одну строку и мельче обычного h1.
   Ограничение 18ch снято (иначе перенос). Новая просьба - ещё на 30% мельче:
   37px → 26px, 3.2vw → 2.24vw. Нижнюю границу оставили 20px, а не 17px: на
   телефоне заголовок иначе сравнивается по кеглю с обычным текстом.
   Без white-space: nowrap - на узком экране строка переносится, а не вылезает */
.page-head h1.page-head__title--oneline { max-width: none; font-size: clamp(20px, 2.24vw, 26px); }
/* Замечание Петра Костина: на «О компании» названия всех разделов (чёрные
   заголовок страницы и h2 секций) - тем же кеглем, что «Каталог роботов и
   техники» в каталоге: тот же clamp, 26px на десктопе. Ограничение по ширине
   у h1 снято, иначе «О компании» держит колонку в 18ch. */
.page-about .page-head h1 { max-width: none; }
.page-about .page-head h1,
.page-about .section > .wrap > h2 { font-size: clamp(20px, 2.24vw, 26px); }
.page-head__lead { color: var(--text-2); max-width: 56ch; margin: 0 0 var(--space-4); }
/* просьба с доски: на «О компании» вводный абзац читается свободнее.
   Отдельный модификатор, чтобы не менять интерлиньяж сразу на всех страницах.
   Кегль по просьбе Петра Костина - как у серого текста в разделе калькулятор
   (.section__lead, 18px), было 15px. Затем по новой просьбе - 16px. Сейчас
   просьба повторена уже про размер и форматирование целиком: берём параметры
   .section__lead со страницы калькулятора - 18px и интерлиньяж 1,6 (было
   16px/1,75). Цвет остаётся тёмным: так просили раньше, отдельной правкой. */
.page-head__lead--loose { line-height: 1.6; font-size: 18px; }
/* Замечание Петра Костина: на «О компании» вводный текст и кнопка «Связаться»
   лежат в белой карточке (.panel), текст в ней чёрный вместо серого --text-2.
   Кегль не трогаем. Ограничение 56ch снято: ширину держит сама карточка.
   Отступ от краёв карточки меньше типового (.panel: 24px сверху и снизу,
   40px по бокам).
   Правило раньше не срабатывало: .panel лежит ниже по файлу с той же
   специфичностью и перебивал отступ обратно на 24px/40px, поэтому селектор
   с .panel. Итоговое значение по новой просьбе - как в карточке кейса
   (.journey--case .jstep), то есть var(--space-3) = 16px со всех сторон;
   было 12px сверху и снизу, 20px по бокам. */
.panel.page-head__card { padding: var(--space-3); }
.page-head__card .page-head__lead { color: var(--text); max-width: none; }
.page-head__media { border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-card); }
.page-head__media img { display: block; width: 100%; height: 100%; object-fit: cover; aspect-ratio: 4/3; }

/* Знак бренда на «О компании» вместо фотографии: та же марка, что в шапке -
   круг с молнией, только светло-серая, и она медленно крутится по часовой
   стрелке (замечание Петра Костина). Прежняя сцена с роботом и книгой убрана
   вместе со своими кадрами. Фон прозрачный, без радиуса и тени - по просьбе
   заказчика блок не должен выделяться контуром на фоне страницы. */
.page-head__media--anim {
  border-radius: 0; box-shadow: none; overflow: visible; background: transparent;
  /* Высота - от верхнего края заголовка «О компании» до нижнего края кнопки
     «Связаться», 241px: заголовок 31px и 16px отступа, абзац 56px и 13px
     отступа (инлайновый), второй абзац 56px и 24px до ряда кнопок (отступы
     абзаца и .hero__actions схлопываются в один), и 45px самой кнопки.
     Было 266px: в расчёт шли абзацы по 63px от прежнего кегля 18px, а сейчас
     он 16px и абзац занимает 56px - из-за лишних 25px знак свисал ниже
     кнопки. Столбец прижат к верху; прежний отступ сверху (28px под
     надстрочник «бренд») снят вместе с самой надписью. */
  height: 241px; align-self: start;
  display: flex; align-items: center; justify-content: center;
}
/* Знак занимает всю высоту блока: его верх совпадает с верхом заголовка
   «О компании», низ - с нижним краем кнопки «Связаться» (замечание Петра
   Костина). Ширина по высоте, круг остаётся кругом. */
.brandloop { display: block; height: 100%; width: auto; aspect-ratio: 1; }
.brandloop__disc { fill: var(--border); }
.brandloop__bolt { fill: var(--surface); }
/* Медленный поворот по часовой стрелке, без остановки. Круг стоит в центре
   viewBox, поэтому вращение идёт ровно вокруг его середины. */
.brandloop__mark {
  transform-box: view-box; transform-origin: 100px 100px;
  animation: brandloop-spin 24s linear infinite;
}
@keyframes brandloop-spin { to { transform: rotate(360deg); } }
/* Без движения знак просто стоит на месте. */
@media (prefers-reduced-motion: reduce) {
  .brandloop__mark { animation: none; }
}

/* строка статистики (паттерн NextGen) */
.statrow {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-3);
  background: var(--white); border-radius: var(--radius); padding: var(--space-4) var(--space-5);
  box-shadow: var(--shadow-card); margin-top: var(--space-5);
}
.statrow__v { font: 700 26px/1.1 var(--font-display); letter-spacing: -0.02em; margin: 0; white-space: nowrap; }
.statrow__k { font-size: 13px; color: var(--text-2); margin: 4px 0 0; line-height: 1.4; }
/* Слоган вместо ряда цифр на странице «О компании»: та же белая карточка,
   но текст идёт одной строкой жирным по центру, без сетки из четырёх колонок
   (сетка ниже в медиазапросах на display:block не влияет). */
.statrow--slogan { display: block; text-align: center; margin-bottom: 0;
  font: 700 22px/1.3 var(--font-display); letter-spacing: -0.01em; }

/* ---------- умный поиск в первом экране ---------- */
/* Белая карточка осталась только под самой строкой поиска: выдача идёт ниже,
   прямо на холсте страницы, во всю ширину контейнера - так её карточки стоят
   ровно как в разделе «Робототехника» (правка заказчика). */
.ssearch-host { margin-top: var(--space-5); }
.ssearch__bar { background: var(--white); border-radius: var(--radius);
  padding: var(--space-4) var(--space-5); box-shadow: var(--shadow-card); }
/* position:relative держит выпадающий список вариантов запроса ровно под полем */
.ssearch { display: flex; gap: var(--space-3); align-items: stretch; position: relative; }
/* Список вариантов запроса: выпадает по нажатию в строку, а на страницу поиска
   уводит уже кнопка «Найти» или Enter (замечание Петра Костина). */
.sshints { position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 30;
  background: var(--white); border: 1px solid var(--border); border-radius: var(--radius-s);
  box-shadow: var(--shadow-card); padding: 6px; display: grid; gap: 2px;
  max-height: 320px; overflow: auto; }
.sshints[hidden] { display: none; }
.sshint { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  background: none; border: 0; cursor: pointer; padding: 8px 10px; border-radius: var(--radius-s);
  font: 400 14px/1.3 var(--font-body); color: var(--text); }
.sshint:hover, .sshint:focus-visible { background: var(--bg); }
.sshint svg { width: 16px; height: 16px; flex: none; color: var(--text-3); }
/* поле прямоугольное с лёгким скруглением - правка заказчика (замечание №82) */
/* «Найти» стоит внутри поля, справа (замечание Петра Костина), поэтому справа
   отступ меньше. min-height держит прежнюю высоту ряда: раньше её задавала
   кнопка, а по ней выровнен соседний блок «Рассчитайте свой кейс» */
/* Рамка поля синяя (правка заказчика: строка поиска должна выделяться).
   Толщина прежняя, 1px, поэтому высота и ширина поля не меняются. */
.ssearch__field { flex: 1; display: flex; align-items: center; gap: 10px; min-width: 0;
  background: var(--bg); border: 1px solid var(--accent); border-radius: var(--radius-s);
  padding: 0 6px 0 16px; min-height: 51px; }
/* Статичной лупы в начале строки нет (замечание Петра Костина): значок поиска
   остался один - на кнопке справа, которая появляется с первым символом. */
.ssearch__field input { flex: 1; min-width: 0; border: 0; background: none; outline: none;
  padding: 15px 0; font: 400 15px/1.3 var(--font-body); color: var(--text); }
/* Крестик сброса свой, а не родной браузерный: он должен появляться вместе с
   лупой на первом символе (уточнение разработчика), а момент показа родного
   крестика задаёт браузер, и в части браузеров его нет вовсе. Родной поэтому
   убран, свой - вдвое крупнее системного и спокойного серого тона. */
.ssearch__field input::-webkit-search-cancel-button {
  -webkit-appearance: none; appearance: none; display: none; }
.ssearch__clear { flex: none; display: grid; place-items: center; width: 20px; height: 20px;
  padding: 0; border: 0; background: none; cursor: pointer;
  color: var(--text-3); opacity: .5; }
.ssearch__clear svg { width: 20px; height: 20px; }
.ssearch__clear:hover { opacity: .85; }
.ssearch__clear[hidden] { display: none; }
/* Кнопка поиска: одна лупа без подписи, подложка спокойная - светлый accent-soft
   вместо яркой синей заливки (уточнение разработчика). Квадрат по высоте поля
   минус пара пикселей с каждой стороны; hidden прячет её до первого символа. */
.ssearch__go { flex: none; display: grid; place-items: center; width: 39px; height: 39px;
  padding: 0; border: 0; border-radius: var(--radius-s); cursor: pointer;
  background: var(--accent-soft); color: var(--accent); }
.ssearch__go svg { width: 20px; height: 20px; }
.ssearch__go:hover { box-shadow: inset 0 0 0 1px var(--accent); }
.ssearch__go[hidden] { display: none; }
.ssearch__hint { margin: 10px 0 0; font-size: 12px; line-height: 1.5; color: var(--text-3); }
/* Та же строка поиска в шапке (замечание Петра Костина): белой карточки и тени
   там не нужно - подложка у шапки своя. Высота поля и кегль текста теперь как
   в каталоге (правка заказчика): 51px и 15px из .ssearch__field выше, поэтому
   уменьшенных до 42px/14px значений здесь больше нет. */
.topbar__search .ssearch__bar { background: none; box-shadow: none; padding: 0; border-radius: 0; }
/* Верхний и нижний край строки поиска совпадают с плашкой лого на всех
   страницах (замечание Петра Костина). У плашки высота задана числом - 51px
   (.topbar__in > .logo--2l, site.css), а поле складывалось из min-height и
   отступов поля ввода и выходило выше: на стыке синих краёв это было видно.
   Теперь у поля то же число, а отступы поля ввода не участвуют - строку держит
   по центру align-items самого поля. */
.topbar__search .ssearch__field { height: 51px; }
.topbar__search .ssearch__field input { padding: 0; }

/* Пока открыт список вариантов, остальная рабочая область страницы затемняется
   на 10%, а строка поиска и сам список - нет (замечание Петра Костина). Слоёв
   два: шапка стоит выше по стеку (z-index 50 у .topbar), и одним слоем страницу
   вместе с ней не накрыть. Строку поиска поднимает над внутренним слоем правило
   .topbar__search в site.css. Слои ставит js/search-hints.js. */
.ss-dim { position: fixed; inset: 0; z-index: 49; background: rgba(15, 23, 42, .1); }
.ss-dim--head { position: absolute; z-index: 1; }
/* свёрнутый калькулятор сразу под строкой поиска (правка заказчика): блок тот же,
   что выпадает в выдаче, - нажатие раскрывает выбор кейса, поля и смету */
.ssearch__calc { margin-top: var(--space-3); }
/* по высоте блок равен строке поиска выше (правка заказчика): 51px кнопки
   «Найти» плюс отступы .ssearch__bar сверху и снизу. Подпись из двух строк в
   эту высоту укладывается, поэтому блоки стоят ровной парой */
.ssearch__calc .sscta { margin-bottom: 0; align-content: center;
  min-height: calc(51px + var(--space-4) * 2); }
.ssearch__calc .sspick { margin: var(--space-3) 0 0; }
.ssearch__note { margin: 12px 0 0; font-size: 13px; line-height: 1.5; color: var(--text-2); }
/* подсказки по мере ввода остаются отдельной белой плашкой под строкой */
.ssearch__rows { display: grid; gap: 6px; margin-top: var(--space-3);
  background: var(--white); border-radius: var(--radius); padding: var(--space-3);
  box-shadow: var(--shadow-card); }
/* выдача остаётся на этой же странице, под строкой поиска (замечание №84) */
.ssearch__res { margin-top: var(--space-4); }
/* Выдача, отрисованная в слое, возвращается на страницу по крестику уже готовой:
   наблюдатель из motion.js её карточки не открывал, и они оставались на
   opacity:0 - выглядело так, будто результаты пропали (замечание Петра Костина).
   Правило то же, что для слоя ниже: в выдаче появление по прокрутке не играет. */
.ssearch__out [data-rv] { opacity: 1 !important; transform: none !important; }
.ssearch__cap { margin: 0; font: 600 12px/1 var(--font-body); color: var(--text-3);
  text-transform: uppercase; letter-spacing: .04em; }
/* выдача по кнопке «Найти» - те же карточки и та же сетка, что в разделе
   «Робототехника» (правка заказчика): рамка и белая подложка им больше не нужны */
.ssearch__group + .ssearch__group { margin-top: var(--space-4); }
.ssearch__grid { margin-top: var(--space-3); }
/* выдача каталога без запроса идёт без подписи сверху - отступ на её месте не нужен */
.ssearch__group > .ssearch__grid:first-child { margin-top: 0; }
.ssearch__group + .ssearch__more { margin-top: var(--space-4); }
.ssearch__more { margin: 10px 0 0; display: flex; gap: var(--space-4); flex-wrap: wrap; }
.ssearch__more a { font: 600 13px/1.4 var(--font-body); color: var(--accent);
  text-decoration: none; }
.ssearch__more a:hover { text-decoration: underline; }
/* «Начать заново» в пустой выдаче: кнопка оформлена ссылкой этого же ряда -
   синяя, с подчёркиванием (правка разработчика) */
.ssearch__restart { background: none; border: 0; padding: 0; cursor: pointer;
  font: 600 13px/1.4 var(--font-body); color: var(--accent);
  text-decoration: underline; text-underline-offset: 3px; }
/* поля кейса под строкой поиска: те же компоненты, что в блоке «Калькулятор
   эффекта» на cases.html, только компактнее. Сметы здесь нет - кнопка
   «Рассчитать эффект» открывает её на cases.html (замечание Петра Костина).
   Раньше здесь была ссылка-карточка .sscase - её заменили поля кейса */
.sscalc { padding: var(--space-4); border-radius: var(--radius-s); background: var(--accent-soft);
  margin-bottom: var(--space-3); }
/* надкатегория «кейс с расчётом» убрана по замечанию Петра Костина - блок
   начинается сразу с названия кейса */
.sscalc__t { display: block; font: 600 18px/1.25 var(--font-display); }
.sscalc__d { margin: 4px 0 0; font-size: 13px; color: var(--text-2); }
.sscalc .case-form { margin: var(--space-3) 0; }
.sscalc .case-run-row { margin-bottom: 0; }
.sscalc .case-status, .sscalc .case-error { margin: var(--space-3) 0 0; }
.sscalc .case-status:empty, .sscalc .case-error:empty { margin: 0; }

.ssrow { display: grid; grid-template-columns: 72px 1fr auto; gap: 12px; align-items: center;
  text-decoration: none; color: inherit; padding: 6px; border-radius: var(--radius-s); }
.ssrow:hover { background: var(--bg); }
.ssrow img { width: 72px; height: 48px; object-fit: cover; border-radius: var(--r-xs); display: block; }
.ssrow__b { min-width: 0; }
.ssrow__b b { display: block; font: 600 14px/1.3 var(--font-body); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.ssrow__b span { font-size: 12px; color: var(--text-3); }
.ssrow__k { font: 600 11px/1 var(--font-body); color: var(--accent);
  background: var(--accent-soft); padding: 5px 9px; border-radius: var(--pill); white-space: nowrap; }

@media (max-width: 640px) {
  /* кнопка теперь внутри поля и осталась квадратом с лупой: во всю ширину её
     не растягиваем, место в строке нужно набранному запросу */
  .ssearch { flex-direction: column; }
}

/* ---------- селектор типов роботов ---------- */
/* Шесть плиток в ряд (просьба заказчика 08-29): весь список типов техники
   помещается в одну строку и не занимает пол-экрана. Плиток больше шести,
   поэтому строка стала каруселью (просьба заказчика 08-31): свайп нативный
   (scroll-snap), а стрелки вынесены ЗА ширину карусели - слева и справа от
   неё (уточнение разработчика), поэтому обёртке нужен position: relative. */
.typecar { position: relative; margin-bottom: calc(var(--space-5) - 14px); }
.typegrid {
  display: grid; grid-auto-flow: column;
  grid-auto-columns: calc((100% - 5 * var(--space-3)) / 6);
  gap: var(--space-3); overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none;
  /* поля под тень и подъём плитки на наведении: scroll-контейнер обрезает
     всё, что выходит за его край. Верхнее поле возвращаем отрицательным
     margin, нижнее засчитано в margin-bottom обёртки - отступы блока прежние.
     По бокам поле такое же (замечание Петра Костина): без него тень первой и
     последней плитки срезалась ровно по краю карусели. Отрицательный margin
     возвращает строку на прежнее место, ширина колонок считается от
     content-box и не меняется, а scroll-padding оставляет scroll-snap на краю
     плитки, а не на краю поля.
     Боковое поле равно просвету между плитками (var(--space-3), 16px) -
     уточнение разработчика: поле шире просвета показывало бы у края кусок
     соседней плитки, а так её край приходится ровно на край карусели и в поле
     остаётся только тень. 16px меньше поля .wrap, поэтому горизонтальной
     прокрутки страницы не появляется, а плитки стоят на прежнем месте. */
  padding: 6px var(--space-3) 14px; margin: -6px calc(-1 * var(--space-3)) 0;
  scroll-padding-inline: var(--space-3);
  /* Край прокрутки всё равно режет всё по прямой: плитка, уехавшая влево,
     обрывалась вместе с тенью. Внешние 8px поля гасим плавно, поэтому тень
     соседней плитки растворяется, а не обрезается. Плитка в снапе стоит на
     16px от края, её собственная тень достаёт до 9px - в прозрачную зону не
     попадает ни она, ни тень. */
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 8px,
    #000 calc(100% - 8px), transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 8px,
    #000 calc(100% - 8px), transparent 100%);
}
.typegrid::-webkit-scrollbar { display: none; }
.typegrid:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.typecard { scroll-snap-align: start; }
/* плитки правее видимой части карусели иначе остались бы скрытыми
   reveal-эффектом до первой прокрутки */
.typegrid [data-rv] { opacity: 1 !important; transform: none !important; }

/* Вид стрелок общий с каруселью карточек (.cardcar ниже): рисунок кнопки один,
   меняется только то, что она листает. */
.typecar__nav, .cardcar__nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid var(--border); background: var(--white); color: var(--text);
  font: 600 15px/1 var(--font-body); cursor: pointer; display: grid; place-items: center;
  box-shadow: var(--shadow-card); transition: border-color .15s ease, color .15s ease;
}
/* 100% - край карусели, плюс 12px просвета: кнопка целиком снаружи блока */
.typecar__nav--prev, .cardcar__nav--prev { right: calc(100% + 12px); }
.typecar__nav--next, .cardcar__nav--next { left: calc(100% + 12px); }
.typecar__nav:hover:not([disabled]), .cardcar__nav:hover:not([disabled]) { border-color: var(--accent); color: var(--accent); }
.typecar__nav[disabled], .cardcar__nav[disabled] { opacity: .3; cursor: default; }
/* Снаружи кнопки помещаются, пока по краям есть 52px: макет 1240px плюс поля
   .wrap. Уже 1300px полей не хватает - там стрелки возвращаются на края
   карусели, иначе они уедут за экран и появится горизонтальная прокрутка.
   На телефоне листание остаётся свайпом, как в карусели изображений. */
@media (max-width: 1300px) {
  .typecar__nav, .cardcar__nav { background: rgba(255, 255, 255, .94); }
  .typecar__nav--prev, .cardcar__nav--prev { right: auto; left: 4px; }
  .typecar__nav--next, .cardcar__nav--next { left: auto; right: 4px; }
}
@media (max-width: 640px) { .typecar__nav, .cardcar__nav { display: none; } }
.typecard {
  display: block; text-align: left; text-decoration: none; background: var(--white); border: 1px solid transparent;
  border-radius: var(--radius); padding: 0; overflow: hidden; cursor: pointer;
  font: inherit; color: inherit; box-shadow: var(--shadow-card);
  transition: transform .15s ease, border-color .15s ease, box-shadow .15s ease;
}
/* Оттенение плитки-фильтра включается на наведении и взято вдвое тоньше
   --shadow-lift: 6px/24px → 3px/12px (уточнение разработчика). В покое ряд
   остаётся с обычной тенью карточки, поэтому карусель не рябит. Боковые поля
   .typegrid оставлены прежними - они же держат подъём плитки. */
.typecard:hover { transform: translateY(-2px); box-shadow: 0 3px 12px rgba(16, 24, 40, .10); }
.typecard[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 4px 16px rgba(43, 92, 230, .18); }
/* Пэкшот в плитке: объект одного визуального масштаба и строго по центру
   (правка заказчика 08-11). Раньше стоял object-fit: cover - рендеры с разной
   компоновкой кадра обрезались по-разному, и техника «прыгала» по размеру. */
/* Кадр ниже прежнего (16/10 → 16/9): в ряду из шести плитка получается
   примерно квадратной, изображение уменьшается вместе с кадром, а не
   обрезается - object-fit остаётся contain. */
/* Высота кадра зафиксирована в 104px вместо aspect-ratio (замечание Петра
   Костина): раньше она считалась от ширины плитки, поэтому пэкшоты и иконки
   отличались по размеру между каталогами роботов, ИИ-решений и кейсов и
   менялись на каждой ширине экрана. 104px - прежняя высота кадра в ряду из
   шести плиток (184px по 16/9), так что ряд плиток не съехал. */
.typecard__ph { display: block; width: 100%; height: 104px; background: #fff; }
.typecard__ph--illus { color: var(--text-3); }
.typecard__ph--illus svg { width: 64%; height: auto; max-height: 100%; }
/* Плитка отрасли в кейсах: вместо пэкшота - контурная иконка того же набора,
   что у плиток отраслей на главной (.indtile), поэтому цвет тот же. Кадр
   остаётся 16/9, иконка стоит по центру - размер плитки не меняется. */
.typecard__ph--icon { display: grid; place-items: center; color: var(--accent); }
/* Иконка увеличена втрое (46px → 138px по просьбе заказчика) и затем убавлена
   на 15% - 117px. Кадр 16/9 при этом не растёт, поэтому держим max-height: 85%:
   иконка не упирается в края кадра (~88px в ряду из шести), размер плитки прежний. */
.typecard__ph--icon svg { width: 85%; max-width: 117px; max-height: 85%; height: auto; }
.typecard__ph--photo img { display: block; width: 100%; height: 100%;
  object-fit: contain; }
/* Под подписями оставляем небольшой отступ вместо прежних 24px: пустое
   место снизу и делало плитку высокой. Просвет между кадром и подписью
   уменьшен вдвое (8 → 4px, замечание Петра Костина): сэкономленные пиксели
   сняты с запаса высоты тела в wow.css, поэтому ряд плиток стал ниже. */
.typecard__body { padding: var(--space-1) var(--space-3) 12px; }
.typecard__t { display: block; font: 600 15px/1.3 var(--font-display); }
.typecard__h { display: block; font-size: 13px; color: var(--text-2); margin-top: 3px; }
.typecard__n { display: block; font: 600 11px/1 var(--font-body); color: var(--accent); margin-top: 8px; }

/* ---------- панель фильтров ---------- */
/* Фильтры стоят над карточками во всю ширину блока (замечание Петра Костина):
   витрина - одна колонка, панель фильтров её первая строка. Раньше это была
   узкая липкая колонка слева на 264px. */
.market { display: grid; grid-template-columns: 1fr; gap: var(--space-4); align-items: start; }
.market > * { min-width: 0; }
/* Общей белой подложки с тенью у панели больше нет (замечание Петра Костина):
   фильтры - просто ряд кнопок над витриной, как в разделе поиска на главной.
   Своих стилей у .filters поэтому не осталось: расстояние до карточек держит
   gap витрины, а вид кнопок - классы .ssfd. */
/* Заголовка «Фильтры» и отдельной строки над рядом больше нет (замечание Петра
   Костина): панель - это один ряд кнопок, «Сбросить» замыкает его. */
.filters__reset { background: none; border: 0; padding: 0; cursor: pointer; font: 500 13px/1 var(--font-body); color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
/* В ряду фильтров «Сбросить» - обычная надпись между кнопками-пилюлями, поэтому
   отделяем её лишним шагом отступа и выравниваем по центру кнопок. */
.filters__row > .filters__reset { margin-left: var(--space-2); align-self: center; }
/* Варианты внутри группы идут рядом и переносятся: 20 отраслей укладываются
   в три ряда по ширине блока, а не в двадцать строк узкой колонки. */
.fgroup { border-top: 1px solid var(--border); padding: var(--space-3) 0 var(--space-2);
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.fgroup:first-of-type { border-top: 0; padding-top: 0; }
.fgroup__t { flex: 0 0 100%; font: 600 11px/1 var(--font-body); letter-spacing: .07em; text-transform: uppercase; color: var(--text-3); margin: 0 0 2px; }
.fopt { display: flex; align-items: center; gap: 8px; padding: 6px 12px; cursor: pointer; font-size: 14px; color: var(--text-2);
  background: var(--surface-2); border: 1px solid transparent; border-radius: var(--pill); white-space: nowrap; }
.fopt input { accent-color: var(--accent); width: 15px; height: 15px; }
.fopt:hover { color: var(--text); border-color: var(--accent); }
.fopt__n { font: 400 12px/1 var(--font-mono); color: var(--text-3); }
.frange { display: flex; gap: 8px; align-items: center; }
.frange input { width: 132px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-s); padding: 8px 10px; font: 400 13px/1.2 var(--font-mono); color: var(--text); }
/* Ряд кнопок с выпадающими списками - как в разделе поиска на главной
   (замечание Петра Костина): вместо рядов галочек в панели стоят «Отрасль»,
   «Задача», «Цена» и «Окупаемость», значения раскрываются под кнопкой. Сами
   кнопки и списки оформлены классами .ssfd (styles/wow.css) - теми же, что в
   поисковом слое, поэтому здесь остаётся только раскладка ряда. */
.filters__row { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
/* Кнопки фильтров вставляет js (catalog.js, pages.js) уже после загрузки, а до
   этого в ряду стоит одна надпись «Сбросить» высотой 13px. Ряд подрастал с 13
   до 32px, и вся выдача под ним уезжала вниз - это и был весь CLS каталогов
   (замер 05.09: 0,1099 на robots.html и 0,1206 на solutions.html, оба - десктоп).
   Резервируем высоту одной кнопки-пилюли: 13px текста + 2x8px поля + 2x1px рамка
   (.ssfd__btn в wow.css). План прода 05.09, шаг 0.5. */
.filters__row { min-height: 32px; }
/* На узком экране кнопки переносятся на второй ряд, и список, привязанный к
   своей кнопке, вылезал за правый край панели. Там он раскрывается во всю
   ширину ряда: .ssfd отдаёт привязку ряду (у него position: relative). */
@media (max-width: 640px) {
  .filters__row .ssfd { position: static; }
  .filters__row .ssfd__menu { left: 0; right: 0; width: auto; max-width: none; }
}

.market__bar { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; margin-bottom: var(--space-4); }
.market__count { font: 500 14px/1 var(--font-body); color: var(--text-2); }
/* Надпись «Найдено моделей: N» убрана с экрана каталога по замечанию Петра
   Костина. Сам элемент остаётся: это live-регион role="status", он озвучивает
   результат фильтрации скринридерам, и в него пишет catalog.js. */
.market__count--sr {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  border: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* ---------- карточка модели ---------- */
/* Карточки ряда тянутся на общую высоту: цена и кнопки прижаты к низу
   (margin-top:auto у .prod__price), поэтому ряд выравнивается по низу и
   текстовым блокам больше не нужно резервировать пустые строки. */
.prodgrid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-3); align-items: stretch; }
.prod {
  background: var(--white); border-radius: var(--radius); overflow: hidden;
  box-shadow: var(--shadow-card); display: flex; flex-direction: column;
}
.prod__media { position: relative; display: block; aspect-ratio: 4/3; background: var(--surface-2); overflow: hidden; }
.prod__media { background: #fff; }
.prod__media img { width: 100%; height: 100%; object-fit: contain; display: block; padding: var(--space-3); }
.prod__media--illus { display: grid; place-items: center; color: var(--text-3); padding: var(--space-3); }
.prod__media--illus svg { width: 82%; height: auto; }
.prod__badge {
  position: absolute; top: 12px; left: 12px; z-index: 1;
  font: 600 11px/1 var(--font-body); background: var(--ink); color: #F2F2F1;
  padding: 6px 10px; border-radius: var(--pill);
}
.prod__rating { position: absolute; top: 12px; right: 12px; z-index: 1; font: 700 12px/1 var(--font-body); background: rgba(255,255,255,.92); color: var(--text); padding: 6px 9px; border-radius: var(--pill); }
.prod__body { padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); flex: 1; }
.prod__brand { font: 600 11px/1 var(--font-body); color: var(--text-3); text-transform: uppercase; letter-spacing: .06em; }
/* Название занимает столько строк, сколько есть: вторая строка больше не
   резервируется, иначе у короткого имени под чёрной надписью зияла пустая
   строка перед серым описанием (замечание Петра Костина). Клэмп на две строки
   остаётся - длинное имя карточку не растянет, а ряд держится на выравнивании
   карточек по высоте (.prodgrid) и margin-top:auto у цены. */
.prod__name { font: 600 18px/1.3 var(--font-display); letter-spacing: -0.01em; margin: 0;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
/* Фиксированные высоты текстовых блоков: иначе цена и кнопки в соседних
   карточках ряда съезжают на высоту одной строки (баг ревью 08-07). */
.prod__tag { font-size: 13px; color: var(--text-2); line-height: 1.45; margin: 0;
  min-height: calc(2 * 1.45em); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
/* Оговорка о происхождении данных: поставщик или типовая конфигурация. Стоит
   ПОД характеристиками, потому что есть не у каждой карточки: блоки выше идут
   фиксированной высоты, а разницу забирает margin-top:auto у цены - иначе
   карточки с оговоркой и без неё разъезжаются по сетке. */
.prod__src { margin: 0; font-size: 11px; line-height: 1.35; color: var(--text-3); min-height: calc(2 * 1.35em); }
.prod__src b { color: var(--text-2); font-weight: 600; }
.prod__src small { display: block; font-size: 11px; color: var(--text-3); }
.prod__src--partner b { color: var(--text); }
.prod__specs { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, 1fr);
  grid-auto-rows: 30px; gap: 6px var(--space-3); min-height: 66px; align-content: start; }
.prod__specs li { display: grid; grid-template-columns: minmax(0, auto) minmax(0, 1fr); align-items: baseline;
  gap: 8px; font-size: 12px; color: var(--text-2); border-bottom: 1px solid var(--border);
  padding-bottom: 5px; min-height: 24px; }
/* Название характеристики сжимается первым, значение не налезает на него:
   длинное значение обрезается многоточием, полный текст - в подсказке (08-11). */
.prod__specs li > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* justify-self:end давал элементу ширину по содержимому, и длинное значение
   вылезало из своей колонки поверх названия. Ширина строго по колонке. */
.prod__specs li b { min-width: 0; width: 100%; justify-self: stretch; text-align: right;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.prod__specs b { font: 600 12px/1.4 var(--font-body); color: var(--text); }
/* Цена синяя во всех карточках и на карточках товара (замечание Петра
   Костина): цвет берётся из --accent, как ссылки и кнопки сайта.
   Пояснение в small остаётся серым. */
.prod__price { margin: auto 0 0; padding-top: var(--space-2); font: 700 18px/1.2 var(--font-display); letter-spacing: -0.01em;
  color: var(--accent); }
.prod__price small { display: block; font: 400 12px/1.4 var(--font-body); color: var(--text-2); margin-top: 3px; }
.prod__actions { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.prod__actions .btn { padding: 10px 16px; font-size: 13px; }

/* раскрытие калькулятора внутри карточки */
.prod__calc { border-top: 1px solid var(--border); background: var(--surface); padding: 0; }
.prod__calc[hidden] { display: none; }
.prod__calc-in { padding: var(--space-3) var(--space-4) var(--space-4); }
.prod__calc-t { font: 600 11px/1 var(--font-body); letter-spacing: .07em; text-transform: uppercase; color: var(--text-3); margin: 0 0 var(--space-3); }

/* ---------- мини-калькулятор ---------- */
.minicalc { display: block; }
.mc-fields { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2) var(--space-3); margin-bottom: var(--space-3); }
.mc-field { display: flex; flex-direction: column; gap: 5px; }
.mc-field span { font-size: 11px; color: var(--text-2); line-height: 1.3; }
.mc-field input {
  width: 100%; background: var(--white); border: 1px solid var(--border); border-radius: var(--radius-s);
  padding: 8px 10px; font: 600 14px/1.2 var(--font-mono); color: var(--text); margin-top: auto;
}
.mc-field input:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; }
.mc-out { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-3); padding: var(--space-3) 0 var(--space-2); border-top: 1px solid var(--border); }
.mc-out__label { font-size: 12px; color: var(--text-2); margin: 0 0 4px; line-height: 1.3; }
.mc-out__val { font: 700 18px/1.15 var(--font-mono); margin: 0; color: var(--good); font-variant-numeric: tabular-nums; }
.mc-out__val--warn { color: var(--warn); }
.mc-assum summary { cursor: pointer; font-size: 12px; color: var(--text-2); padding: 8px 0 0; }
.mc-assum ul { margin: 8px 0 0; padding-left: 18px; font-size: 12px; color: var(--text-2); line-height: 1.5; }
.mc-assum li { margin-bottom: 5px; }

/* ---------- детальная карточка модели ---------- */
/* Замечание Петра Костина: строка крошек на карточках (кейс, робот,
   ИИ-решение) стоит ровно посередине между нижним краем шапки меню и верхним
   краем изображения. Поэтому отступ сверху и снизу у неё одинаковый - 24px
   (--space-4) вместо прежних 32px сверху и 12px (кейс) или 24px (робот,
   ИИ-решение) снизу. Каталоги и остальные страницы не трогаем: там под
   крошками стоит заголовок раздела, а не кадр. */
#case-root .page-head,
#robot-root .page-head,
#solution-root .page-head { padding-top: var(--space-4); }
#case-root .page-head .breadcrumbs,
#robot-root .page-head .breadcrumbs,
#solution-root .page-head .breadcrumbs { margin-bottom: var(--space-4); }

/* колонка с названием, описанием и кнопками выровнена по верху кадра
   (правка заказчика 09-02). До этого она центрировалась по высоте фото
   (v144 от 08-15): так под кнопками не оставалось пустого поля, но начало
   текста уезжало вниз от верхней границы изображения. Заказчик выбрал
   верхнюю границу - пустое поле под кнопками при коротком описании
   это осознанный размен, не дефект вёрстки. */
.detail { display: grid; grid-template-columns: 1.15fr 1fr; gap: var(--space-6); align-items: start; }
.detail > * { min-width: 0; }
.detail__media { border-radius: var(--radius); overflow: hidden; background: var(--white); box-shadow: var(--shadow-card); }
.detail__media img { display: block; width: 100%; aspect-ratio: 4/3; object-fit: contain; background: #fff; padding: var(--space-4); }
.detail__media--illus { display: grid; place-items: center; padding: var(--space-5); color: var(--text-3); aspect-ratio: 4/3; }
.detail__media--illus svg { width: 78%; height: auto; }
.detail__note { font: 400 12px/1.5 var(--font-body); color: var(--text-3); margin: var(--space-2) 0 0; }
.detail__title { margin: 0 0 var(--space-2); }
/* Название на карточках (роботы, ИИ-решения, кейсы) - фиксированные 30px
   (уточнение к замечанию Петра Костина) вместо базовой шкалы h1
   clamp(30px, 4vw, 46px). Остальные заголовки страниц не трогаем.
   Ограничение .page-head h1 (18ch ≈ 364px) здесь снято: название занимает всю
   ширину колонки и переносится, только если в неё не влезает (замечание
   Петра Костина). Без white-space: nowrap - иначе на узком экране строка
   вылезала бы за край вместо переноса. */
.detail__title,
#robot-root .page-head h1,
#solution-root .page-head h1,
#case-root .page-head h1 { font-size: 30px; max-width: none; }
/* Названия разделов на карточках кейса, модели и ИИ-решения - на 15% мельче
   (замечание Петра Костина). Базовая шкала h2 clamp(24px, 2.8vw, 34px) x 0,85
   даёт clamp(20px, 2.38vw, 29px): 24 -> 20,4, 34 -> 28,9. Селектор берёт только
   чёрные заголовки секций (прямые дети .wrap) - подписи панелей .panel__t и
   светлые заголовки на тёмных плашках (.ctabar, .panel--dark) остаются как были. */
#robot-root .section > .wrap > h2,
#solution-root .section > .wrap > h2,
#case-root .section > .wrap > h2 { font-size: clamp(20px, 2.38vw, 29px); }
/* Кегль ради одной строки не уменьшаем (уточнение разработчика): длинные
   названия кейсов - «Автоматизация складской логистики» требует ~554px при
   колонке 540px, «Контроль качества на производстве электроники» и того
   больше - переносятся на вторую строку, это нормальное поведение. */
/* Бренд - ссылка в каталог с фильтром по этому бренду. При наведении надпись
   светлеет, подчёркивания нет: #6A7688 даёт 4,6:1 на белом, то есть AA
   сохраняется и в наведённом состоянии.
   Блок без верхнего отступа и по ширине надписи (замечание Петра Костина):
   верхний край надписи встаёт вровень с верхним краем изображения слева, а
   кликабельной остаётся сама надпись, а не вся ширина колонки. */
.detail__brand { display: block; width: fit-content;
  margin: 0 0 var(--space-2); font: 600 12px/1 var(--font-body); color: var(--text-3); text-transform: uppercase; letter-spacing: .06em;
  text-decoration: none; transition: color .15s ease; }
.detail__brand:hover, .detail__brand:focus-visible { color: #6A7688; }
.detail__lead { color: var(--text-2); margin: 0 0 var(--space-4); }
.detail__origin { margin: 0 0 var(--space-4); padding: var(--space-3); border: 1px solid var(--border);
  border-radius: var(--radius-s); background: var(--surface); font-size: 13px; line-height: 1.5; color: var(--text-2); }
.detail__origin b { color: var(--text); }
.detail__price { font: 700 30px/1.1 var(--font-display); letter-spacing: -0.02em; margin: 0 0 var(--space-1);
  color: var(--accent); }
.detail__price small { display: block; font: 400 14px/1.5 var(--font-body); color: var(--text-2); margin-top: 6px; }
.detail__actions { display: flex; gap: var(--space-3); flex-wrap: wrap; margin: var(--space-4) 0 0; }
/* Кнопки действий одной высоты (замечание Петра Костина): в ряду стоят и
   ссылки, и <button>, а при переносе на вторую строку тянуться флексу уже не за
   кем - поэтому высота задана общим min-height, а не растяжением ряда. 45px -
   собственная высота .btn (padding 12px + строка 15/1,3 + рамка). */
.detail__actions .btn { min-height: 45px; }

/* «Расчет на своих вводных» под кнопками - ссылка, а не третья кнопка
   (замечание Петра Костина): путь к расчёту на виду, но не спорит с целевым
   действием карточки. */
.detail__calclink { margin: var(--space-3) 0 0; font: 600 14px/1.4 var(--font-body); }
.detail__calclink a { color: var(--accent); text-decoration: none; }
.detail__calclink a:hover, .detail__calclink a:focus-visible { text-decoration: underline; }
/* Замечание Петра Костина: по этой ссылке страница прокручивалась так, что верх
   раздела расчёта уходил под липкую шапку с поиском, и надпись «калькулятор
   эффекта» с заголовком было не видно. Отодвигаем якорь на высоту шапки - то же
   значение, что у якорей разделов главной (site.css, scroll-margin-top: 150px):
   шапка в две строки занимает 129px, остальное - воздух над заголовком. */
#case-root #calc,
#solution-root #calc { scroll-margin-top: 150px; }

.speclist { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-2) var(--space-4); }
.speclist li { display: flex; justify-content: space-between; gap: var(--space-2); border-bottom: 1px solid var(--border); padding: 9px 0; font-size: 14px; color: var(--text-2); }
.speclist b { font: 600 14px/1.4 var(--font-body); color: var(--text); text-align: right; }

/* Замечание Петра Костина: на странице решения строки параметров идут друг под
   другом одной колонкой - список читается сверху вниз, а не змейкой по двум
   столбцам. На странице модели (robot-page) раскладка в две колонки остаётся. */
#solution-root .speclist { grid-template-columns: 1fr; }

/* Панель характеристик с раскрытием: кликабельна целиком, курсор об этом
   подсказывает, надпись внизу переключает состояние. При наведении надпись
   только светлеет - без подчёркивания, как у остальных кликабельных мест. */
.panel--specs { cursor: pointer; }
.speclist__toggle { margin-top: var(--space-3); padding: 0; border: 0; background: none;
  font: 600 13px/1.4 var(--font-body); color: var(--accent); cursor: pointer; }
.speclist__toggle:hover { opacity: 0.75; }

/* min-width:0 у панели и её строк: по умолчанию grid/flex-элемент не уже своего
   содержимого, и длинная строка спецификации распирала документ (MOBILE-001) */
.panel { background: var(--white); border-radius: var(--radius); padding: var(--space-4) var(--space-5); box-shadow: var(--shadow-card); min-width: 0; }
.cardgrid > *, .newsgrid > * { min-width: 0; }
.speclist li { min-width: 0; overflow-wrap: anywhere; }
.speclist li b { min-width: 0; }
.panel + .panel { margin-top: var(--space-3); }
/* max-width:24ch с глобального h2 при кегле 17px обрезает строку на 269 px:
   заголовок панели ломался пополам при свободном месте справа */
.panel__t { font: 600 18px/1.3 var(--font-display); letter-spacing: -0.01em;
  margin: 0 0 var(--space-3); max-width: none; }
.panel--dark { background: var(--ink); color: var(--text); }

.chips { display: flex; gap: 8px; flex-wrap: wrap; margin: 0; padding: 0; list-style: none; }
.chip { font: 500 13px/1 var(--font-body); background: var(--surface); border: 1px solid var(--border); border-radius: var(--pill); padding: 8px 13px; color: var(--text-2); }
.chip--on { background: var(--ink); color: #F2F2F1; border-color: var(--ink); }
/* Светло-синяя плашка: тот же тон, что у тегов новостей (.nrow__tag) и выбранных
   плиток - --accent-soft под --accent. Для перечислений, которые не являются
   выбранным состоянием фильтра: чёрная заливка chip--on читается как «включено». */
.chip--accent { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-soft); }
/* Зелёная плашка результата: тон экономии --good на подложке --good-soft, как у
   цифр эффекта. Ставится на показатель, а не на фильтр, поэтому не ссылка и без
   состояния при наведении. */
.chip--good { background: var(--good-soft); color: var(--good); border-color: var(--good-soft); }

/* ---------- сетка кейсов и решений ---------- */
.cardgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-3); }
/* Расстояние между карточками ряда держит gap сетки, как в .req: типовой
   отступ .panel + .panel сдвигал вторую и третью карточку вниз на 24px, и в
   растянутой строке они выходили ниже первой - заголовки не стояли на одной
   линии (замечание Петра Костина: блоки одной высоты, содержимое по верхнему
   краю). */
.cardgrid > .panel + .panel { margin-top: 0; }
/* Модификаторы вместо инлайновых grid-template-columns: инлайн-стиль сильнее
   медиа-запросов и на мобильных давал горизонтальный скролл. */
.cardgrid--2 { grid-template-columns: repeat(2, 1fr); }
/* Карусель карточек: в видимой части те же три в ряд, что в .cardgrid, а
   остальные листаются стрелками (замечание Петра Костина). Стрелки вынесены
   за ширину строки, как в карусели типов, поэтому обёртке нужен
   position: relative. */
.cardcar { position: relative; }
.cardcar__track {
  display: grid; grid-auto-flow: column;
  grid-auto-columns: calc((100% - 2 * var(--space-3)) / 3);
  gap: var(--space-3); overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none;
  /* поля под тень карточки: scroll-контейнер обрезает всё, что выходит за его
     край. Обратными margin возвращаем блоку прежние внешние отступы. Боковые
     поля - чтобы тень первой карточки не срезалась слева (замечание Петра
     Костина); scroll-padding держит снап на видимом краю карточки. */
  padding: 6px 10px 14px; margin: -6px -10px -14px;
  scroll-padding-inline: 10px;
}
/* Тень карточек в карусели на 30% тоньше базовой --shadow-card (и такая же
   доля у тени при наведении): в ряду широкое размытие заметно сильнее, чем в
   сетке, а боковых полей трека хватает, чтобы её не срезало. */
.cardcar__track .mcard { box-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 3px 10px rgba(16, 24, 40, .05); }
.cardcar__track .mcard:hover, .cardcar__track .mcard:focus-within { box-shadow: 0 4px 17px rgba(16, 24, 40, .10); }
.cardcar__track::-webkit-scrollbar { display: none; }
.cardcar__track:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* min-width:0 - по той же причине, что у .cardgrid > *: иначе карточка не уже
   своего содержимого. Карточки правее видимой части иначе остались бы скрытыми
   reveal-эффектом до первой прокрутки. */
.cardcar__track > * { scroll-snap-align: start; min-width: 0; }
.cardcar__track [data-rv] { opacity: 1 !important; transform: none !important; }
/* Карусель карточек моделей: в видимой части четыре в ряд, как в выдаче
   каталога (.prodgrid--4, замечание Петра Костина 04.09). Селектор из двух
   классов сильнее одиночного .cardcar__track, поэтому число колонок на узких
   экранах переопределяется в адаптиве отдельными правилами - иначе базовое
   правило победило бы медиазапросы. */
.cardcar--4 .cardcar__track { grid-auto-columns: calc((100% - 3 * var(--space-3)) / 4); }
/* Карусель плиток: шесть в видимой части, ширина колонки та же, что у ряда
   фильтров отрасли (.typegrid) - по ней раздел «Кто нам доверяет» на странице
   о компании повторяет блоки фильтров каталога ИИ-решений (замечание Петра
   Костина). Плитки там не фильтруют, поэтому у них обычный курсор. */
.cardcar--6 .cardcar__track { grid-auto-columns: calc((100% - 5 * var(--space-3)) / 6); }
.cardcar--6 .typecard { cursor: default; }
/* Карточка-переход в ряду плиток: поля меньше базовых, иначе в узкой колонке
   текст занимает всю высоту блока. */
.morecard--tile { padding: var(--space-4) var(--space-3); gap: 10px; }
.morecard--tile .morecard__t { font-size: 16px; }
/* Карточка-переход в полный каталог: последняя в рядах главной (замечание
   Петра Костина). Высота и радиус - от соседних карточек ряда, поэтому
   размеров своих не задаёт; пунктирная рамка вместо тени отличает её от
   карточек каталога и не обещает товара. */
.morecard {
  display: flex; flex-direction: column; justify-content: center; gap: var(--space-2);
  text-align: center; padding: var(--space-5) var(--space-4);
  background: var(--white); border: 1px dashed var(--border); border-radius: var(--radius);
  text-decoration: none; color: inherit;
  transition: border-color .15s ease, color .15s ease;
}
.morecard:hover { border-color: var(--accent); color: var(--accent); }
.morecard__t { font: 600 18px/1.35 var(--font-display); letter-spacing: -0.01em; }
.morecard__d { font-size: 13px; line-height: 1.5; color: var(--text-2); }
.morecard__go { font: 600 14px/1 var(--font-body); color: var(--accent); }
.prodgrid--3 { grid-template-columns: repeat(3, 1fr); }
/* Витрина каталога и выдача поиска стоят по четыре карточки в ряд (замечание
   Петра Костина): плотнее, как в поисковой выдаче. Ниже 1100px колонок
   становится три, ниже 780px - две, на телефоне - одна. */
.prodgrid--4 { grid-template-columns: repeat(4, 1fr); }
.mcard { background: var(--white); border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-card); display: flex; flex-direction: column; text-decoration: none; color: inherit; }
.mcard__media { position: relative; aspect-ratio: 16/9; overflow: hidden; background: var(--surface-2); }
.mcard__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mcard__tag { position: absolute; top: 12px; left: 12px; font: 600 11px/1 var(--font-body); background: rgba(32,32,32,.9); color: #F2F2F1; padding: 6px 10px; border-radius: var(--pill); }
.mcard__body { padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); flex: 1; }
.mcard__t { font: 600 18px/1.35 var(--font-display); letter-spacing: -0.01em; margin: 0; }
/* Бренд над названием карточки решения - тот же вид, что у .prod__brand в
   карточке робота (замечание Петра Костина). */
.mcard__brand { font: 600 11px/1 var(--font-body); color: var(--text-3); text-transform: uppercase; letter-spacing: .06em; }
.mcard__d { font-size: 13px; color: var(--text-2); line-height: 1.5; margin: 0; }
/* Фиксированная высота нужна ТОЛЬКО внутри карточки-ссылки: там метрики и эффект
   соседних карточек ряда встают на одну линию (баг ревью 08-07). Те же классы
   переиспользованы как обычные абзацы в панелях консалтинга и сервисов - там
   клэмп срезал содержательный текст даже на десктопе (MOBILE-001). */
.mcard .mcard__t {
  min-height: calc(2 * 1.35em); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.mcard .mcard__d {
  min-height: calc(3 * 1.5em); display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
/* Карточка решения: названия тут в одну строку, а запас высоты под вторую
   оставлял пустоту между названием и серым описанием (замечание Петра
   Костина). Снимаем только запас, клэмп на две строки остаётся - низ карточки
   всё равно выравнивает margin-top:auto у плашки эффекта. */
.mcard:has(.mcard__metrics--effect) .mcard__t { min-height: 0; }
/* Карточка решения в каталоге: название встаёт в одну строку, и запас высоты
   под вторую оставлял пустоту между названием и серым текстом (замечание
   Петра Костина). Запас снимаем. Добор высоты нижним отступом тела убран
   (замечание Петра Костина): под кнопкой «Подробнее» оставалось вдвое больше
   воздуха, чем в карточке кейса. Теперь низ такой же - обычный padding тела
   (--space-4, 24px), как у .ngm-case. В две колонки и на телефоне название
   переносится, там запас нужен - правка только для широкого экрана. */
@media (min-width: 981px) {
  .mcard--sol .mcard__t { min-height: 0; }
}
/* Карточка кейса: то же самое, что у карточки решения выше (замечание Петра
   Костина). Короткие названия вроде «Автономный уход за территорией» встают в
   одну строку, а запас под вторую оставлял пустоту между названием и серым
   описанием. Запас снимаем, клэмп на две строки остаётся. Нижним отступом тела
   высоту здесь не добираем (в отличие от решений): названия кейсов разной
   длины, и лишний отступ поднял бы карточки с двухстрочным названием - высоту
   ряда и так держит самая высокая карточка, поэтому вверх едут только
   описание, цена и кнопка. На узких экранах название переносится, там запас
   нужен - правка только для широкого экрана. */
@media (min-width: 981px) {
  .ngm-case .mcard__t { min-height: 0; }
}
.mcard__metrics { display: flex; gap: var(--space-4); margin-top: auto; padding-top: var(--space-3); border-top: 1px solid var(--border); }
.mcard__mv { font: 700 18px/1.1 var(--font-mono); color: var(--good); display: block; }
.mcard__mk { font-size: 11px; color: var(--text-2); line-height: 1.3; display: block; margin-top: 3px; }
.mcard__link { font: 400 13px/1 var(--font-mono); color: var(--accent); }
/* Эффект на карточке решения: зелёная надпись в одну строку на светло-зелёной
   подложке (просьба заказчика). Ширину задаёт сам текст, поэтому плашка
   вынесена из сетки метрик - там она сидела в трети карточки и переносилась. */
.mcard__metrics--effect { display: block; border-top: 0; padding-top: var(--space-2); }
.mcard__metrics--effect .mcard__mv {
  display: inline-block; max-width: 100%; font-size: var(--fs-4);
  background: var(--good-soft); padding: 6px 12px; border-radius: var(--pill);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Карточка релиза: в зелёной плашке остаётся только цифра, подпись стоит
   рядом зелёным текстом без подложки (замечание Петра Костина). */
.mcard__effrow { display: flex; align-items: baseline; gap: 8px; }
.mcard__effrow .mcard__mv { flex: 0 0 auto; }
.mcard__ml { font: 600 13px/1.3 var(--font-display); color: var(--good); }
/* Цена на карточке решения и кейса - ровно как .prod__price в карточке робота
   (замечание Петра Костина): тот же кегль, тот же отступ от текста выше
   (padding-top: --space-2 поверх общего gap тела) и то же прижатие к низу.
   Раньше цена стояла без margin-top: auto, потому что низ карточки держала
   плашка эффекта над ней; плашку убрали по просьбе заказчика, и цена с кнопкой
   «Подробнее» всплывали сразу под описанием, разъезжаясь по ряду. */
.mcard__price { margin: auto 0 0; padding-top: var(--space-2);
  font: 700 18px/1.2 var(--font-display); letter-spacing: -0.01em;
  color: var(--accent); }
/* Платёж по подписке под ценой решения - той же мелкой строкой, что в карточке
   робота (.prod__price small). */
.mcard__price small { display: block; font: 400 12px/1.4 var(--font-body);
  color: var(--text-2); margin-top: 3px; }
/* Кнопка «Подробнее» внизу карточки решения. Сама карточка - ссылка, кнопка
   внутри неё span, поэтому подсвечиваем её при наведении на всю карточку.
   Кнопка синяя, как «В калькулятор» в карточке робота (замечание Петра
   Костина): при наведении так же темнеет, плавность берётся из .btn.
   Отступ от цены до кнопки - как в карточке кейса (замечание Петра Костина):
   там кнопка лежит в .ngm-case__acts с margin-top: var(--space-3), и вместе с
   общим gap тела карточки (--space-2) это те же 24px. */
.mcard__more { align-self: flex-start; margin-top: var(--space-3); padding: 9px 16px; font-size: 13px; }
.mcard:hover .mcard__more, .mcard:focus-within .mcard__more {
  background: var(--accent-dark); border-color: var(--accent-dark); }
/* Наведение подсвечивает карточку тенью - тот же приём, что у карточки робота
   (.prod:hover). У кейсов это уже сделано в wow.css, теперь и у решений. */
.mcard { transition: box-shadow .15s ease; }
.mcard:hover, .mcard:focus-within { box-shadow: var(--shadow-lift); }
/* Вся карточка решения кликается растянутой ссылкой названия: сама карточка
   перестала быть одним <a>, когда на медиа встало сердечко «в избранное»
   (замечание Петра Костина) - интерактив внутри ссылки браузер не примет.
   Приём и опора те же, что у кейса (.ngm-case__link) и модели (.prod__name a). */
.mcard--sol { position: relative; }
.mcard__tlink { color: inherit; text-decoration: none; }
.mcard__tlink::after { content: ''; position: absolute; inset: 0; }
.mcard__tlink:focus-visible { outline: none; }
.mcard__tlink:focus-visible::after {
  outline: 2px solid var(--accent); outline-offset: -3px; border-radius: var(--radius); }
/* Сердечко «в избранное» - единый вид во всех каталогах (роботы, решения,
   кейсы) и на всех страницах (замечание Петра Костина): неактивное - белая
   заливка с тёмно-серой обводкой по контуру, активное - красная заливка с
   тёмно-красной обводкой. Круглой подложки нет ни у одной карточки, поэтому
   сердечко везде одинаковое; чтобы белое читалось на любом кадре, под ним
   мягкая тень. Активное состояние берётся из aria-pressed, его ставит
   wireShopButtons (js/market.js). z-index 2 - выше растяжки ссылки названия,
   иначе клик уходил бы на карточку. */
.mcard__fav, .prod__fav { position: absolute; right: 10px; z-index: 2; width: 34px; height: 34px;
  padding: 0; border: 0; background: transparent; display: inline-flex; align-items: center;
  justify-content: center; color: #3E4A5C; cursor: pointer;
  filter: drop-shadow(0 1px 3px rgba(16, 24, 40, .35));
  transition: color .15s ease, transform .15s ease; }
.mcard__fav { top: 10px; }
.mcard__fav svg, .prod__fav svg { width: 22px; height: 22px; fill: #FFFFFF; stroke: currentColor; }
.mcard__fav:hover, .prod__fav:hover { transform: scale(1.08); }
.mcard__fav[aria-pressed="true"], .prod__fav[aria-pressed="true"] { color: #8C1024; }
.mcard__fav[aria-pressed="true"] svg, .prod__fav[aria-pressed="true"] svg { fill: #E0245E; }
.mcard__fav:focus-visible, .prod__fav:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 50%; }
/* Сердечко в кнопке с подписью «В избранное» на страницах модели и решения -
   те же цвета, что у сердечка на карточках. */
.fav-ic { color: #3E4A5C; }
[aria-pressed="true"] .fav-ic { color: #E0245E; }

/* ---------- путь пользователя (паттерн NextGen) ---------- */
.journey { display: grid; grid-template-columns: repeat(5, 1fr); gap: var(--space-2); align-items: start; }
.jstep { text-align: center; position: relative; padding: 0 var(--space-2); }
.jstep__i { width: 46px; height: 46px; margin: 0 auto var(--space-2); border-radius: var(--radius-s); background: var(--white); display: grid; place-items: center; color: var(--text-2); box-shadow: var(--shadow-card); }
.jstep__i svg { width: 24px; height: 24px; }
.jstep__t { font: 600 13px/1.35 var(--font-display); margin: 0; }
.jstep__d { font-size: 12px; color: var(--text-2); margin: 5px 0 0; line-height: 1.4; }
.jstep:not(:last-child)::after {
  content: ''; position: absolute; top: 22px; right: -6px; width: 12px; height: 2px; background: var(--accent); opacity: .5;
}

/* ---------- совместимость и доверие ---------- */
.stackrow { display: flex; gap: var(--space-2); flex-wrap: wrap; }
/* Плашка метода - ссылка в раздел «Для разработчиков» (замечание Петра
   Костина). Вид прежний, под курсором меняется тон и рамка: подчёркивания
   у таких плашек на сайте нет. */
.stackrow span, .stackrow__i { font: 500 13px/1 var(--font-body); background: var(--white); border: 1px solid var(--border); border-radius: var(--radius-s); padding: 10px 14px; color: var(--text-2); }
.stackrow__i { text-decoration: none; display: inline-block; transition: color 0.15s, border-color 0.15s; }
.stackrow__i:hover, .stackrow__i:focus-visible { color: var(--text); border-color: var(--text-2); }

/* ---------- раздел «Для разработчиков» ---------- */
.devpanel { scroll-margin-top: 84px; }   /* якорь не уезжает под липкую шапку */
.devfacts { list-style: none; margin: var(--space-3) 0 0; padding: 0; display: grid; gap: var(--space-2); }
/* подпись слева, пояснение справа: строки длинные, правый край .speclist тут не годится */
.devfacts li { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: var(--space-3); border-top: 1px solid var(--border); padding-top: var(--space-2); font-size: 14px; line-height: 1.55; color: var(--text-2); }
.devfacts b { font: 600 14px/1.55 var(--font-body); color: var(--text); }
@media (max-width: 700px) { .devfacts li { grid-template-columns: minmax(0, 1fr); gap: 4px; } }

/* ---------- CTA-полоса с фото ---------- */
.ctabar { display: grid; grid-template-columns: 1fr 220px; gap: var(--space-5); align-items: center; background: var(--ink); color: var(--text); border-radius: var(--radius); overflow: hidden; padding: var(--space-5); }
.ctabar h2 { color: #F2F2F1; margin-bottom: var(--space-2); max-width: 22ch; }
.ctabar p { color: #B9BDB9; margin: 0 0 var(--space-4); max-width: 52ch; }
.ctabar__media { align-self: center; }
.ctabar__media { background: #fff; border-radius: var(--radius-s); overflow: hidden; }
.ctabar__media img { display: block; width: 100%; aspect-ratio: 4/3; object-fit: contain; background: #fff; }
/* полоса без картинки: текст занимает всю ширину, пустой колонки не остаётся */
.ctabar:not(:has(.ctabar__media)) { grid-template-columns: 1fr; }

/* ---------- адаптив ---------- */
@media (max-width: 1100px) {
  /* в карусели меняется ширина плитки, а не число колонок: строка одна */
  .typegrid { grid-auto-columns: calc((100% - 3 * var(--space-3)) / 4); }
  .cardgrid, .cardgrid--2 { grid-template-columns: repeat(2, 1fr); }
  .cardcar__track { grid-auto-columns: calc((100% - var(--space-3)) / 2); }
  .cardcar--4 .cardcar__track { grid-auto-columns: calc((100% - 2 * var(--space-3)) / 3); }
  /* у ряда плиток меняется ширина колонки так же, как у .typegrid */
  .cardcar--6 .cardcar__track { grid-auto-columns: calc((100% - 3 * var(--space-3)) / 4); }
  .prodgrid--3 { grid-template-columns: repeat(2, 1fr); }
  .prodgrid--4 { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 980px) {
  /* .market и .filters здесь больше не переопределяются: одна колонка
     и обычный поток теперь заданы по умолчанию. */
  .page-head__grid { grid-template-columns: 1fr; }
  .detail { grid-template-columns: 1fr; }
  .journey { grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }
  .jstep:not(:last-child)::after { display: none; }
  .statrow { grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }
}
@media (max-width: 780px) {
  .prodgrid { grid-template-columns: repeat(2, 1fr); }
  .typegrid { grid-auto-columns: calc((100% - var(--space-3)) / 2); }
  .cardgrid, .cardgrid--2 { grid-template-columns: repeat(2, 1fr); }
  .prodgrid--3, .prodgrid--4 { grid-template-columns: repeat(2, 1fr); }
  .cardcar--4 .cardcar__track { grid-auto-columns: calc((100% - var(--space-3)) / 2); }
  .cardcar--6 .cardcar__track { grid-auto-columns: calc((100% - var(--space-3)) / 2); }
  .ctabar { grid-template-columns: 1fr; padding: var(--space-4); }
  .ctabar__media { display: none; }
}
@media (max-width: 640px) {
  .mc-fields { grid-template-columns: repeat(2, 1fr); }
  .mc-out { grid-template-columns: 1fr; gap: var(--space-2); }
  .speclist, .prod__specs { grid-template-columns: 1fr; }
  .journey { grid-template-columns: 1fr; }
  .statrow { grid-template-columns: 1fr; }
  .detail__price { font-size: 26px; }
}

/* ---------- лендинг: заголовки секций и вспомогательное ---------- */
.sec-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; margin-bottom: var(--space-3); }
.sec-head h2 { margin-bottom: 0; }
.sec-head__link { font: 600 14px/1 var(--font-body); color: var(--accent); text-decoration: none; white-space: nowrap; padding: 8px 0; }
.sec-head__link:hover { text-decoration: underline; }
/* Кликабельное название блока: кегль и цвет как у обычного заголовка. При
   наведении меняется только тон надписи (--text вместо него --text-2), без
   подчёркивания - разработчик отклонил его как слишком резкое. Фокус
   с клавиатуры остаётся видимым рамкой акцента. */
.sec-head__h2link { color: inherit; text-decoration: none; transition: color .15s ease; }
.sec-head__h2link:hover { color: var(--text-2); }
.sec-head__h2link:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: var(--r-xs); }
@media (prefers-reduced-motion: reduce) { .sec-head__h2link { transition: none; } }

.hero__photo { align-self: center; }
.chip--link { text-decoration: none; display: inline-block; transition: background .15s ease, color .15s ease; }
.chip--link:hover { background: var(--ink); color: #F2F2F1; border-color: var(--ink); }
/* Светлый вариант чипа-ссылки (правка разработчика): при наведении и нажатии
   кнопка не заливается тёмным, а показывает кликабельность тоном рамки и
   текста - как чипы-табы и выбранная плитка типа в каталоге. */
.chip--link.chip--soft:hover,
.chip--link.chip--soft:active { background: var(--surface); color: var(--text); border-color: var(--ink); }

.prod__media-link { display: block; position: relative; text-decoration: none; }
/* Название не подчёркивается ни в покое, ни при наведении (замечание Петра
   Костина): растяжка ссылки накрывает всю карточку, и подчёркивание срабатывало
   от курсора в любом её месте. */
.prod__name a, .prod__name a:hover { text-decoration: none; color: inherit; }
/* Вся карточка модели - ссылка: ссылка названия растянута на карточку, поэтому
   курсор в любом свободном месте показывает ссылку, а клик открывает модель
   (замечание Петра Костина). Приём тот же, что на карточке кейса
   (.ngm-case__link в wow.css); опора - position: relative у .prod.
   Наведение подсвечивает карточку тенью: растяжка - часть самой ссылки,
   поэтому :hover срабатывает на ней, а над кнопками - нет.
   Пэкшот, кнопки и калькулятор лежат ПОВЕРХ растяжки и работают как раньше;
   сердечко .prod__fav уже стоит на z-index 2. */
.prod { transition: box-shadow .15s ease; }
.prod:hover, .prod:focus-within { box-shadow: var(--shadow-lift); }
.prod__name a::after { content: ''; position: absolute; inset: 0; z-index: 1; }
.prod__name a:focus-visible { outline: none; }
.prod__name a:focus-visible::after {
  outline: 2px solid var(--accent); outline-offset: -3px; border-radius: var(--radius); }
.prod__media-link, .prod__actions, .prod__calc { position: relative; z-index: 2; }
.market__empty { color: var(--text-2); font-size: 15px; padding: var(--space-5) 0; }
.footer__credits { font: 400 12px/1.6 var(--font-body); color: var(--text-3); margin: var(--space-3) 0 0; max-width: 90ch; }

/* ---------- предметные рендеры на белом (пэкшоты каталога) ---------- */
.prod__media--art, .typecard__ph--art, .detail__media--art {
  background: #fff; display: grid; place-items: center; overflow: hidden;
}
.prod__media--art { aspect-ratio: 4/3; padding: var(--space-2); }
.prod__media--art svg, .typecard__ph--art svg, .detail__media--art svg { display: block; width: 100%; height: auto; }
/* Высоту кадра задаёт .typecard__ph (104px), здесь остаётся только поле. */
.typecard__ph--art { padding: var(--space-2); }
/* Рисунок в плитке (типы без пэкшота) вписывается в невысокий кадр по высоте,
   иначе широкий 4:3 обрезался бы сверху и снизу. */
.typecard__ph--art svg { width: auto; height: 100%; max-width: 100%; }
.detail__media--art { aspect-ratio: 4/3; padding: var(--space-4); }
.detail__media--art img { aspect-ratio: auto; width: 100%; height: 100%; object-fit: contain; padding: 0; }
.detail__photo { margin: var(--space-3) 0 0; }
.detail__photo img { display: block; width: 100%; border-radius: var(--radius); aspect-ratio: 4/3; object-fit: cover; }
.detail__photo figcaption { font-size: 12px; color: var(--text-3); margin-top: 8px; }

/* ---------- подвал маркетплейса ---------- */
.foot__grid { display: grid; grid-template-columns: 1.4fr repeat(3, 1fr); gap: var(--space-5); padding-bottom: var(--space-5); }
.foot__brand .logo { margin-bottom: var(--space-3); display: inline-flex; }
.foot__note { color: var(--text-2); font-size: 14px; max-width: 34ch; margin: 0 0 var(--space-3); }
.foot__phone { display: block; font-weight: 700; font-size: 18px; text-decoration: none; color: var(--text); }
.foot__mail { display: inline-block; margin-top: 6px; color: var(--accent); text-decoration: none; font-size: 14px; }
.foot__mail:hover { text-decoration: underline; }
.foot__col { display: flex; flex-direction: column; gap: 9px; }
.foot__t { font: 600 12px/1 var(--font-body); letter-spacing: .07em; text-transform: uppercase; color: var(--text-3); margin: 0 0 4px; }
.foot__col a { color: var(--text-2); text-decoration: none; font-size: 14px; }
.foot__col a:hover { color: var(--accent); }
.foot__bottom { display: flex; gap: var(--space-4); align-items: baseline; flex-wrap: wrap; border-top: 1px solid var(--border); padding-top: var(--space-4); }
.foot__bottom .footer__note--right { max-width: 60ch; text-align: right; font-size: 12px; }
@media (max-width: 980px) { .foot__grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px) { .foot__grid { grid-template-columns: 1fr; gap: var(--space-4); }
  .foot__bottom .footer__note--right { text-align: left; margin-left: 0; } }

/* Планшет: карточки стоят в два столбца, выравнивание по строке нужно, но
   текста в узкой колонке помещается меньше - даём клэмпу больше строк,
   иначе описание кейса и решения обрывается (MOBILE-001). */
@media (min-width: 641px) and (max-width: 980px) {
  .mcard .mcard__t { min-height: calc(3 * 1.35em); -webkit-line-clamp: 3; }
  .mcard .mcard__d { min-height: calc(5 * 1.5em); -webkit-line-clamp: 5; }
  .prod__tag { min-height: calc(3 * 1.45em); -webkit-line-clamp: 3; }
  .prod__name { -webkit-line-clamp: 3; }
  /* в узкой колонке плашке эффекта не хватало ширины на одну строку */
  .mcard__metrics--effect .mcard__mv { font-size: var(--fs-3); padding: 5px 10px; }
}

/* одна колонка — только на телефонах */
@media (max-width: 640px) {
  .prodgrid, .prodgrid--3, .prodgrid--4, .cardgrid, .cardgrid--2 { grid-template-columns: 1fr; }
  /* на телефоне видно полторы плитки: край следующей подсказывает, что ряд листается */
  .typegrid { grid-auto-columns: calc((100% - var(--space-3)) / 1.6); }
  /* стрелок на телефоне нет, ряд листается свайпом - край второй карточки
     подсказывает, что за ней есть ещё */
  .cardcar__track, .cardcar--4 .cardcar__track { grid-auto-columns: calc((100% - var(--space-3)) / 1.15); }
  /* ряд плиток на телефоне листается, как .typegrid: видно полторы плитки */
  .cardcar--6 .cardcar__track { grid-auto-columns: calc((100% - var(--space-3)) / 1.6); }
  /* Клэмп существует, чтобы карточки в РЯДУ вставали на одну линию. В одной
     колонке выравнивать нечего, а текст решения и кейса терялся (MOBILE-001):
     на телефоне показываем его целиком. */
  .mcard .mcard__t, .mcard .mcard__d, .prod__name, .prod__tag, .prod__src {
    display: block; -webkit-line-clamp: none; overflow: visible; min-height: 0;
  }
  /* новость: на телефоне карточка и так уже 530px, поэтому берёт всю ширину
     экрана, а кадр с каруселью делят её в той же пропорции 4 : 1 */
  .nrow { gap: var(--space-2); }
}

/* Плотная вёрстка узких телефонов: паддинги и иконки, из-за которых
   документ уезжал вправо (MOBILE-001). */
@media (max-width: 400px) {
  .statrow { padding: var(--space-3); gap: var(--space-2); }
  .statrow__i { width: 36px; height: 36px; }
  .statrow__i svg { width: 20px; height: 20px; }
  /* плитки цифр на первом баннере: иконка мельче, как у плиток отраслей на
     узких экранах (.story__ind svg), - иначе она съедает ширину под подпись */
  .hero .statrow__i, .hero .statrow__i svg { width: 40px; height: 40px; }
  .statrow__v { font-size: 22px; }
  /* подписи-метки на hero позиционируются в процентах и вылезали за экран */
  .hero-mark { display: none; }
}

/* Заголовки секций по левому краю (правка заказчика 08-09, пины 60-62).
   Оверрайд живёт здесь: market.css грузится после site.css, и прежнее
   центрирование отсюда перебивало левое выравнивание из site.css.
   Ссылка «весь каталог →» остаётся справа, поэтому шапка секции - строка. */
.sec-head { flex-direction: row; align-items: baseline; justify-content: space-between;
  text-align: left; gap: var(--space-3); flex-wrap: wrap; }
.sec-head > div { text-align: left; }
.sec-head h2 { margin-left: 0; margin-right: 0; }
/* CTA-плашка опроса тоже по левому краю: единый вертикальный ритм страницы */
.ctabar > div:first-child { text-align: left; }
.ctabar h2, .ctabar p { margin-left: 0; margin-right: 0; }

/* ---------- сравнение с аналогами (деталь модели) ---------- */
.cmpwrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.cmp { width: 100%; min-width: 640px; border-collapse: collapse; font-size: 14px; }
.cmp th, .cmp td { padding: 12px 16px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top; }
.cmp thead th { font: 600 13px/1.3 var(--font-body); letter-spacing: .04em; text-transform: uppercase; color: var(--text-3); }
.cmp thead th a { color: var(--text); text-decoration: none; display: block; text-transform: none; letter-spacing: 0; font-size: 15px; }
.cmp thead th a:hover { color: var(--accent); }
.cmp tbody th { font-weight: 500; color: var(--text-2); white-space: nowrap; }
.cmp tbody tr:last-child th, .cmp tbody tr:last-child td { border-bottom: 0; }
.cmp .cmp__cur { background: color-mix(in srgb, var(--accent) 7%, var(--surface)); }
.cmp thead .cmp__cur { box-shadow: inset 0 3px 0 var(--accent); }
.cmp__badge { display: inline-block; margin-top: 6px; font: 600 11px/1 var(--font-body); letter-spacing: .05em; text-transform: uppercase; color: var(--accent); }

/* строка эффекта в карточке кейса */
.mcard__eff { margin: var(--space-3) 0 0; padding-top: var(--space-3); border-top: 1px dashed var(--border); font-size: 14px; color: var(--text-2); }
.mcard__eff b { color: var(--text); font-size: 15px; }
.mcard__eff small { display: block; margin-top: 2px; font-size: 12px; color: var(--text-3); }

/* табы-фильтры кейсов */
.chip--tab { cursor: pointer; transition: background .15s ease, color .15s ease, border-color .15s ease; }
.chip--tab:hover:not(.chip--on) { border-color: var(--ink); color: var(--text); }

/* сердечко и корзина на карточке */
/* Вид сердечка общий для всех карточек и задан выше (.mcard__fav, .prod__fav),
   здесь остаётся только положение на карточке модели. Отступ сверху такой же,
   как у карточек кейсов и ИИ-решений (10px): бейдж с картинки убран, опускать
   сердечко ниже уголка больше не нужно (замечание Петра Костина). */
.prod__fav { top: 10px; }
.prod { position: relative; }
/* мини-счётчик единиц: встаёт на место кнопки, когда позиция уже в корзине */
.prod__cart[hidden], .prod__qty[hidden] { display: none; } /* inline-flex иначе перебивает hidden */
.prod__qty { display: inline-flex; align-items: center; gap: 4px; min-height: 38px; padding: 0 6px; border: 1px solid var(--border); border-radius: var(--radius-s); background: var(--surface); }
.prod__qty-b { width: 26px; height: 26px; border: 1px solid var(--border); background: var(--surface); border-radius: var(--r-xs); cursor: pointer; font-size: 15px; line-height: 1; color: var(--text-2); }
.prod__qty-b:hover { border-color: var(--accent); color: var(--accent); }
.prod__qty-n { font-style: normal; min-width: 26px; text-align: center; font: 600 14px/1 var(--font-body); color: var(--text); }

/* ---------- страница новостей: лента + сайдбар ---------- */
/* сайдбар слева от ленты (правка заказчика): порядок в разметке не меняем,
   переставляем колонки сеткой - на узких экранах лента снова идёт первой */
/* Лента выровнена по строке поиска в шапке (замечание Петра Костина): левый
   край поля - ширина плашки лого 236px минус радиус 10px, на который поле на
   неё заходит (site.css, .topbar__search), то есть 226px от края .wrap; правый
   край держат иконки шапки (3x51 + 2x6 = 165px) и зазор колонки 24px, то есть
   189px от правого края .wrap. Отсюда колонка сайдбара 226 - 24 = 202px, а
   лента - остаток за вычетом 202 + 24 + 189 = 415px. */
.newsgrid { display: grid; grid-template-columns: 202px minmax(0, calc(100% - 415px)); gap: var(--space-4); align-items: start; }
/* левая колонка - один блок .newscol: сверху фильтры, под ними панель подписки,
   лента справа. Раньше это были два отдельных элемента сетки в двух строках,
   но прилипать при прокрутке они должны вместе, поэтому теперь у них общая
   обёртка, а строка у сетки одна. */
.newsgrid > .newsfeed { grid-column: 2; }
.newsgrid > .newscol { grid-column: 1; display: flex; flex-direction: column; gap: var(--space-4); }
/* Колонка ограничена по высоте (правило ниже), поэтому её элементы нельзя
   давать сжимать: у ряда фильтров есть min-height 32px, и при сжатии кнопки
   вылезали за свой блок поверх панели «Следите за новостями». */
.newscol > * { min-width: 0; flex: none; }
/* Прилипание левой колонки (замечание Петра Костина): фиксируется у нижнего
   края липкой шапки, отступ до неё - как между карточками ленты (--space-3).
   129px - высота шапки: 25px верхнего поля + 51px строки лого и поиска + 6px
   между строками + 36px строки разделов + 10px нижнего поля + 1px границы.
   Колонка выше экрана, поэтому её высота ограничена видимой частью, иначе
   низ панели с кнопкой «Подписаться» остался бы за краем экрана. */
.newsgrid > .newscol { position: sticky; top: calc(129px + var(--space-3));
  max-height: calc(100vh - 129px - var(--space-3) * 2); overflow-y: auto; scrollbar-width: thin; }
/* каждая новость - отдельная карточка (правка заказчика), поэтому у ленты
   свой промежуток между блоками вместо общей панели */
.newsfeed { display: flex; flex-direction: column; gap: var(--space-3); }
/* страница новости (06.09): строка 60-75 символов, вывод для покупателя выделен, кнопки в ряд */
.news-article { padding: var(--space-5); max-width: 760px; }
.news-article p { font-size: 17px; line-height: 1.6; max-width: 68ch; }
.news-article .section__lead { font-size: 19px; }
.news-article--takeaway > p:last-of-type { border-left: 3px solid var(--accent); padding: 8px 14px; background: var(--accent-soft); border-radius: 0 var(--radius-s) var(--radius-s) 0; }
.news-article__foot { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: var(--space-4); }
.news-article__foot .hero__actions { margin-top: 0 !important; }
.news-article__foot .btn { min-height: 44px; }
/* карточка новости: своя рамка и тень, как у .panel.
   Карточка - колонка: тема и дата стоят над изображением (замечание Петра
   Костина), сама карточка никуда не ведёт и не нажимается. */
/* Отступ от текста до нижнего края карточки увеличен вдвое (замечание Петра
   Костина): было 16px (--space-3), стало 32px; остальные поля прежние. */
/* Карточка не шире главного изображения (уточнение разработчика): 496px кадра
   плюс поля 16px с двух сторон и рамка - 530px. Кадр и текст занимают всю
   ширину карточки, поэтому правый край блока совпадает с краем изображения. */
/* отступ от строки «Смотреть в источнике» до нижнего края карточки убран,
   оставлен небольшой: 32px -> 8px (замечание Петра Костина) */
.nrow { position: relative; display: flex; flex-direction: column; gap: var(--space-3); max-width: 530px; padding: var(--space-3); padding-bottom: var(--space-2); border-radius: var(--radius); min-width: 0; background: var(--white); border: 1px solid var(--border); box-shadow: var(--shadow-card); }
.nrow > div { min-width: 0; }
/* Подсветка рамки при наведении убрана по замечанию Петра Костина. */
/* Быстрые фильтры ленты (замечание Петра Костина): кнопки-пилюли в левой
   колонке - те же .ssfd__btn и та же раскладка .filters__row, что в фильтрах
   каталога, поэтому здесь остаётся только выбранное состояние (в каталоге
   кнопка подсвечивается раскрытым списком). Отступы держит сетка .newsgrid. */
.newsfilter .ssfd__btn[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
/* Новое замечание Петра Костина: ряд фильтров и кнопки подписки стоят в одной
   панели - пилюли сверху, под ними просвет до блока соцсетей. */
.newsside .panel > .newsfilter { margin-bottom: var(--space-3); }
/* если категория в ленте одна, news.js прячет ряд: display: flex у .filters__row
   перебивает hidden, поэтому убираем его явно - иначе в панели остаётся пустой просвет */
.newsside .panel > .newsfilter[hidden] { display: none; }
/* Отфильтрованная карточка не рисуется: display: flex перебивает hidden. */
.nrow[hidden] { display: none; }
/* Ссылки-подложки .nrow__link больше нет: карточка новости не кликабельна и
   не ведёт на отдельную страницу (замечание Петра Костина). Нажимается только
   изображение - оно открывается просмотрщиком .nshow ниже. */
.nrow__media { display: flex; align-items: flex-start; gap: var(--space-2); min-width: 0; }
/* Вертикальная карусель других изображений справа от кадра (замечание Петра
   Костина): появляется, только если у новости их больше одного. Ширина полосы -
   25% ширины главного кадра: кадр и карусель делят строку как 4 : 1 с просветом,
   высота полосы равна высоте кадра (ширина миниатюры х 2,5), лишние миниатюры
   прокручиваются внутри. */
.nrow__thumbs { flex: 0 0 calc((100% - var(--space-2)) / 5); display: flex; flex-direction: column; gap: 8px; aspect-ratio: 1 / 2.5; overflow-y: auto; scroll-snap-type: y mandatory; }
.nrow__thumb { flex: none; width: 100%; aspect-ratio: 16/10; padding: 0; overflow: hidden; border: 1px solid var(--border); border-radius: var(--r-xs); background: #fff; cursor: pointer; scroll-snap-align: start; }
.nrow__thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.nrow__thumb[aria-current="true"] { border-color: var(--accent); }
/* курсор как у ссылки, а не лупа (замечание Петра Костина) */
.nrow__shot { flex: 1 1 auto; min-width: 0; display: block; padding: 0; border: 0; background: none; cursor: pointer; }
.nrow__shot img { display: block; width: 100%; height: auto; aspect-ratio: 16/10; object-fit: cover; border-radius: var(--radius-s); background: #fff; border: 1px solid var(--border); }
/* Тема, дата и текст новости идут во всю ширину карточки - то есть ровно по
   краям изображения (уточнение разработчика). */
.nrow__b { min-width: 0; display: flex; flex-direction: column; gap: 6px; justify-content: center; }
.nrow__meta { display: flex; align-items: center; gap: 6px; margin: 0; font-size: 12px; color: var(--text-3); }
/* просвет перед датой сокращён вдвое (замечание Петра Костина): было 12px
   просвета строки и 8px отступа у самой даты, стало 6px и 4px */
.nrow__meta time { margin-left: var(--space-1); }
.nrow__tag { color: var(--accent); background: var(--accent-soft); border-radius: var(--pill); padding: 4px 10px; font-weight: 600; font-size: 12px; }
/* Заголовок новости идёт во всю ширину блока и переносится на новую строку
   (замечание Петра Костина). Раньше его резало по 24ch с глобального h2 -
   при кегле 18px это 291px из 497px, а обрезка -webkit-line-clamp добавляла
   многоточие вместо переноса. Отступ снизу увеличен в 1,5 раза: 6px просвета
   .nrow__b + 3px margin = 9px. Второй проход (уточнение разработчика): ещё
   +50%, то есть 9px -> 13,5px, значит margin снизу 3px -> 7,5px. */
.nrow__b h2 { font-size: 18px; max-width: none; margin: 0 0 7.5px; line-height: 1.3; overflow-wrap: break-word; }
/* В карточке теперь полный текст новости (уточнение разработчика), поэтому
   обрезка абзацев по трём строкам снята: читается прямо в ленте. */
/* Весь текст новости - чёрный, как первый абзац (замечание Петра Костина):
   было --text-2 у всех абзацев кроме лида, стало --text у всех. Светло-серой
   остаётся только строка «Смотреть в источнике» - у неё свой цвет ниже.
   Просвет между абзацами увеличен в 1,5 раза: 6px gap .nrow__b + 6px margin =
   12px, стало 18px, то есть margin сверху 6px -> 12px. */
/* Кегль текста новости - 16px (замечание Петра Костина): было 14px у лида и
   всех абзацев. Строка «Смотреть в источнике» остаётся 12px - у неё свой
   селектор ниже, он специфичнее. */
.nrow__b p { margin: 0; color: var(--text); font-size: 16px; }
.nrow__b .nrow__full { margin-top: 12px; line-height: 1.55; }
/* «Смотреть в источнике» у нижнего края карточки (замечание Петра Костина):
   надпись слева, справа от неё - логотипы-ссылки на публикацию в Telegram и MAX. */
/* По уточнению разработчика надпись - светло-серая, менее насыщенная, чем
   основной серый --text-3, а кнопки каналов в 1,5 раза меньше: 28px -> 19px,
   значок 18px -> 12px. */
/* Второй проход (замечание Петра Костина): надпись на 15% мельче (13px -> 11px)
   и на 30% светлее (#98A2B3 -> #B7BECA), кнопки каналов ещё на 15% меньше
   (19px -> 16px, значок 12px -> 10px), просвет сверху увеличен до 24px. */
/* Третий проход (замечание Петра Костина). Кегль и цвет надписи до сих пор
   перебивало правило `.nrow__b p` (оно специфичнее), поэтому строка рисовалась
   как обычный абзац - 14px, --text-2, - и прошлые проходы на экране не видны.
   Ставим селектор в пару к `.nrow__b .nrow__lead` и считаем от того, что реально
   на экране: 14px -> 12px (-15%) и #5A6474 -> #9CA2AC (на 40% ближе к белому). */
.nrow__b .nrow__src { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-4); color: #9CA2AC; font-size: 12px; }
/* padding 4px -> 5px: знак MAX шире просвета кнопки и прижимался к рамке */
.nrow__srcl { display: inline-flex; align-items: center; justify-content: center; height: 16px; min-width: 16px; padding: 0 5px; border: 1px solid var(--border); border-radius: 4px; background: var(--white); color: var(--text-2); text-decoration: none; }
.nrow__srcl svg { display: block; width: 10px; height: 10px; }
.nrow__srcl:hover { border-color: var(--accent); color: var(--accent); }
/* у MAX своего файла логотипа в assets нет - ставим его словесный знак */
/* знак центрируется в кнопке: строка без лишней высоты, а хвостовой
   межбуквенный просвет снимается отрицательным полем справа */
.nrow__srcm { display: block; font-weight: 700; font-size: 7px; line-height: 1; letter-spacing: .04em; margin-right: -.04em; text-align: center; text-decoration: none; }
/* Просмотрщик изображений новости (замечание Петра Костина): страница за ним
   затемнена на 20%, кадр - не больше 2/3 экрана по ширине и по высоте,
   изображения листаются стрелками влево-вправо и клавишами. */
.nshow { position: fixed; inset: 0; z-index: 96; display: flex; align-items: center; justify-content: center; gap: var(--space-3); padding: var(--space-4); background: rgba(15, 27, 46, .2); }
.nshow[hidden] { display: none; }
.nshow__img { max-width: calc(100vw * 2 / 3); max-height: calc(100vh * 2 / 3); object-fit: contain; border-radius: var(--radius); background: #fff; box-shadow: var(--shadow-lift); }
.nshow__nav, .nshow__x { flex: none; width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--border); border-radius: 50%; background: var(--white); color: var(--text); font: 400 26px/1 var(--font-body); cursor: pointer; box-shadow: var(--shadow-card); }
.nshow__x { position: absolute; top: 18px; right: 22px; font-size: 18px; }
.nshow__nav[hidden] { display: none; }
/* прилипает теперь вся левая колонка целиком (.newscol выше), поэтому у самой
   панели подписки своего sticky нет */
.newsside { display: flex; flex-direction: column; gap: var(--space-4); }
/* колонка сайдбара сузилась до 202px, поэтому боковые поля панели меньше: с
   40px внутри оставалось 122px и кнопки категорий переносились по слогам */
.newsside .panel { padding-left: var(--space-3); padding-right: var(--space-3); }
.nchan { display: flex; align-items: center; gap: 12px; margin-top: var(--space-3); padding: 12px; border: 1px solid var(--border); border-radius: var(--radius-s); text-decoration: none; transition: border-color .15s ease; }
.nchan:hover { border-color: var(--accent); }
.nchan__i { flex: none; width: 42px; height: 42px; border-radius: 50%; background: #2AABEE; color: #fff; display: inline-flex; align-items: center; justify-content: center; }
.nchan__i svg { width: 22px; height: 22px; }
.nchan__b { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.nchan__b b { color: var(--text); font-size: 14px; }
.nchan__b span { color: var(--text-2); font-size: 12px; }
.nchan__go { color: var(--accent); font-weight: 700; }
#news-sub { display: flex; flex-direction: column; gap: 10px; margin-top: var(--space-3); }
#news-sub input[type="email"] { border: 1.5px solid var(--border); border-radius: var(--radius-s); padding: 11px 13px; font: 400 15px/1.3 var(--font-body); background: var(--bg); }
#news-sub input[type="email"]:focus { outline: none; border-color: var(--accent); background: var(--surface); }
/* Частота писем и категории дайджеста (замечание Петра Костина 16.09).
   Варианты - те же кнопки-пилюли .ssfd__btn, что и в фильтрах ленты, но
   выстроены в столбик, друг под другом (уточнения к замечанию). */
.newssub__opts { border: 0; margin: 0; padding: 0; }
.newssub__lg { padding: 0; font-size: 12px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--text-2); }
.newssub__row { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-2); margin-top: var(--space-2); }
/* сам переключатель не рисуем: выбор видно по подсветке кнопки */
.newssub__opt input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.newssub__opt:has(input:checked) { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.newssub__opt:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.newsside__bot { width: 62%; aspect-ratio: 3/2; object-fit: cover; height: auto; margin: var(--space-3) auto 0; border-radius: var(--radius-s); display: block; }
@media (max-width: 980px) {
  .newsgrid { grid-template-columns: 1fr; }
  /* в одну колонку прилипания нет: обёртка левой колонки растворяется
     (display: contents), а порядок задан явно - панель с фильтрами, потом лента.
     Фильтры теперь внутри панели, поэтому отдельной строки у них нет. */
  .newsgrid > .newscol { position: static; display: contents; max-height: none; overflow: visible; }
  .newsgrid .newsfeed, .newsgrid .newsside { grid-column: auto; }
  .newsgrid .newsside { grid-row: 1; }
  .newsgrid .newsfeed { grid-row: 2; }
  /* панель снова во всю ширину - поля как у остальных панелей */
  .newsside .panel { padding-left: var(--space-5); padding-right: var(--space-5); }
}
@media (max-width: 640px) {
  /* просмотрщик на телефоне: 2/3 экрана по ширине оставляли марку, поэтому
     кадр берёт ширину целиком, а по высоте ограничение остаётся */
  .nshow { gap: var(--space-2); padding: var(--space-3); }
  .nshow__img { max-width: 100%; }
}

/* авторизация */
.auth-tabs { display: flex; gap: 4px; background: var(--bg); border-radius: var(--radius-s); padding: 4px; margin-bottom: var(--space-4); }
.auth-tab { flex: 1; border: 0; background: none; border-radius: var(--r-xs); padding: 10px; font: 600 14px/1 var(--font-body); color: var(--text-2); cursor: pointer; }
.auth-tab--on { background: var(--surface); color: var(--text); box-shadow: var(--shadow-card); }
.auth-form { display: flex; flex-direction: column; gap: 14px; }
.auth-form label { display: flex; flex-direction: column; gap: 5px; font: 500 13px/1.2 var(--font-body); color: var(--text-2); }
/* кто регистрируется: заказчик или поставщик (05.09) */
.auth-kind { margin: 0; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--r-xs); display: flex; flex-direction: column; gap: 8px; }
.auth-kind legend { padding: 0 4px; font: 500 13px/1.2 var(--font-body); color: var(--text-2); }
.auth-form .auth-kind__opt { flex-direction: row; align-items: center; gap: 10px; color: var(--text); font-weight: 400; cursor: pointer; }
.auth-kind__opt input { margin: 0; accent-color: var(--accent); }
.auth-form input { border: 1.5px solid var(--border); border-radius: var(--radius-s); padding: 11px 13px; font: 400 15px/1.4 var(--font-body); background: var(--bg); }
.auth-form input:focus { outline: none; border-color: var(--accent); background: var(--surface); }
.iconbtn--auth::after { content: ""; position: absolute; right: 5px; top: 5px; width: 8px; height: 8px; border-radius: 50%; background: #1F9D55; border: 2px solid var(--surface); }

/* ================= WOW-пакет (ресерч 2026-08-07, 15 эффектов) ================= */

/* --- пружинный easing: физика вместо стандартной кривой (Baseline linear()) --- */
:root { --spring: ease-out; }
@supports (transition-timing-function: linear(0, 1)) {
  :root { --spring: linear(0, 0.006, 0.025 2.8%, 0.101 6.1%, 0.539 18.9%, 0.721 25.3%,
    0.849 31.5%, 0.937 38.1%, 0.968 41.8%, 0.991 45.7%, 1.006 50.1%, 1.015 55%, 1.017 63.9%, 1.001); }
}

/* --- bump + расходящееся кольцо бейджа корзины/избранного --- */
.iconbtn__badge.bump { animation: badge-bump .45s var(--spring); }
@keyframes badge-bump { 50% { transform: scale(1.28); } }
.iconbtn__badge::after { content: ''; position: absolute; inset: -2px; border: 2px solid var(--accent);
  border-radius: 50%; opacity: 0; pointer-events: none; }
.iconbtn__badge.bump::after { animation: badge-ring .5s ease-out; }
@keyframes badge-ring { from { opacity: .8; transform: scale(1); } to { opacity: 0; transform: scale(2.1); } }


/* --- одометр-барабан денежных сумм --- */
.od { display: inline-flex; align-items: baseline; font-variant-numeric: tabular-nums; }
/* шаг барабана СТРОГО 1em - transform в JS двигает на кратные 1em (пин 48) */
.od__d { display: inline-block; overflow: hidden; height: 1em; line-height: 1; }
.od__reel { display: flex; flex-direction: column; line-height: 1;
  transform: translateY(0); transition: transform .9s cubic-bezier(.2,.7,.2,1); }
.od__reel span { height: 1em; display: block; }
.od__s { white-space: pre; line-height: 1; }

/* --- дельта-чип «+N ₽/год» --- */
.mc-chip { position: absolute; right: 0; top: -4px; font: 600 12px/1 var(--font-body);
  color: var(--text-3); background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--pill); padding: 4px 8px; pointer-events: none; white-space: nowrap;
  box-shadow: var(--shadow-card); }
.mc-chip--up { color: var(--good); border-color: #BFE3CF; }

/* --- кольцо окупаемости --- */
.mc-out__val--ring { display: inline-flex; align-items: center; gap: 8px; }
.mc-ring { flex: none; }
.mc-ring__arc { transition: stroke-dashoffset 1s ease-in-out; }

/* --- флеш изменившихся ячеек сметы --- */
.case-table td.flash { animation: cell-flash .8s ease-out; }
@keyframes cell-flash { from { background: #DBE6FF; } to { background: transparent; } }

/* --- луч-сканер по выгодной колонке --- */
.case-beam { position: absolute; top: 0; height: 140px; pointer-events: none; will-change: transform;
  background: linear-gradient(180deg, transparent, rgba(43, 92, 230, .16), transparent);
  animation: beam-down 1.1s ease-in-out both; }
@keyframes beam-down { from { transform: translateY(-140px); } to { transform: translateY(var(--h, 400px)); } }

/* --- кнопка-стейт-машина «Подобрать конфигурацию» --- */
.case-run { position: relative; }
.case-run__spinner, .case-run__check { position: absolute; inset: 0; margin: auto; opacity: 0; }
.case-run__spinner { width: 18px; height: 18px; border: 2px solid rgba(255, 255, 255, .35);
  border-top-color: #fff; border-radius: 50%; }
.case-run__check { width: 22px; height: 22px; }
.case-run__check path { fill: none; stroke: #fff; stroke-width: 2.5; stroke-linecap: round;
  stroke-linejoin: round; stroke-dasharray: 1; stroke-dashoffset: 1; }
.case-run__label { transition: opacity .18s ease; }
.case-run[data-state="loading"] .case-run__label,
.case-run[data-state="success"] .case-run__label { opacity: 0; }
.case-run[data-state="loading"] .case-run__spinner { opacity: 1; animation: spin .6s linear infinite; }
.case-run[data-state="success"] .case-run__check { opacity: 1; }
.case-run[data-state="success"] .case-run__check path { stroke-dashoffset: 0;
  transition: stroke-dashoffset .35s ease .1s; }
@keyframes spin { to { transform: rotate(360deg); } }

/* --- 3D-tilt пэкшота (только hover-указатели, вешает tilt.js) ---
   Белый блик за курсором убран по просьбе заказчика: при наведении он
   засвечивал изображение и искажал цвет техники. Наклон оставлен. */
.prod__media, .detail__media { transform: perspective(800px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition: transform .55s var(--spring); }
.prod__media.is-tilt, .detail__media.is-tilt { transition: transform .12s ease-out; }
.prod__media, .detail__media { position: relative; }

/* --- морф пэкшота карточка -> hero детальной (View Transitions) --- */
.detail__media--art img { view-transition-name: robot-hero; }
::view-transition-group(robot-hero) { animation-duration: .35s;
  animation-timing-function: cubic-bezier(.22, .61, .36, 1); }

/* --- @starting-style: панели шапки и пузыри консультанта въезжают сами --- */
@supports (transition-behavior: allow-discrete) {
  .hpanel { transition: opacity .22s ease, transform .22s ease; }
  @starting-style { .hpanel { opacity: 0; transform: translateY(6px); } }
  .adv-menu { transition: opacity .2s ease, transform .2s ease; }
  @starting-style { .adv-menu { opacity: 0; transform: translateY(8px) scale(.98); } }
}

/* --- LiDAR-скан hero --- */
.hero__float { position: relative; animation: hero-float 7s ease-in-out infinite; }
.hero__photo--render img { animation: none; }
.hero-scan__beam { position: absolute; left: -4%; right: -4%; top: 0; height: 3px; opacity: 0;
  pointer-events: none; border-radius: var(--r-xs);
  background: linear-gradient(90deg, transparent, rgba(43, 92, 230, .65), transparent); }
.scanning .hero-scan__beam { opacity: 1; animation: scan-down 2.2s linear both; }
@keyframes scan-down { from { transform: translateY(0); opacity: 1; } 88% { opacity: 1; } to { transform: translateY(330px); opacity: 0; } }
.hero-mark { position: absolute; pointer-events: none; opacity: 0; transform: scale(.92);
  transition: opacity .25s ease, transform .25s var(--spring);
  font: 600 11px/1 var(--font-mono); color: var(--accent); white-space: nowrap;
  background: rgba(255, 255, 255, .86); border: 1px solid var(--accent-soft);
  border-radius: var(--r-xs); padding: 5px 8px; box-shadow: var(--shadow-card); }
.hero-mark::before { content: '+'; margin-right: 5px; font-weight: 700; }
.hero-mark.lit { opacity: 1; transform: none; }

/* --- спарклайн безубыточности (деталь модели) --- */
.spark { margin-top: var(--space-3); border-top: 1px dashed var(--border); padding-top: var(--space-3); }
.spark svg { display: block; width: 100%; height: 84px; }
.spark__t { margin: 0 0 6px; font: 600 12px/1.3 var(--font-body); color: var(--text-2); }
.spark__legend { display: flex; gap: 14px; margin: 6px 0 0; font-size: 11px; color: var(--text-3); }
.spark__pulse { animation: spark-pulse 2.2s ease-out 2s 3; opacity: 0; }
@keyframes spark-pulse { 0% { opacity: .7; transform: scale(1); } 100% { opacity: 0; transform: scale(2.6); } }
.spark__pulse { transform-origin: center; transform-box: fill-box; }

/* --- reduced-motion: весь пакет выключается --- */
@media (prefers-reduced-motion: reduce) {
  .iconbtn__badge.bump, .iconbtn__badge.bump::after, .case-beam,
  .case-table td.flash, .case-run__spinner, .spark__pulse, .scanning .hero-scan__beam { animation: none; }
  .od__reel, .mc-ring__arc, .case-run__check path, .prod__media, .detail__media,
  .hero-mark, .spark__line, .mcard { transition: none; }
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
  .hero__float { animation: none; }
}

/* панель вводных каталога («Ваши вводные») убрана по замечанию Петра Костина
   (31.08): ставку и смены клиент задаёт в калькуляторе на странице модели */

/* мобилка: плавающая кнопка консультанта - компактный круг, не перекрывает контент */
@media (max-width: 560px) {
  .adv-fab { padding: 0; width: 56px; height: 56px; border-radius: 50%; justify-content: center; }
  .adv-fab__msg { display: none; }
  .adv-fab .adv-face { width: 34px; height: 34px; }
  .adv-menu { right: 14px; bottom: 78px; }
}

/* консалтинг: большие блоки одной высоты (правило живёт здесь - market.css
   грузится после site.css и перебивает .journey{align-items:start}) */
.journey--big { align-items: stretch; }
.journey--big .jstep--big { display: flex; flex-direction: column; height: 100%; }
.journey--big .jstep__d { margin-bottom: 0; }

/* ---------- режим инвесткомитета ---------- */
.fin-schemes { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-2); margin-bottom: var(--space-2); }
.fin-scheme { text-align: left; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-s);
  padding: 12px 14px; cursor: pointer; font: inherit; transition: border-color .15s ease, background .15s ease; }
.fin-scheme b { display: block; font-size: 15px; }
.fin-scheme span { display: block; font-size: 12px; color: var(--text-2); margin-top: 2px; }
.fin-scheme:hover { border-color: var(--text-3); }
.fin-scheme.is-on { background: var(--accent-soft); border-color: var(--accent); }
/* Подсветки «лучшей» схемы (зелёная рамка и плашка) больше нет - убрана по
   правке Петра Костина 08.09, на тумблере остаётся только выбор схемы (is-on). */
.fin-toggle { display: flex; align-items: center; gap: 8px; font-size: 14px;
  margin: var(--space-3) 0 0; cursor: pointer; }
.fin-toggle input { width: 16px; height: 16px; margin: 0; accent-color: var(--accent); flex: none; }
.fin-pay { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-4); margin-bottom: var(--space-2); }
.fin-pay__v { margin: 2px 0 0; font: 700 22px/1.2 var(--font-mono); font-variant-numeric: tabular-nums; }
.fin-pay__v small { display: block; font: 400 12px/1.4 var(--font-body); color: var(--text-2); margin-top: 3px; }
.fin-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-3); margin: var(--space-4) 0; }
.fin-kpi { background: var(--surface-2); border-radius: var(--radius-s); padding: 12px 14px; }
.fin-kpi__v { margin: 2px 0 0; font: 700 18px/1.2 var(--font-mono); font-variant-numeric: tabular-nums; }
.fin-kpi__v--good { color: var(--good); }
.fin-kpi__v--bad { color: var(--warn); }
/* Показатели кликабельные (правка Петра Костина 07.09): выбранный блок задаёт
   график расходов под блоками. Рамка прозрачная, поэтому размер карточки от
   выбора не меняется. */
.fin-kpi { cursor: pointer; border: 1px solid transparent;
  transition: border-color .15s ease, background .15s ease; }
.fin-kpi:hover { border-color: var(--text-3); }
.fin-kpi.is-on { background: var(--accent-soft); border-color: var(--accent); }
.fin-kpi:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; }
/* Столбчатая диаграмма расходов по месяцам: во всю ширину панели. Столбик -
   накопительный, нарастающего итога по месяцам нет. Чем крупнее статья
   расходов, тем ниже она в столбике и тем темнее заливка: в основании синий
   панели, выше более светлые тона. */
.fin-chart { margin: 0 0 var(--space-4); }
.fin-chart__plot { display: flex; align-items: stretch; gap: 2px; width: 100%; height: 180px;
  margin-top: var(--space-2); border-bottom: 1px solid var(--border); }
/* В месяце может стоять несколько столбиков рядом (правка Петра Костина 07.09):
   на графике NPV это траты на технику, оплата труда и баланс месяца. Зазор
   между ними меньше зазора между месяцами, поэтому тройка читается как группа. */
.fin-bar { flex: 1 1 0; min-width: 0; display: flex; gap: 1px; }
.fin-bar__stack { flex: 1; min-width: 0; display: flex; flex-direction: column-reverse;
  justify-content: flex-start; }
/* мелкая статья не должна пропасть совсем: на фоне разового платежа в первом
   месяце сервис занимает доли процента высоты */
.fin-bar__seg { display: block; min-height: 2px; }
.fin-bar__seg--1 { background: var(--accent); }
.fin-bar__seg--2 { background: color-mix(in srgb, var(--accent) 62%, var(--white)); }
.fin-bar__seg--3 { background: color-mix(in srgb, var(--accent) 36%, var(--white)); }
.fin-bar__seg--4 { background: color-mix(in srgb, var(--accent) 20%, var(--white)); }
/* баланс месяца: зелёный, когда оплата труда дороже техники, красный - когда
   техника дороже людей (те же цвета, что у показателей выше) */
.fin-bar__seg--good { background: var(--good); }
.fin-bar__seg--bad { background: var(--warn); }
/* Расходы за весь период одним горизонтальным столбиком с накоплением
   (правка Петра Костина 08.09): статьи идут слева направо от самой крупной к
   мелкой, подпись статьи и сумма стоят внутри своего сегмента. Узкие сегменты
   подписи не вмещают - они читаются по легенде и подсказке. */
.fin-chart__row { display: flex; width: 100%; height: 64px; margin-top: var(--space-2);
  border-radius: var(--radius-s); overflow: hidden; }
.fin-bar__part { min-width: 3px; display: flex; flex-direction: column; justify-content: center;
  gap: 2px; padding: 0 10px; overflow: hidden; color: var(--text); }
.fin-bar__part.fin-bar__seg--1, .fin-bar__part.fin-bar__seg--good,
.fin-bar__part.fin-bar__seg--bad { color: var(--white); }
.fin-bar__part i { font: 400 11px/1.2 var(--font-body); font-style: normal; white-space: nowrap; }
.fin-bar__part b { font: 700 13px/1.2 var(--font-body); white-space: nowrap;
  font-variant-numeric: tabular-nums; }
.fin-chart__ax { display: flex; gap: 2px; margin-top: 4px; }
.fin-ax__k { flex: 1 1 0; min-width: 0; text-align: center; overflow: hidden;
  font: 400 10px/1.3 var(--font-body); color: var(--text-2); font-variant-numeric: tabular-nums; }
.fin-chart__legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: var(--space-2) 0 0;
  font: 400 12px/1.4 var(--font-body); color: var(--text-2); }
.fin-legend__i { display: inline-flex; align-items: center; gap: 6px; }
.fin-legend__c { flex: none; width: 10px; height: 10px; border-radius: 2px; }
/* Классический график IRR (правка Петра Костина 07.09): профиль NPV - кривая
   NPV при разных ставках дисконтирования, IRR это её пересечение с нулём.
   viewBox растянут по ширине панели, поэтому толщина линий держится
   non-scaling-stroke, а подписи и точка выведены span поверх графика. */
.fin-irr__plot { position: relative; width: 100%; height: 180px; margin-top: var(--space-2);
  border-bottom: 1px solid var(--border); }
.fin-irr__svg { display: block; width: 100%; height: 100%; }
.fin-irr__curve { fill: none; stroke: var(--accent); stroke-width: 2; vector-effect: non-scaling-stroke; }
.fin-irr__base { stroke: var(--text-3); stroke-width: 1; stroke-dasharray: 4 4; vector-effect: non-scaling-stroke; }
.fin-irr__at { stroke: var(--accent); stroke-width: 1; stroke-dasharray: 3 3; vector-effect: non-scaling-stroke; }
.fin-irr__dot { position: absolute; width: 9px; height: 9px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--white); transform: translate(-50%, -50%); }
.fin-irr__mark { position: absolute; transform: translate(-50%, -100%); margin-top: -8px;
  white-space: nowrap; font: 700 12px/1.3 var(--font-mono); color: var(--accent); }
.fin-irr__zt { position: absolute; right: 0; transform: translateY(-100%); margin-top: -3px;
  font: 400 11px/1.3 var(--font-body); color: var(--text-2); }
/* График срока окупаемости (правка Петра Костина 07.09): две накопительные
   линии - траты на технику и оплата труда, точка их пересечения и есть срок
   окупаемости. Разметка та же, что у графика IRR (.fin-irr__*), своя только
   раскраска линий: техника синяя, труд зелёный - как в легенде столбиков. */
.fin-line { fill: none; stroke-width: 2; vector-effect: non-scaling-stroke; }
.fin-line--cost { stroke: var(--accent); }
.fin-line--gain { stroke: var(--good); }
.fin-irr__ax { display: flex; justify-content: space-between; margin-top: 4px; }
.fin-irr__ax span { font: 400 10px/1.3 var(--font-body); color: var(--text-2);
  font-variant-numeric: tabular-nums; }
.fin-verdict { display: flex; flex-direction: column; gap: 4px; padding: 12px 16px; border-radius: var(--radius-s);
  border-left: 4px solid var(--text-3); background: var(--surface-2); margin-bottom: var(--space-4); }
.fin-verdict b { font-size: 15px; }
.fin-verdict span { font-size: 14px; color: var(--text-2); }
.fin-verdict--good { border-left-color: var(--good); background: #EAF7F0; }
.fin-verdict--ok { border-left-color: var(--accent); background: var(--accent-soft); }
.fin-verdict--warn, .fin-verdict--stop { border-left-color: var(--warn); background: #FDF1E7; }
/* подписи строк переносятся по словам (правка Петра Костина 10.09): после
   «Оплата труда за 12 месяцев» в одну строку таблица переставала помещаться
   в панель и получала полосу прокрутки */
.fin-flow th[scope="row"] { white-space: normal; }
.fin-flow td { font-variant-numeric: tabular-nums; text-align: right; }
/* пояснения к строкам таблицы NPV (правка Петра Костина 10.09): рядом с
   подписью строки стоит значок «?», текст открывается по наведению. Уточнение
   разработчика: фрейм раскрывается над строкой, у самого курсора, а не полосой
   под таблицей. Обрез у обёртки этой таблицы снят, иначе её край срезал бы
   фрейм; прокрутки от этого не появляется - подписи строк переносятся по
   словам, и таблица помещается по ширине панели. На узких экранах столбцы уже
   не сжимаются, поэтому там обёртка по-прежнему прокручивается, а фрейм первой
   строки раскрывается вниз, чтобы не уходить под её край */
.fin-flow__wrap { overflow: visible; }
/* без обреза заливку последнего столбца нужно скруглить самой, иначе она
   выходит за скруглённые углы обёртки */
.fin-flow__wrap .fin-flow thead th:last-child { border-top-right-radius: var(--radius); }
.fin-flow__wrap .fin-flow tbody tr:last-child td:last-child { border-bottom-right-radius: var(--radius); }
/* значок «?» в таблице мельче, чем у вводных полей, и стоит по центру строки
   в конце подписи (уточнение разработчика) */
.mc-field__tip.fin-flow__q {
  width: 11px; height: 11px; font-size: 8px; vertical-align: middle;
}
.fin-flow__cap { position: relative; cursor: help; }
.fin-flow__cap::after {
  content: attr(data-tip);
  position: absolute; left: 0; bottom: calc(100% + 8px); z-index: 6;
  width: max-content; max-width: 320px; padding: 8px 10px;
  border: 1px solid var(--border); border-radius: var(--radius-s);
  background: var(--white); color: var(--text); box-shadow: var(--shadow-lift);
  font: 400 12px/1.35 var(--font-body); text-align: left; white-space: normal;
  opacity: 0; visibility: hidden; pointer-events: none;
}
.fin-flow__cap:hover::after, .fin-flow__cap:focus-within::after {
  opacity: 1; visibility: visible;
}
@media (max-width: 980px) {
  .fin-flow__wrap { overflow-x: auto; }
  .fin-flow__cap::after { max-width: 240px; }
  .fin-flow tbody tr:first-child .fin-flow__cap::after { top: calc(100% + 8px); bottom: auto; }
}
/* вертикальные линии между столбцами и номера лет по центру
   (правка заказчика 04.09): первый столбец с подписями строк остаётся
   без линии слева, иначе она удвоит рамку .cmpwrap */
.fin-flow th + th, .fin-flow td { border-left: 1px solid var(--border); }
.fin-flow thead th + th { text-align: center; }
/* последний столбец ведомости - «в месяц»: лёгкая заливка тем же оттенком,
   что и выделенный столбец сравнения (правка заказчика 04.09) */
.fin-flow th:last-child, .fin-flow td:last-child {
  background: color-mix(in srgb, var(--accent) 7%, var(--surface)); }
/* расход в ведомости: знака «минус» нет, вместо него сдержанный красный
   (правка заказчика 04.09) - 5,9:1 на белом, темнее и спокойнее --warn */
.fin-flow__neg { color: #B42318; }
/* положительный NPV в таблице по годам (правка заказчика 10.09): зелёный
   рядом с красным расходом, нулевое значение остаётся обычного цвета */
.fin-flow__pos { color: var(--good); }
.fin-fields { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-3); margin: var(--space-3) 0; }
/* поэтапное заполнение (правка заказчика 05.09): поле, которого ждёт
   следующий шаг, подсвечено акцентной рамкой. Правка заказчика 07.09:
   подсказка вернулась под поле, но абсолютом - высота .mc-field от неё не
   растёт, и поле остаётся на прежнем месте по вертикали. Внутри поля -
   рекомендуемое значение плейсхолдером и кнопка-галочка, под неё отведён
   правый отступ ввода */
.mc-field--need { position: relative; }
.mc-field--need input { border-color: var(--accent); background: var(--accent-soft); padding-right: 34px; }
.mc-field--need input::placeholder { color: var(--accent); opacity: 1; font-weight: 400; }
.mc-field__need {
  position: absolute; top: 100%; left: 0; margin-top: 4px;
  font: 400 11px/1.3 var(--font-body); font-style: normal; color: var(--accent);
}
.mc-field__ok {
  position: absolute; right: 6px; bottom: 6px; width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--accent); border-radius: var(--radius-s);
  background: var(--white); color: var(--accent); font-size: 12px; line-height: 1;
  padding: 0; cursor: pointer;
}
/* значок подсказки у подписи поля (правка Петра Костина 09.09): сам текст
   выводится сразу своим фреймом в стиле сайта - системный title ждал около
   секунды и рисовался окном системы. Фрейм стоит над подписью абсолютом,
   поэтому поля по вертикали не сдвигаются */
.mc-field { position: relative; }
.mc-field__tip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 13px; height: 13px; border-radius: 50%;
  border: 1px solid var(--accent); color: var(--accent);
  font: 700 9px/1 var(--font-body); cursor: help; vertical-align: middle;
}
.mc-field__tip:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; }
.mc-field__cap { cursor: help; }
.mc-field__cap::after {
  content: attr(data-tip);
  position: absolute; left: 0; bottom: calc(100% + 6px); z-index: 5;
  width: max-content; max-width: 240px; padding: 6px 8px;
  border: 1px solid var(--border); border-radius: var(--radius-s);
  background: var(--white); color: var(--text); box-shadow: var(--shadow-lift);
  font: 400 12px/1.35 var(--font-body); text-align: left;
  opacity: 0; visibility: hidden; pointer-events: none;
}
/* без задержки: показываем по наведению на подпись со значком и по фокусу
   на значке с клавиатуры */
.mc-field__cap:hover::after, .mc-field__cap:focus-within::after {
  opacity: 1; visibility: visible;
}
.mc-field__ok:hover { background: var(--accent); color: var(--white); }
.mc-field__ok:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; }
/* крестик у заполненного поля (замечание Петра Костина, карточка решения):
   очищает значение и возвращает шаг к этому полю. Кнопка стоит там же, где
   галочка у поля-шага, но спокойнее по тону - это не подсказка, а сброс */
.mc-field__no {
  position: absolute; right: 6px; bottom: 6px; width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: var(--radius-s);
  background: var(--white); color: var(--text-3); font-size: 12px; line-height: 1;
  padding: 0; cursor: pointer;
}
.mc-field__no:hover { border-color: var(--text-3); color: var(--text); }
.mc-field__no:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; }
/* под кнопку внутри поля отведён правый отступ ввода - как у поля-шага */
.mc-field--filled input { padding-right: 34px; }
@media (max-width: 980px) {
  .fin-schemes, .fin-kpis { grid-template-columns: repeat(2, 1fr); }
  .fin-pay, .fin-fields { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .fin-schemes, .fin-kpis, .fin-pay, .fin-fields { grid-template-columns: 1fr; }
}

/* стили блока «Цель простой окупаемости» убраны вместе с ним (правка 04.09) */

/* ---------- запас прочности: шкала порогов и торнадо чувствительности ---------- */
.sens { margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px dashed var(--border); }
.sens:empty { display: none; }
.sens__t { margin: 0 0 var(--space-3); font: 600 14px/1.3 var(--font-body); }
.sens__note { margin: var(--space-3) 0 0; font-size: 13px; line-height: 1.55; color: var(--text-2); }
.sens__note b { color: var(--text); }

/* Маркер «вы» стоит НАД полосой и подписан значением: раньше он висел отдельной
   меткой под шкалой и на широкой панели читался как оторванный элемент (08-11). */
.sens-scale { position: relative; height: 46px; margin-top: var(--space-5); }
.sens-scale__track { position: absolute; left: 0; right: 0; top: 0; height: 8px; border-radius: var(--r-xs);
  background: linear-gradient(90deg, #FDE7DA 0%, #FDE7DA var(--sub), #EAF0FE var(--sub), #EAF0FE var(--pay), #E4F5EC var(--pay), #E4F5EC 100%); }
.sens-scale__mark { position: absolute; top: 0; transform: translateX(-50%); text-align: center; white-space: nowrap; }
.sens-scale__you { position: absolute; transform: translateX(-50%); text-align: center; white-space: nowrap; }
.sens-scale__mark i, .sens-scale__you i { display: block; width: 2px; height: 14px; margin: 0 auto 4px; background: var(--text-3); }
.sens-legend { list-style: none; margin: var(--space-3) 0 0; padding: 0; display: grid; gap: 6px; }
.sens-legend li { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-2); }
.sens-legend b { font-family: var(--font-mono); color: var(--text); }
.sens-dot { width: 10px; height: 10px; border-radius: var(--r-xs); flex: none; }
.sens-dot--sub { background: var(--warn); }
.sens-dot--pay { background: var(--accent); }
.sens-dot--you { background: var(--good); }
.sens-scale__mark--sub i { background: var(--warn); }
.sens-scale__mark--pay i { background: var(--accent); }
.sens-scale__you { top: -26px; }
.sens-scale__you i { background: var(--good); height: 16px; width: 3px; border-radius: var(--r-xs); margin-top: 2px; }
.sens-scale__you b { display: block; font: 700 12px/1.2 var(--font-mono); color: var(--good);
  background: #E4F5EC; border-radius: var(--pill); padding: 3px 8px; }

.torn { display: grid; gap: 8px; }
.torn__row { display: grid; grid-template-columns: minmax(120px, 26%) 1fr 44px; align-items: center; gap: var(--space-3); }
.torn__label { font-size: 13px; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.torn__bar { height: 14px; background: var(--surface-2); border-radius: var(--r-xs); overflow: hidden; }
.torn__bar i { display: block; height: 100%; width: var(--w); border-radius: var(--r-xs);
  background: linear-gradient(90deg, var(--accent), #6C93FF); transform-origin: left center; }
.torn__val { font: 600 12px/1 var(--font-mono); color: var(--text-2); text-align: right; }
@media (max-width: 560px) { .torn__row { grid-template-columns: 1fr 40px; }
  .torn__label { grid-column: 1 / -1; } }

/* честный статус кейса: расчётная модель против реального внедрения (P0-02) */
.case-status-badge { display: inline-block; margin-bottom: 10px; font: 600 11px/1 var(--font-body);
  letter-spacing: .04em; text-transform: uppercase; color: var(--text-2);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--pill); padding: 6px 11px; }
.case-status-badge--pilot { color: var(--warn); background: #FDF1E7; border-color: #F5D5BC; }
/* Плашка статуса не растягивается на всю ширину карточки: в .mcard__body
   колонка флекса, и inline-block сам по себе занял бы всю строку. */
.mcard .case-status-badge { align-self: flex-start; margin-bottom: 0; }

/* Сетка цифр кейса: четыре метрики в колонке карточки в один ряд не встают -
   раскладываем их в две. Правила .case-item убраны вместе со своей разметкой
   выдачи: карточки каталога кейсов теперь такие же, как на главной
   (замечание Петра Костина), и берут оформление .ngm-case из wow.css. */
.mcard__metrics--case { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-3); }
.mcard__metrics--case > * { min-width: 0; }

/* Блок-схема карточки кейса (/cases/<id>/): тот же ряд из пяти шагов .journey,
   что и на главной, только шаг - карточка с рамкой и текстом, а не иконка:
   проблема, тип решения, стоимость и сроки, риски, итоги. Стрелка-перемычка
   между шагами остаётся, её только опускаем на середину карточки. */
.journey--case { align-items: stretch; gap: var(--space-3); }
/* На карточке кейса пятый шаг («Итоги») занимает отдельную строку, поэтому
   верхний ряд делим на четыре колонки - блоки занимают всю ширину страницы
   (замечание Петра Костина). На карточке партнёра шагов пять в один ряд,
   её сетку не трогаем. */
.journey--case:has(.jstep--sum) { grid-template-columns: repeat(4, 1fr); }
/* Тезис шага стоит справа от его номера (замечание Петра Костина), описание -
   строкой ниже во всю ширину карточки. Так же, как в шаге «Итоги».
   Карточки ряда равной высоты (align-items: stretch выше), поэтому строки
   сетки прижимаем к верху (align-content: start): иначе лишнюю высоту делят
   строки и серое описание уезжает в середину карточки (замечание Петра
   Костина). align-items: center оставляем - он держит номер и тезис на одной
   линии в первой строке. */
.journey--case .jstep { text-align: left; padding: var(--space-3); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-card);
  display: grid; grid-template-columns: auto 1fr; align-items: center; align-content: start;
  column-gap: var(--space-2); }
.journey--case .jstep__i { width: 32px; height: 32px; margin: 0;
  font: 700 15px/1 var(--font-display); color: var(--accent); background: var(--accent-soft); box-shadow: none; }
.journey--case .jstep__t { font-size: 15px; }
.journey--case .jstep__d { font-size: 13px; grid-column: 1 / -1; margin-top: var(--space-2); }
.journey--case .jstep:not(:last-child)::after { top: 50%; right: -10px; width: 10px; opacity: .7; }
/* Шаг «Инструменты решения» (замечание Петра Костина): ссылки на карточки
   техники и ИИ-решений кейса - плашками в столбик во всю ширину карточки. */
.jtools { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: var(--space-1);
  margin-top: var(--space-2); }
.jtool { display: inline-block; padding: 4px var(--space-2); border: 1px solid var(--border);
  border-radius: var(--radius-s); background: var(--surface);
  font-size: 13px; line-height: 1.35; color: var(--text); text-decoration: none; }
.jtool:hover { border-color: var(--accent); color: var(--accent); }
/* Сноска под рядом шагов: пометка о расчётной модели и условиях расчёта. */
.jnote { margin: var(--space-3) 0 0; font-size: 12px; color: var(--text-2); line-height: 1.5; }

/* Шаг «Итоги» (замечание Петра Костина): отдельной строкой во всю ширину ряда,
   цифры - плитками. Стрелка у предыдущего шага не нужна: дальше по строке
   карточек нет. */
.journey--case .jstep--sum { grid-column: 1 / -1;
  /* Заголовок «Итоги» стоит справа от цифры 5 (замечание Петра Костина),
     плитки цифр переносятся на следующую строку целой шириной. */
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.journey--case .jstep--sum .jstep__i { margin: 0; }
.journey--case .jstep--sum .jsum { flex-basis: 100%; margin-top: 0; }
.journey--case .jstep:has(+ .jstep--sum)::after { display: none; }
.jsum { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }
.jsum__c { display: flex; flex-direction: column; gap: 2px; padding: var(--space-2) var(--space-3);
  border: 1px solid transparent; border-radius: var(--radius-s); }
.jsum__v { font: 700 20px/1.2 var(--font-display); }
.jsum__k { font-size: 12px; color: var(--text-2); }
/* Серая плитка со смысловым итогом решения: стоит первой в «Итогах»
   (замечание Петра Костина), текст в одну колонку с цифрами. */
.jsum__c--note { max-width: 420px; justify-content: center;
  font-size: 13px; line-height: 1.45; color: var(--text-2);
  background: var(--surface-2); border-color: var(--border); }
/* Плитки срока и стоимости реализации: нейтральные серые - это не рост и не
   снижение показателя (замечание Петра Костина). */
.jsum__c--plan { background: var(--surface-2); border-color: var(--border); }
/* Срок реализации залит светло-жёлтым (замечание Петра Костина): оттенок
   статуса «в работе», в тёмной теме тот же токен темнеет сам. */
.jsum__c--term { background: var(--work-soft); border-color: var(--work-soft); }
.jsum__c--good { color: var(--good); background: var(--good-soft); border-color: var(--good-soft); }
.jsum__c--warn { color: var(--warn); background: var(--warn-soft); border-color: var(--warn-soft); }
@media (max-width: 1120px) {
  .journey--case, .journey--case:has(.jstep--sum) { grid-template-columns: repeat(2, 1fr); }
  .journey--case .jstep:not(:last-child)::after { display: none; }
}
@media (max-width: 640px) {
  .journey--case, .journey--case:has(.jstep--sum) { grid-template-columns: 1fr; }
}

/* P0-10: сетки детальной страницы решения - классами, не инлайном
   (инлайновый grid-template-columns перебивал медиа-запросы и давал
   горизонтальный скролл документа 502px при вьюпорте 390px) */
.journey--4 { grid-template-columns: repeat(4, 1fr); }
.svcrow--2 { grid-template-columns: repeat(2, 1fr); }

/* Подробное описание решения перед тезисами (замечание Петра Костина):
   карточка той же фактуры, что .svcrow ниже, колонка текста ограничена по
   ширине - длинная строка на 1192px читается тяжело. */
#solution-root .sol-about { background: var(--surface); border-radius: var(--radius);
  box-shadow: var(--shadow-card); padding: var(--space-4) var(--space-5);
  margin-bottom: var(--space-4); }
#solution-root .sol-about p { max-width: 78ch; margin: 0 0 var(--space-3);
  font: 400 16px/1.7 var(--font-body); color: var(--text-2); }
#solution-root .sol-about p:first-child { color: var(--text); }
#solution-root .sol-about p:last-child { margin-bottom: 0; }
/* Каждая возможность - отдельная карточка с обводкой (замечание Петра
   Костина): фон, тень и внутренние отступы ушли с контейнера на .svc,
   расположение в две колонки сохранено. Тезисы разной длины, поэтому
   карточки тянутся по высоте ряда - обводки в ряду одинаковые. */
.svcrow--ex { background: none; box-shadow: none; padding: 0;
  row-gap: var(--space-4); align-items: stretch; }
.svcrow--ex .svc { background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-card);
  padding: var(--space-4); }
@media (max-width: 980px) { .journey--4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) {
  .journey--4, .svcrow--2 { grid-template-columns: 1fr; }
}

/* Заголовок блока возможностей - в одну строку (замечание Петра Костина).
   Общий лимит h2 в 24ch резал «Что умеет ИИ-контроль качества» на две строки;
   в контейнере страницы (1192px) строка помещается целиком. На узких экранах
   перенос остаётся, иначе длинные названия решений уедут за край. */
.section > .wrap > h2.h2--1l { max-width: none; }

/* P0-10: метрики кейса переносятся, а не уезжают за край (на 390px из четырёх
   были видны две). Инлайновый gap убран - иначе медиа-запрос его не перебивает. */
.mcard__metrics { flex-wrap: wrap; }
.mcard__metrics--wide { border-top: 0; padding-top: var(--space-4); gap: var(--space-6); }
@media (max-width: 640px) {
  /* суммы вида «14 016 000 ₽» не влезают в две колонки на 390px - одна колонка */
  .mcard__metrics--wide { display: grid; grid-template-columns: 1fr; gap: var(--space-3); }
  .mcard__metrics--wide > * { min-width: 0; }
  .mcard__metrics--wide .mcard__mv { font-size: 22px !important; }
}

/* P0-10: до 1120px разделы живут в панели-меню, а не в сжатой строке */
.iconbtn--burger { display: none; }
@media (max-width: 1120px) {
  .topnav { display: none; }
  .iconbtn--burger { display: inline-flex; }
}
.navdrawer { display: grid; gap: 2px; }
.navdrawer a { display: block; padding: 12px 10px; border-radius: var(--radius-s); text-decoration: none;
  color: var(--text); font: 500 15px/1.2 var(--font-body); }
.navdrawer a:hover { background: var(--bg); }
.navdrawer a[aria-current="page"] { color: var(--accent); background: var(--accent-soft); }

/* ---------- вход: смысл до формы, скелет вместо вспышки гостя ---------- */
.auth-wrap { display: grid; grid-template-columns: 1.05fr 1fr; gap: var(--space-6); align-items: start; max-width: 1040px; }
.auth-intro h1 { font-size: clamp(26px, 3vw, 34px); }
.auth-benefits { list-style: none; margin: var(--space-4) 0 0; padding: 0; display: grid; gap: 12px; }
.auth-benefits li { display: grid; gap: 2px; font-size: 14px; color: var(--text-2);
  padding-left: 26px; position: relative; }
.auth-benefits li::before { content: ''; position: absolute; left: 0; top: 4px; width: 16px; height: 16px;
  border-radius: 50%; background: var(--accent-soft);
  box-shadow: inset 0 0 0 2px var(--accent); }
.auth-benefits b { color: var(--text); font-size: 15px; }
.auth-note { margin-top: var(--space-4); font-size: 13px; color: var(--text-3); }
.auth-card { min-height: 320px; }
.auth-skeleton { display: grid; gap: 14px; padding: var(--space-2) 0; }
.auth-skeleton span { display: block; height: 44px; border-radius: var(--radius-s);
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--bg) 50%, var(--surface-2) 75%);
  background-size: 200% 100%; animation: auth-shine 1.2s linear infinite; }
.auth-skeleton span:first-child { height: 40px; width: 60%; }
@keyframes auth-shine { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .auth-skeleton span { animation: none; } }
.auth-form label { font: 500 13px/1.2 var(--font-body); color: var(--text-2); }
@media (max-width: 900px) { .auth-wrap { grid-template-columns: 1fr; } }

/* ---------- запрос КП: состав проекта и переписка с менеджером ---------- */
.req { display: grid; gap: var(--space-3); max-width: 760px; }
/* Пока request-page.js не отрисовал переписку, в блоке стоит скелет высотой
   156px, а на его место встаёт вид гостя: 380px на десктопе и 590px на телефоне
   (замерено в Chromium 05.09). Подвал уезжал вниз на всю разницу - отсюда
   CLS 0,1418 на мобильной request.html, самый высокий на сайте, при том что
   изображений на странице нет вовсе. Резервируем место по гостевому виду -
   он самый частый; после отрисовки js снимает aria-busy, и резерв уходит
   вместе с ним. План прода 05.09, шаг 0.5. */
.req[aria-busy="true"] { min-height: 380px; }
@media (max-width: 720px) { .req[aria-busy="true"] { min-height: 590px; } }
.req .panel + .panel { margin-top: 0; }   /* расстояние держит gap сетки */
.req__t { margin-bottom: var(--space-2); }
.req__items { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.req__items li { display: flex; gap: var(--space-3); justify-content: space-between;
  align-items: baseline; font-size: var(--fs-4); border-bottom: 1px solid var(--border);
  padding-bottom: var(--space-2); }
.req__items li:last-child { border-bottom: 0; padding-bottom: 0; }
.req__items span { color: var(--text-2); white-space: nowrap; }
.req__total { display: flex; justify-content: space-between; margin: var(--space-3) 0 var(--space-2);
  font-size: var(--fs-5); }
.req__keep, .req__who { font-size: var(--fs-3); color: var(--text-2); margin: var(--space-2) 0 0; }
.req__status { color: var(--accent); font-weight: 600; }
.req__empty { color: var(--text-2); font-size: var(--fs-4); margin: 0; }
.req__thread { margin: var(--space-3) 0; }
/* подраздел «Запросы демонстрации»: карточка модели, с которой пришли */
.req__demo { background: var(--surface-2); border-radius: var(--radius-s);
  padding: var(--space-3); margin-bottom: var(--space-3); }
.req__demo-t { margin: 0; font-size: var(--fs-4); color: var(--text-2); }
.req__demo .mcard__d { margin: var(--space-2) 0 0; }
.req__demo .prod__actions { margin-top: var(--space-3); }
.chat { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.chatmsg { background: var(--surface-2); border-radius: var(--radius-s); padding: 10px 14px;
  max-width: 90%; justify-self: end; }
/* ответ менеджера - с другой стороны и другим фоном: видно, кто написал */
.chatmsg--manager { background: var(--accent-soft); justify-self: start; }
.chatmsg__who { display: flex; gap: var(--space-2); margin: 0; font-size: var(--fs-2);
  color: var(--text-2); }
.chatmsg__text { margin: 2px 0 0; white-space: pre-wrap; font-size: var(--fs-4); }
.req__form label { display: block; font: 500 13px/1.2 var(--font-body); color: var(--text-2);
  margin-bottom: var(--space-1); }
/* поле как в форме заявки: своих номиналов не заводим */
.req__form textarea { width: 100%; box-sizing: border-box; border: 1.5px solid var(--border);
  border-radius: var(--radius-s); padding: 10px 12px; font: 400 15px/1.4 var(--font-body);
  background: var(--bg); color: var(--text); resize: vertical; }
.req__form textarea:focus { outline: none; border-color: var(--accent); background: var(--surface); }
.req__form .prod__actions { margin-top: var(--space-2); }

/* спокойное подтверждение вместо «полёта в корзину» (B2B, не супермаркет) */
.proj-toast { position: fixed; right: 22px; bottom: 92px; z-index: 95; max-width: 320px;
  background: var(--ink); color: #F2F5FA; border-radius: var(--radius-s); padding: 12px 16px;
  font: 500 14px/1.4 var(--font-body); box-shadow: 0 14px 40px rgba(15, 23, 42, .28); }
@media (max-width: 560px) { .proj-toast { right: 12px; left: 12px; max-width: none; bottom: 84px; } }

/* источник цифр витрины виден рядом с ними */
.statrow__src { margin: var(--space-2) 0 0; font-size: 12px; color: var(--text-3); text-align: left; }
.statrow__src a { color: var(--accent); text-decoration: none; }
.statrow__src a:hover { text-decoration: underline; }

/* теги решения отдельной строкой: раньше стояли на месте подписи к цифре эффекта */
.mcard__tags { margin: 6px 0 0; font-size: 11px; color: var(--text-3); }

/* ---------- карусель изображений модели (пин 71) ----------
   Свайп нативный: scroll-snap по горизонтали, кнопки и точки - для мыши
   и клавиатуры. Каждый слайд подписан своим происхождением. */
.gal { position: relative; display: flex; align-items: stretch; gap: var(--space-2); }
.gal--single { display: block; }
.gal__main { position: relative; flex: 1 1 auto; min-width: 0; }
/* Рельс миниатюр слева: все изображения карточки сразу, клик - переход на слайд.
   Ширина - 15% от основного изображения (просьба заказчика). Основное занимает
   оставшиеся 100%, поэтому от всей галереи без зазора это 15/115. */
.gal__thumbs { flex: 0 0 calc((100% - var(--space-2)) * 15 / 115); min-width: 0; min-height: 0;
  display: flex; flex-direction: column; gap: var(--space-2);
  overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; }
.gal__thumb { flex: 0 0 auto; padding: 0; overflow: hidden; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-s); background: var(--white); }
/* height: auto обязателен - у картинки есть атрибут height="1024",
   и без сброса он побеждает aspect-ratio, растягивая миниатюру на всю высоту. */
.gal__thumb img { display: block; width: 100%; height: auto; aspect-ratio: 16/11;
  object-fit: cover; object-position: center; }
.gal__thumb:hover { border-color: var(--accent); }
.gal__thumb.is-on { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.gal__track { display: grid; grid-auto-flow: column; grid-auto-columns: 100%;
  overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none;
  border-radius: var(--radius); background: var(--white); }
.gal__track::-webkit-scrollbar { display: none; }
.gal__track:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.gal__slide { margin: 0; scroll-snap-align: start; }
/* Изображение слайда - кнопка: клик открывает просмотр во весь экран.
   Курсор здесь такой же, как над ссылкой (уточнение разработчика);
   «плюс» живёт внутри виджета, где щелчок увеличивает снимок. */
.gal__open { display: block; width: 100%; padding: 0; border: 0; background: none;
  cursor: pointer; border-radius: var(--radius); overflow: hidden; }
.gal__open:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Кадр один и тот же во всех карточках, а фото занимает его целиком:
   выравнивается по центру и обрезается по краям (замечание Петра Костина).
   Белой подложки и полей вокруг изображения больше нет.
   height: auto обязателен - иначе атрибут height="1024" победит aspect-ratio. */
.gal__slide img { display: block; width: 100%; height: auto; aspect-ratio: 16/11; max-height: 460px;
  object-fit: cover; object-position: center; }
.gal__nav { position: absolute; top: 40%; width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid var(--border); background: rgba(255,255,255,.94); color: var(--text);
  font: 600 15px/1 var(--font-body); cursor: pointer; display: grid; place-items: center;
  box-shadow: var(--shadow-card); }
.gal__nav--prev { left: 10px; }
.gal__nav--next { right: 10px; }
.gal__nav:hover { border-color: var(--accent); color: var(--accent); }
/* На узком экране 15% - слишком тонкая полоска, поэтому миниатюры уходят
   под основное изображение и листаются по горизонтали. */
@media (max-width: 640px) {
  .gal__nav { display: none; }
  .gal { flex-direction: column; }
  .gal__thumbs { order: 2; flex: 0 0 auto; flex-direction: row;
    overflow-x: auto; overflow-y: hidden; }
  .gal__thumb { flex: 0 0 64px; }
}

/* Высота снимка - от верхнего края блока до нижнего края кнопок «Запросить КП»,
   «В корзину», «В избранное» (замечание Петра Костина, 04.09). Пока колонки две,
   левая растягивается на всю строку сетки, а галерея внутри лежит поверх неё:
   тогда высоту строки задаёт только правая колонка, и снимок кончается ровно
   на кнопках. min-height - страховка на случай очень короткой правой колонки
   (например, «Цена по запросу» без чипов). */
@media (min-width: 981px) {
  /* Ширина снимка - ровно от левого до правого края панели «Характеристики»
     под ним (замечание Петра Костина, 04.09). Панель - половина сетки
     .detail-stack, а она лежит в том же .wrap, поэтому колонка галереи
     считается той же формулой: (ширина .wrap - зазор сетки) / 2. До этого
     колонка была 1.15fr и снимок выступал за панель на 15 px.
     Правило через :has, чтобы не задеть .detail на странице консалтинга. */
  .detail:has(> .detail__gal) { grid-template-columns: calc((100% - var(--space-3)) / 2) 1fr; }
  .detail__gal { position: relative; align-self: stretch; min-height: 320px; }
  /* В карточках ИИ-решений минимальная высота снимка на 10% больше базовой:
     320px -> 352px (замечание Петра Костина). Карточки роботов не трогаем. */
  #solution-root .detail__gal { min-height: 352px; }
  .detail__gal > .gal { position: absolute; inset: 0; }
  .detail__gal .gal__main { height: 100%; min-height: 0; }
  .detail__gal .gal__track { height: 100%; }
  .detail__gal .gal__slide { position: relative; height: 100%; min-height: 0; }
  /* Кнопка снимка разложена по слайду absolute: высота строки карусели считается
     по содержимому, и обычный height: 100% внутри неё схлопывается обратно в
     пропорцию картинки. Растягиваем именно кнопку, а не изображение, иначе у
     кнопки остаётся нулевая высота - по снимку нельзя кликнуть и рамка фокуса
     вырождается в полоску. */
  .detail__gal .gal__open { position: absolute; inset: 0; }
  /* Кадр теперь задаёт колонка, а не пропорция 16/11: снимок обрезается по
     центру (object-fit: cover стоит выше). */
  .detail__gal .gal__slide img { height: 100%; aspect-ratio: auto; max-height: none; }
}

/* ---------- виджет просмотра изображений модели ----------
   Открывается кликом по изображению карточки: подложка белая непрозрачная и во
   весь экран (просьба заказчика), слева список изображений, стрелки по бокам,
   крестик справа сверху. Щелчок по снимку увеличивает его на 30%.
   top и bottom market.js может сузить до видимой части экрана - это нужно в
   рамке доски ревью, где высота окна равна высоте всей страницы. */
.galview { position: fixed; inset: 0; z-index: 95; background: var(--white);
  display: flex; align-items: stretch; gap: var(--space-3); padding: var(--space-4); }
.galview__rail { flex: 0 0 120px; display: flex; flex-direction: column; gap: var(--space-2);
  overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; }
.galview__thumb { flex: 0 0 auto; padding: 0; overflow: hidden; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-s); background: var(--white); }
/* height: auto обязателен - иначе атрибут height="1024" победит aspect-ratio. */
.galview__thumb img { display: block; width: 100%; height: auto; aspect-ratio: 16/11;
  object-fit: cover; object-position: center; }
.galview__thumb:hover { border-color: var(--accent); }
.galview__thumb.is-on { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
/* Стрелки отсчитываются от области снимка, а не от всего виджета: иначе левая
   ложится поверх списка изображений, когда он длинный. */
.galview__body { position: relative; flex: 1 1 auto; min-width: 0; display: flex; }
.galview__stage { flex: 1 1 auto; min-width: 0; display: grid; overflow: auto; }
/* margin: auto вместо place-items: center - при центрировании сетки увеличенный
   снимок обрезается по верхнему и левому краю и доскроллить до него нельзя. */
.galview__img { margin: auto; max-width: 100%; max-height: 100%;
  object-fit: contain; cursor: zoom-in; }
/* Увеличенный размер считает market.js: он берёт 200% от того, в котором
   снимок помещается в окно, и ставит в пикселях - потолки здесь только мешают. */
.galview__img.is-zoom { max-width: none; max-height: none; object-fit: contain; cursor: zoom-out; }
.galview__nav, .galview__x { position: absolute; width: 44px; height: 44px; border-radius: 50%;
  border: 1px solid var(--border); background: var(--white); color: var(--text);
  font: 600 17px/1 var(--font-body); cursor: pointer; display: grid; place-items: center;
  box-shadow: var(--shadow-card); }
.galview__nav:hover, .galview__x:hover { border-color: var(--accent); color: var(--accent); }
.galview__nav { top: 50%; transform: translateY(-50%); }
.galview__nav--prev { left: var(--space-3); }
.galview__nav--next { right: var(--space-3); }
.galview__x { top: var(--space-3); right: var(--space-3); font-size: 22px; }
/* На узком экране список изображений уходит вниз строкой, как рельс в карточке. */
@media (max-width: 640px) {
  .galview { flex-direction: column; padding: var(--space-3); }
  .galview__rail { order: 2; flex: 0 0 auto; flex-direction: row;
    overflow-x: auto; overflow-y: hidden; }
  .galview__thumb { flex: 0 0 64px; }
  .galview__nav { display: none; }
}

/* ---------- карточка модели: панели в одну колонку во всю ширину (пины 73-76) ---------- */
.detail-stack { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
.detail-stack .panel { margin-top: 0; }
/* Два столбца нужны только паре «Характеристики» + «Где применяется» (замечание
   Петра Костина): содержимого в них немного, и порознь каждая занимала целую
   полосу. Остальные панели остаются во всю ширину - они растянуты на оба
   столбца, чтобы не вернуть двухколоночную раскладку из пинов 73-76. */
.detail-stack > * { grid-column: 1 / -1; }
.detail-stack .panel--half { grid-column: auto; }
/* На узком экране пара снова встаёт одна под другой. */
@media (max-width: 900px) {
  .detail-stack .panel--half { grid-column: 1 / -1; }
}
/* Характеристики - одним столбцом, пункт под пунктом (замечание Петра Костина):
   в три колонки строки читались вразнобой, а название и значение стояли впритык.
   Столбец один на всех ширинах, поэтому медиазапросы тут больше не нужны. */
.detail-stack .speclist { grid-template-columns: minmax(0, 1fr); }

/* ---------- страница решения: «Реализация» + «Совместимость ПО» в одну линию ----------
   Пропорция 2/3 и 1/3 (замечание Петра Костина). Высота выравнивается сама:
   элементы сетки растягиваются по строке, то есть по самой высокой панели. */
.sol-panels { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: var(--space-3); align-items: stretch; }
.sol-panels .panel { margin-top: 0; }
/* На узком экране панели снова встают одна под другой. */
@media (max-width: 900px) {
  .sol-panels { grid-template-columns: minmax(0, 1fr); }
}

/* финальная плашка карточки модели: текст слева, а не по центру (пин 77) */
.cta-final { text-align: left; }
.cta-final__lead { color: var(--text-2); margin: var(--space-2) 0 var(--space-4); max-width: none; }

/* плитки типов техники: подписи в одну сетку, чтобы карточки не «прыгали» (пин 68) */
.typecard__t { min-height: 1.3em; }
.typecard__h { min-height: calc(2 * 1.35em); display: -webkit-box; -webkit-line-clamp: 2;
  -webkit-box-orient: vertical; overflow: hidden; }

/* заголовки разделов в одну строку (пин 64, повтор 08-19, 03.09): общее правило
   h2 ограничивает ширину 24 символами и рвёт их на две строки. Так было с
   «Консалтинг - как отдельная услуга», так же переносилось «Рабочие и
   безопасные решения» в блоке о компании - последнее слово уезжало вниз,
   и «Оптимальный способ инвестировать» в блоке инвесткомитета.
   Блок кейсов на карточке модели (#rel-cases) был здесь же, пока заголовок
   был длинным; после правки 03.09 он звучит «Кейсы с похожей техникой» и в
   24ch укладывается сам - исключение убрано, замеры с ним и без совпадают:
   одна строка до 768 px, две на телефоне, где ширину задаёт .wrap */
#journey h2, #team h2, #invest h2 { max-width: none; }
/* подпись под заголовком инвесткомитета - тоже в одну строку (правка 03.09): общее
   правило .section__lead режет ширину по 64ch и рвало фразу пополам. Ширину
   ограничивает сам .wrap, поэтому на узких экранах строка переносится как
   обычно, без white-space: nowrap. */
#invest > .wrap > .section__lead { max-width: none; }

/* Масштаб пэкшотов выровнен в самих файлах (tools/normalize_tiles.py):
   объект обрезан по своим границам, вписан в общий бокс и поставлен на общую
   базовую линию. Поэтому здесь никаких индивидуальных коэффициентов. */

/* ---------- блок «экономический эффект» на широкой панели (правка 08-11) ----------
   Раньше блок жил в узкой колонке; после перевода панелей во всю ширину поля,
   шкала и график растянулись в тонкие полосы. Здесь: поля в четыре столбца,
   итоги карточками, а запас прочности и график - рядом. */
.detail-stack .mc-fields { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.detail-stack .mc-out { gap: var(--space-4); }
.detail-stack .mc-out > div { background: var(--bg); border-radius: var(--radius-s);
  padding: var(--space-3) var(--space-4); }
.effect-cols { display: grid; grid-template-columns: minmax(280px, 380px) minmax(0, 1fr);
  gap: var(--space-5); align-items: start; margin-top: var(--space-4);
  border-top: 1px solid var(--border); padding-top: var(--space-4); }
.effect-cols .sens { margin: 0; }
@media (max-width: 900px) {
  .detail-stack .mc-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .effect-cols { grid-template-columns: minmax(0, 1fr); gap: var(--space-4); }
}

/* ---------- график накопленной экономии ---------- */
.pbc { min-width: 0; }
.pbc[hidden] { display: none; }
.pbc__t { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin: 0 0 var(--space-3);
  font: 600 14px/1.3 var(--font-body); }
.pbc__t b { font: 600 13px/1.3 var(--font-body); color: var(--accent); }
.pbc__box { position: relative; }
.pbc__svg { display: block; width: 100%; height: auto; touch-action: pan-y; cursor: crosshair; }
.pbc__grid { stroke: var(--border); stroke-width: 1; }
.pbc__tick { font: 400 11px/1 var(--font-body); fill: var(--text-3); }
.pbc__capex { stroke: var(--text-3); stroke-width: 1.5; stroke-dasharray: 6 5; }
.pbc__capex-label { font: 500 11px/1 var(--font-body); fill: var(--text-3); }
.pbc__fill { fill: var(--good); opacity: .14; }
.pbc__line { fill: none; stroke: var(--accent); stroke-width: 2.5; stroke-linejoin: round; }
.pbc__dot { fill: var(--accent); stroke: #fff; stroke-width: 2; }
.pbc__cursor { stroke: var(--text-3); stroke-width: 1; stroke-dasharray: 3 3; }
.pbc__hit { fill: var(--accent); stroke: #fff; stroke-width: 2; }
.pbc__tip { position: absolute; top: 6px; transform: translateX(-50%); pointer-events: none;
  background: var(--ink); color: #F2F5FA; border-radius: var(--radius-s); padding: 8px 11px;
  font: 400 12px/1.45 var(--font-body); white-space: nowrap; box-shadow: var(--shadow-lift); }
.pbc__tip[hidden] { display: none; }
.pbc__tip b { display: block; font: 700 13px/1.2 var(--font-mono); }
.pbc__tip span { display: block; color: rgba(242,245,250,.75); }
.pbc__legend { display: flex; gap: var(--space-3); flex-wrap: wrap; align-items: center;
  margin: var(--space-2) 0 0; font-size: 11px; color: var(--text-3); }
.pbc__key { width: 14px; height: 3px; border-radius: var(--r-xs); display: inline-block; }
.pbc__key--line { background: var(--accent); }
.pbc__key--capex { background: repeating-linear-gradient(90deg, var(--text-3) 0 4px, transparent 4px 7px); }
.pbc__key--fill { background: var(--good); opacity: .5; height: 10px; border-radius: var(--r-xs); }

/* На телефоне график сжимался до нечитаемого: даём ему собственную
   горизонтальную прокрутку вместо уменьшения подписей (08-11). */
@media (max-width: 760px) {
  .pbc__box { overflow-x: auto; }
  .pbc__svg { min-width: 460px; }
  .pbc__tip { white-space: normal; max-width: 220px; }
}


/* ---------- баннеры первого экрана в формате сториз ---------- */
.stories { position: relative; overflow: hidden; }
/* Пэкшоты лежат на белом и «вписываются» в страницу через mix-blend-mode:
   multiply. Трек с transform создаёт свой контекст наложения, поэтому смешивать
   белое ему не с чем - подкладываем фон сайта прямо под слайды (замечание №86). */
.stories__track { display: flex; background: var(--bg); align-items: flex-start;
  transition: transform .45s cubic-bezier(.4, 0, .2, 1), height .45s cubic-bezier(.4, 0, .2, 1); }
@media (prefers-reduced-motion: reduce) { .stories__track { transition: none; } }
/* overflow: картинка соседнего баннера не должна выезжать за границу своего
   слайда - анимация покачивания заступала на линию перехода.
   padding-bottom: нижняя плашка стоит вплотную к границе слайда, и overflow
   срезал её тень - плашка читалась обрезанной и слипалась с блоком поиска
   снизу (замечание заказчика 27.08). 16px хватает на тень карточки
   (--shadow-card: 4+14px). */
.story { flex: 0 0 100%; min-width: 100%; overflow: hidden; padding-bottom: var(--space-3); }
.story__t { font: 700 clamp(26px, 3.4vw, 44px)/1.1 var(--font-display); letter-spacing: -0.02em;
  margin: 0 0 var(--space-3); max-width: 18ch; }
/* Расстояние от нижней линии шапки до полосок индикации баннера сокращено на
   65% (правка заказчика 08.09): было 48px - 32px верхнего поля hero плюс 16px
   над полосками, стало 17px (11px + 6px). Поле hero режем только на первом
   экране (#hero есть лишь на главной), на остальных страницах hero прежний. */
#hero { padding-top: 11px; }
.stories__barwrap { padding-top: 6px; }
.stories__bars { display: flex; gap: 6px; }
.stories__bar { flex: 1; border: 0; background: none; padding: 0; cursor: pointer; height: 14px; }
.stories__bar > span { display: block; height: 3px; border-radius: var(--r-xs); background: var(--border);
  overflow: hidden; position: relative; }
.stories__bar.is-done > span { background: var(--accent); opacity: .45; }
.stories__bar.is-on > span::after { content: ''; position: absolute; inset: 0;
  background: var(--accent); transform-origin: left; animation: story-fill 15s linear forwards; }
@media (prefers-reduced-motion: reduce) {
  .stories__bar.is-on > span::after { animation: none; }
}
@keyframes story-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.stories__nav { position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 42px; height: 42px; border-radius: 50%; border: 1px solid var(--border);
  background: var(--white); color: var(--text); font-size: 18px; cursor: pointer;
  box-shadow: var(--shadow-card); opacity: 0; transition: opacity .2s ease; }
.stories:hover .stories__nav, .stories__nav:focus-visible { opacity: 1; }
/* Стрелки держатся за контентную колонку, а не за края экрана: на широких
   мониторах они стояли в полуметре от баннера (замечание заказчика 19.08). */
.stories__nav--prev { left: max(14px, calc(50% - var(--maxw) / 2 - 58px)); }
.stories__nav--next { right: max(14px, calc(50% - var(--maxw) / 2 - 58px)); }
@media (max-width: 900px) {
  /* стрелки-накладки перекрывали кнопки слайда: на узком экране листаем
     свайпом и полосками прогресса */
  .stories__nav { display: none; }
  .story__t { max-width: none; }
}

/* слайд с фотографией: снимок показываем карточкой, режим пэкшота
   (mix-blend-mode) фотографию бы затемнил */
.story__photo { display: flex; justify-content: center; align-items: center; }
/* высота как у пэкшотов, иначе фото-слайд растягивал всю карусель */
.story__photo img { width: 100%; max-width: 520px; max-height: 380px; aspect-ratio: 4/3;
  object-fit: cover; border-radius: var(--radius); box-shadow: var(--shadow-card); }

/* Слайд кейс-калькулятора: вместо снимка своя векторная сцена (js/illus.js).
   Фон у неё прозрачный, поэтому ни карточки, ни mix-blend-mode здесь нет -
   у трека сториз свой контекст наложения, blend в нём всё равно не работает.
   Высота сцены - во всю строку баннера (--media-h, см. блок про общую высоту
   ниже), запасное значение - как у рендера робота на первом баннере (323px,
   site.css). preserveAspectRatio в самой картинке ставит калькулятор по центру
   колонки и прижимает его к низу - как пэкшот на первом баннере. */
.story__art { display: flex; align-items: flex-end; }
.story__art svg { display: block; width: 100%; height: var(--media-h, 323px); }
@media (max-width: 980px) {
  /* в одну колонку сцена тянется по ширине, высоту держит пропорция холста */
  .story__art svg { height: auto; aspect-ratio: 520 / 323; }
}

/* ---------- кнопка раздела под карточками (замечания №102-№104) ---------- */
.sec-more { display: flex; justify-content: center; margin-top: var(--space-4); }
/* По просьбе заказчика переходы в раздел выглядят ссылкой, а не кнопкой:
   рамки и фона нет, подчёркивание только при наведении. Кегль 15/600 и
   отбивки 12px по вертикали остались от .btn - место ссылки не сдвинулось. */
.sec-more__link {
  display: inline-flex; align-items: center; gap: 8px; padding: 12px 22px;
  font: 600 15px/1.3 var(--font-body); color: var(--text); text-decoration: none;
}
.sec-more__link:hover { text-decoration: underline; }

/* ---------- отрасли и лента новостей на слайдах сториз ---------- */
/* Плитки цифр на первом баннере: иконка и текст стоят по центру плитки
   (правка заказчика 28.08). Раньше под подпись резервировались две строки
   13px/1.4 - столько занимает «экономический эффект от внедрённых решений».
   В плитках с однострочной подписью («120+ ИИ-решений») пустая вторая строка
   висела под текстом и тянула его вверх: иконка стояла по центру, а текст
   на 9px выше. Резерва больше нет - каждая плитка центрирует свою пару
   «иконка - текст» (центрирование само по себе идёт от .statrow > div в
   site.css, здесь оно закреплено явно, чтобы правку не потерять). Высота
   плашки от этого не меняется: её держит общий --bar-h (блок про общую высоту
   баннеров ниже). Цена решения: у плитки «388 млн ₽» подпись всё равно идёт
   в две строки, поэтому её цифра стоит чуть выше соседних - зато текст в
   каждой плитке ровно по центру, как просил заказчик. */
.hero .statrow > div { align-items: center; }

/* Ряд отраслей на баннере кейс-калькулятора (правка заказчика 28.08): вместо
   шагов 1-4 те же плитки, что в фильтре калькулятора на cases.html. Шесть
   равных долей во всю ширину баннера, у ряда нет ни своих полей, ни общей
   подложки - поэтому левый край первой плитки и правый край последней стоят
   ровно по краям баннера, как просил заказчик. Иконка вдвое крупнее, чем
   в фильтре (26px → 52px), подпись под ней. */
.story__inds { display: grid; grid-template-columns: repeat(6, 1fr);
  gap: var(--space-3); margin-top: var(--space-4); }
.story__ind { display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: var(--space-2); padding: var(--space-3) var(--space-2);
  background: var(--white); border-radius: var(--radius-s); box-shadow: var(--shadow-card);
  text-decoration: none; text-align: center; color: var(--text);
  font: 500 14px/1.25 var(--font-body); transition: box-shadow .15s ease, color .15s ease; }
.story__ind svg { width: 52px; height: 52px; color: var(--accent); }
.story__ind:hover { color: var(--accent); box-shadow: var(--shadow-lift); }
@media (max-width: 900px) {
  /* в одну колонку баннера шесть плиток в ряд становятся уже подписи */
  .story__inds { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 480px) {
  .story__inds { grid-template-columns: repeat(2, 1fr); gap: var(--space-2); }
  .story__ind svg { width: 40px; height: 40px; }
}
/* minmax(0, 1fr), а не 1fr: иначе длинное слово в тексте карточки раздвигает
   колонку, и ряд становится шире баннера (замечание про выросшую ширину). */
.story__news { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-3); margin-top: var(--space-4); }
/* Карточка новости по макету заказчика (замечание №166): миниатюра слева,
   справа дата, заголовок и ссылка «читать». Заголовок подрезан по строкам,
   высота двух строк зарезервирована - иначе карточки в ряду разъезжаются по
   высоте, а баннер прыгает при листании.
   Миниатюра и столбик текста стоят по центру по вертикали (правка заказчика
   28.08): что ниже - то и центрируется относительно соседа, по верхнему краю
   больше ничего не равняется. */
.story__ncard { display: flex; align-items: center; gap: var(--space-3);
  background: var(--white); border-radius: var(--radius-s); box-shadow: var(--shadow-card);
  padding: var(--space-3); text-decoration: none; color: var(--text); }
.story__nimg { flex: none; width: 76px; height: 76px; object-fit: cover;
  border-radius: var(--radius-s); background: #fff; border: 1px solid var(--border); }
/* Плитка-приглашение в ряду карточек площадки (баннер «Поиск партнёров»):
   витрины запросов заказчиков пока нет, придумывать чужие запросы нельзя,
   поэтому вместо миниатюры - пунктирный квадрат с плюсом. */
.story__nadd { display: grid; place-items: center; font-size: 26px; line-height: 1;
  color: var(--accent); border-style: dashed; border-color: var(--accent); }
/* Текст карточки набран плотнее (правка заказчика 27.08, та же просьба снизить
   высоту плашки): миниатюра осталась 76px, поэтому именно она теперь задаёт
   высоту карточки, а не столбик текста рядом. Две строки заголовка
   зарезервированы по-прежнему - иначе карточки в ряду разъезжаются. */
.story__nb { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 2px; }
.story__ncard b { font: 600 14px/1.35 var(--font-body);
  min-height: calc(2 * 1.35em); display: -webkit-box; -webkit-line-clamp: 2;
  -webkit-box-orient: vertical; overflow: hidden; }
.story__nd { font-size: 12px; line-height: 1.4; color: var(--text-3); }
.story__nmore { font: 400 13px/1.35 var(--font-body); color: var(--accent); }
/* Начало новости серым вместо надписи «читать» (правка заказчика 28.08).
   Строка ровно одна: line-clamp: 1 подрезает хвост многоточием, а высота
   совпадает со строкой «читать», поэтому карточка не подросла. Ширину держат
   min-width: 0 и перенос по словам - длинный текст не растягивает колонку. */
.story__nlead { font: 400 13px/1.35 var(--font-body); color: var(--text-3);
  min-width: 0; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical;
  overflow: hidden; }
/* Наведение на карточки-ссылки баннеров «Поиск партнёров» и «Экспертиза»
   (правка заказчика 28.08): блок оттеняется так же, как плитки отраслей на
   баннере кейс-калькулятора (.story__ind выше) - карточка приподнимается
   тенью, обводки нет. Текст цвет по-прежнему не меняет. */
.story__ncard, .story__fcard { transition: box-shadow .15s ease; }
.story__ncard:hover, .story__fcard:hover { box-shadow: var(--shadow-lift); }

/* Свежая публикация в правой колонке баннера вместо снимка (макет заказчика):
   снимок слева, справа дата, заголовок и лид. Лид подрезан по строкам, чтобы
   карточка не перерастала колонку с текстом слева. */
.story__feat { display: flex; align-items: center; }
.story__fcard { flex: 1; min-width: 0; display: flex; gap: var(--space-3);
  background: var(--white); border-radius: var(--radius); box-shadow: var(--shadow-card);
  padding: var(--space-3); text-decoration: none; color: var(--text); }
/* height: 100% срабатывает только там, где у карточки задана высота (широкая
   раскладка ниже); в остальных случаях снимок остаётся квадратным */
.story__fimg { flex: none; width: 48%; height: 100%; aspect-ratio: 1/1; object-fit: cover;
  border-radius: var(--radius-s); background: #fff; border: 1px solid var(--border); }
.story__fb { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 8px; }
.story__fcard b { font: 600 16px/1.35 var(--font-body); }
.story__flead { font: 400 14px/1.5 var(--font-body); color: var(--text-2);
  display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical; overflow: hidden; }
/* ссылка «читать» стоит внизу карточки, под текстом (правка заказчика) */
.story__fmore { margin-top: auto; }
/* Высота крупной карточки - 90% строки баннера (--media-h, блок про общую
   высоту ниже): заказчик просил снизить её на 10% (правка 28.08). Строка и сам
   баннер при этом не меняются - карточка ниже соседней колонки с текстом и
   стоит по центру строки (.story__feat выше). Запасное значение - как у рендера
   робота на первом баннере: там .hero__photo--render img ограничен 323px
   (site.css). Только в широкой раскладке: ниже 981px hero идёт одной колонкой,
   и карточка тянется по содержимому. */
@media (min-width: 981px) {
  .story__fcard { height: calc(var(--media-h, 323px) * 0.9); overflow: hidden; }
}

/* Общая высота у всех баннеров одинаковая (замечание заказчика 27.08).
   Слайды меряет js/hero-stories.js: высоту самой высокой нижней плашки кладёт
   в --bar-h, высоту самого высокого слайда - в --story-h, высоту строки
   «текст + картинка» - в --media-h. Каждый слайд дорастает до общей высоты,
   остаток забирает строка, а разницу добирает большое изображение справа -
   рендер, сцена калькулятора и карточка новости растут до высоты строки,
   поэтому под коротким баннером не появляется пустота.
   Значения в пикселях, а не в процентах: слайд должен меряться по своему
   содержимому, иначе замер и высота начинают зависеть друг от друга.
   min-height, а не height: если текст после подгрузки шрифтов станет выше,
   слайд вырастет, а не обрежется. Только в широкой раскладке: ниже 981px
   баннер идёт одной колонкой, и выравнивать по высоте нечего. */
@media (min-width: 981px) {
  .story { min-height: var(--story-h, 0); display: flex; flex-direction: column; }
  /* первый баннер лежит в разметке одним блоком (data-story-first) - колонку
     собираем и внутри него, иначе остаток высоты некуда отдать */
  .story > [data-story-first] { display: flex; flex-direction: column; flex: 1 1 auto; }
  .story .hero__grid { flex: 1 1 auto; }
  /* Слайд стал колонкой-флексбоксом, а у .wrap боковые поля auto. По правилам
     flexbox авто-поля по поперечной оси отменяют растягивание: полоса под
     баннером сжималась по своему содержимому и вставала уже баннера, а поля
     разводили её по центру. На баннере «Поиск партнёров» подписи карточек
     короткие, поэтому ряд не доходил до краёв баннера ни слева, ни справа
     (замечание заказчика 28.08). Ширину задаём явно: ограничение --maxw и
     поля .wrap остаются, поэтому полоса встаёт ровно по контентной колонке. */
  .story > .wrap, .story > [data-story-first] > .wrap { width: 100%; }
  /* рендер робота: обёртка остаётся по картинке, поэтому подписи ТТХ, которые
     расставлены в процентах от неё, держатся на своих местах */
  .story .hero__photo--render img { max-height: var(--media-h, 323px); }
  /* Нижняя плашка - одной высоты на всех баннерах (--bar-h): цифры компании,
     ряд отраслей и ряды карточек площадки и новостей меряются по содержимому,
     самая высокая задаёт высоту остальным. Без выравнивания плашки баннеров
     расходились по высоте, и при листании низ баннера прыгал. Строки внутри
     плашки растягиваются вместе с ней (align-content по умолчанию), ячейка
     остаётся по центру. min-height, а не height: текст не должен обрезаться,
     если строка перенесётся. */
  .story .statrow, .story .story__news, .story .story__inds { min-height: var(--bar-h, 0); }
  /* Карточка ленты дорастает до общей плашки. Раньше добавленную высоту
     забирали растяжкой: миниатюра оставалась вверху, а ссылку «читать»
     прижимали к низу. Заказчик просил обратное (правка 28.08) - миниатюра и
     текст стоят по центру, поэтому остаток высоты делится поровну сверху и
     снизу, а растяжки здесь больше нет (align-items: center выше). */
}
@media (max-width: 900px) {
  /* в одну колонку карточка становится широкой: миниатюру увеличиваем, как
     в ленте новостей */
  .story__news { grid-template-columns: 1fr; }
  .story__nimg { width: 132px; height: 96px; }
}
@media (max-width: 640px) {
  /* на телефоне выравнивать в ряду нечего, поэтому заголовок показываем
     целиком (тот же приём, что в ленте новостей), а миниатюру уменьшаем -
     иначе три карточки подряд растягивают первый экран */
  .story__nimg { width: 96px; height: 76px; }
  .story__ncard b { display: block; -webkit-line-clamp: none; overflow: visible; min-height: 0; }
  /* у крупной карточки снимок над текстом: в 48% ширины на телефоне он
     превращается в марку */
  .story__fcard { flex-direction: column; }
  .story__fimg { width: 100%; aspect-ratio: 16/9; }
}

/* ---------- поисковый слой: строка под шапкой, фильтры холдером ----------
   При активации поиск раскрывается на всю страницу (замечания №117, №118):
   строка закреплена под шапкой сайта, ниже выдача, а фильтры раскрываются
   холдером над карточками (правка Петра Костина). */
/* --ss-top (высота шапки) считает js/smart-search.js по факту и обновляет, пока
   слой открыт: шапка бывает разной высоты - объявление над меню закрывается, на
   узком экране меню переносится на вторую строку. Значения в скобках - запасные,
   на первый кадр. Полоса прокрутки у слоя зарезервирована всегда
   (scrollbar-gutter): без неё короткая выдача сдвигала строку поиска
   относительно шапки на ширину полосы. */
.sslayer { position: fixed; left: 0; right: 0; top: var(--ss-top, 68px); bottom: 0; z-index: 45;
  background: var(--bg); overflow-y: auto; overscroll-behavior: contain;
  scrollbar-gutter: stable; }
.sslayer[hidden] { display: none; }
/* Страница под слоем заблокирована, и вместе с блокировкой у неё пропадает
   полоса прокрутки - страница вместе с шапкой прыгала вправо на её ширину.
   Ширину возвращаем отступом (--ss-sbw ставит js), а шапке компенсируем его
   отрицательным полем: фон и нижняя линия остаются во всю ширину, а меню
   внутри стоит на месте (правка заказчика: шапка не должна двигаться). */
body.sslayer-open { overflow: hidden; padding-right: var(--ss-sbw, 0px); }
body.sslayer-open > #site-header { margin-right: calc(0px - var(--ss-sbw, 0px));
  padding-right: var(--ss-sbw, 0px); }
/* Листаем выдачу вниз - шапка с поиском уезжает вверх, а слой поднимается к
   верхнему краю окна: на месте шапки оказывается липкий ряд фильтров
   (замечание Петра Костина). Класс sslayer-up ставит js/smart-search.js по
   направлению прокрутки слоя; вверх - шапка возвращается. */
body.sslayer-open > #site-header { transition: transform .22s ease; }
body.sslayer-up > #site-header { transform: translateY(-100%); }
.sslayer { transition: top .22s ease; }
body.sslayer-up .sslayer { top: 0; }
@media (prefers-reduced-motion: reduce) {
  body.sslayer-open > #site-header, .sslayer { transition: none; }
}
/* Непрозрачный фон --bg закрывает выдачу, проезжающую под строкой, а под
   нижней границей блока лежит небольшая тень (правка Петра Костина). Серую
   линию под фильтрами убрали по его же просьбе, границу ряда держит одна
   тень, а нижний отступ вернулся блоку. */
.sslayer__bar { position: sticky; top: 0; z-index: 3; background: var(--bg);
  padding: var(--space-3) 0; box-shadow: 0 6px 10px -6px rgba(16, 24, 40, .14); }
/* Строка поиска закреплена в шапке (правка заказчика), в ряду остались одни
   фильтры. Пока их нет, ряду нечего показывать: схлопываем его, иначе над
   выдачей висела бы пустая полоса с тенью. */
.sslayer__bar:not(:has(.sslayer__quick:not([hidden]))) { padding: 0; box-shadow: none; }
/* быстрые сортировки закреплены вместе со строкой поиска, а не уезжают с
   карточками (правка заказчика). Отступа слева больше нет: кнопка возврата
   уехала внутрь строки, и сортировки встают по левому краю карточки поиска. */
.sslayer__quick { padding-top: var(--space-2); display: flex; flex-wrap: wrap;
  align-items: center; gap: var(--space-2); }
.sslayer__quick[hidden] { display: none; }
.sslayer__quick .ss-sort, .sslayer__quick .ss-kinds { margin: 0; }
/* сортировки прячутся, когда сортировать нечего, а разделы и фильтры остаются:
   у .ss-sort, .ss-kinds и .ssfd свой display:flex, и атрибут hidden без
   правила ниже их не убирает */
.sslayer__quick .ss-sort[hidden], .sslayer__quick .ss-kinds[hidden],
.sslayer__quick .ssfd[hidden] { display: none; }
/* Колонка одна: фильтры не стоят ни слева, ни холдером над выдачей - они
   разъехались по кнопкам с выпадающими списками в закреплённом ряду под
   строкой поиска (правка Петра Костина). Карточкам осталась вся ширина слоя.
   Верхний край карточек отбит от нижней границы ряда фильтров: раньше выдача
   начиналась вплотную к тени и первая карточка с подписью группы выглядела
   подрезанной рядом (замечание Петра Костина). Отступ был увеличен до высоты
   всего ряда, но по просьбе разработчика вернулся к прежним 24px. */
.sslayer__grid { display: grid; grid-template-columns: minmax(0, 1fr);
  gap: var(--space-3); align-items: start; padding-top: var(--space-4);
  padding-bottom: var(--space-6); }
/* Прокрутка по элементу (подпись группы, карточка) не должна оставлять его под
   закреплённым рядом фильтров: высоту ряда js/smart-search.js меряет по факту и
   отдаёт переменной --ss-bar (уточнение разработчика). */
.sslayer { scroll-padding-top: calc(var(--ss-bar, 0px) + var(--space-4)); }
.sslayer__main { min-width: 0; }
/* «Есть что предложить?» - последним в слое, как в конце каталога роботов
   (замечание Петра Костина). Отступ сверху даёт padding-bottom самой выдачи,
   снизу блок отбивается сам, чтобы не упирался в край слоя. */
.sslayer__offer { padding-bottom: var(--space-6); }
/* Подвал переезжает в конец слоя (замечание Петра Костина): под слоем свой
   подвал не виден. Отбивка между блоком и подвалом - как на главной: там
   «Есть что предложить?» лежит в .section с нижним отступом --space-7, а
   дальше подвал добавляет свой --space-6 (уточнение разработчика). */
.sslayer__offer:has(+ .footer) { padding-bottom: var(--space-7); }
/* Выдача заняла всю ширину слоя, поэтому в ряду четыре карточки вместо трёх
   (правка Петра Костина). Сужаем ряд теми же ступенями, что и каталог:
   селектор из двух классов сильнее .prodgrid--3 на любом экране. */
.sslayer .prodgrid, .sslayer .cardgrid { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1100px) {
  .sslayer .prodgrid, .sslayer .cardgrid { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 780px) {
  .sslayer .prodgrid, .sslayer .cardgrid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .sslayer .prodgrid, .sslayer .cardgrid { grid-template-columns: minmax(0, 1fr); }
}
/* Появление по прокрутке в слое не играет: выдача обязана быть видна сразу.
   Наблюдатель из motion.js внутри перерисовываемого фильтрами списка то и
   дело оставлял карточки на opacity:0 - здесь его эффект просто выключен. */
.sslayer [data-rv] { opacity: 1 !important; transform: none !important; }

/* ---------- «рассчитайте свой кейс» перед карточками (замечание №98) ---------- */
.sscta { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center;
  gap: 2px 12px; width: 100%; text-align: left; cursor: pointer;
  /* заливка и обводка - как у строки поиска выше (.ssearch__bar): белая карточка
     с тенью и радиусом --radius, без пунктирной акцентной рамки (правка заказчика) */
  background: var(--white); border: 0; box-shadow: var(--shadow-card);
  border-radius: var(--radius); padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-3); font: inherit; color: inherit; }
/* Иконка калькулятора перед текстом (правка заказчика): рисунок и обводка те же,
   что у плиток отраслей на баннере кейс-калькулятора (.story__ind). Высота -
   ровно по тексту: иконка занимает обе строки сетки и растянута по ним, то есть
   от верхней кромки заголовка до нижней кромки подписи. Ширина задана числом,
   а не долей от высоты: рисунок без своих размеров иначе попадает в расчёт
   дорожек сетки как 300px и раздувает и колонку, и высоту кнопки.
   Селектор с двумя классами - чтобы правило .sscta span ниже не забрало
   иконку во вторую строку: она тоже span. */
.sscta .sscta__ico { grid-column: 1; grid-row: 1 / span 2; align-self: stretch;
  width: 64px; color: var(--accent); }
.sscta__ico svg { display: block; width: 100%; height: 100%; }
.sscta b { grid-column: 2; grid-row: 1; font: 600 16px/1.3 var(--font-display); }
.sscta span { grid-column: 2; grid-row: 2; font-size: 13px; color: var(--text-2); }
.sscta i { grid-column: 3; grid-row: 1 / span 2; font-style: normal; font-size: 20px;
  color: var(--accent); }
/* на узком экране подпись занимает всю ширину, поэтому иконка уже - так же,
   как ужимаются иконки плиток отраслей */
@media (max-width: 480px) { .sscta .sscta__ico { width: 40px; } }
/* рамки больше нет, поэтому наведение подсвечивает карточку тенью */
.sscta:hover { box-shadow: var(--shadow-lift); }
.sscta[aria-expanded="true"] i { transform: rotate(90deg); }
.sspick { margin-bottom: var(--space-3); }
.sspick__f { display: grid; gap: 6px; font-size: 13px; color: var(--text-2); }
/* отрасль - плитками, а не списком (замечание Петра Костина): на плитке иконка
   отрасли и название. Сами плитки - общие с кейсами, .indtile в site.css */
.sspick__inds { margin-bottom: var(--space-3); }
.sspick__inds .indtiles { grid-template-columns: repeat(auto-fit, minmax(116px, 1fr)); gap: 10px; }
.sspick__inds .indtile { padding: 12px 8px 10px; gap: 8px; }
.sspick__inds .indtile svg { width: 22px; height: 22px; }
/* плитки отрасли здесь - кнопки, а не ссылки, поэтому курсор задаём явно:
   иначе на них остаётся стрелка (замечание Петра Костина) */
.sspick .indtile { cursor: pointer; transition: background-color .15s ease; }
/* ни наведение, ни выбор плитку не обводят: рамка остаётся обычной, тени нет,
   наведение только едва оттеняет фон (замечание Петра Костина) */
.sspick .indtile:hover { border-color: var(--border); box-shadow: none; }
.sspick .indtile:hover:not([aria-pressed="true"]) { background: var(--surface-2); }
/* выбранная плитка здесь заливается светло-синим - тем же --accent-soft, что
   и фон блока с калькулятором ниже (замечание Петра Костина). На cases.html
   выбор остаётся тёмным, поэтому правило заведено внутри .sspick.
   border-color возвращаем к обычному: без него плитку обводит тёмная рамка
   общего правила .indtile[aria-pressed="true"] из site.css */
.sspick .indtile[aria-pressed="true"] { background: var(--accent-soft);
  border-color: var(--border); color: var(--text); }
/* кейс - тоже плитками: кадр процесса из карточки кейса, название и суть.
   Колонок столько, сколько плиток при фильтре «все отрасли» (не больше пяти):
   выбор отрасли прячет лишние плитки, а ширина оставшихся не меняется
   (замечание Петра Костина). Число колонок приходит из smart-search.js. */
.sspick__cases { margin-bottom: var(--space-3); }
.casetiles { display: grid; grid-template-columns: repeat(var(--casetiles-n, 5), minmax(0, 1fr)); gap: 10px; }
.casetile { display: flex; flex-direction: column; gap: 6px; text-align: left; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-s);
  padding: 0 0 12px; overflow: hidden; font: inherit; color: var(--text);
  transition: background-color .15s ease; }
/* без этого правила плитка с display:flex не прячется по атрибуту hidden */
.casetile[hidden] { display: none; }
/* кадр процесса вдвое ниже прежнего (270 → 135) и фиксирован по высоте, чтобы
   плитки не менялись при фильтре (замечание Петра Костина). Высоту задаём явно:
   у img в разметке есть атрибуты width/height, и без правила высоту диктует
   height="270", а не пропорция */
.casetile img { display: block; width: 100%; height: 135px; aspect-ratio: auto; object-fit: cover; }
.casetile b { padding: 8px 10px 0; font: 600 13px/1.25 var(--font-body); }
.casetile span { padding: 0 10px; font-size: 12px; line-height: 1.35; color: var(--text-2); }
/* наведение не обводит плитку и не поднимает её тенью, а едва оттеняет фон
   (замечание Петра Костина) */
.casetile:hover:not([aria-pressed="true"]) { background: var(--surface-2); }
/* выбранный кейс - такая же светло-синяя заливка, как у плитки отрасли, тоже
   без обводки */
.casetile[aria-pressed="true"] { background: var(--accent-soft);
  color: var(--text); }
.casetile[aria-pressed="true"] span { color: var(--text-2); }
@media (max-width: 700px) {
  .sspick__inds .indtiles { grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); }
  /* на узком экране колонок меньше, но auto-fill держит их ширину при фильтре */
  .casetiles { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
}

/* ---------- одна высота изображений во всех блоках лендинга ----------
   За образец взят первый блок «Робототехника»: колонка 386 px при пропорции
   4/3 даёт кадр 290 px. У блоков разное число колонок (решения и кейсы - 3,
   шаги консалтинга - 5), поэтому высота задана явно, а не пропорцией:
   иначе картинки снова разъезжаются по высоте. */
#landing-prods .prod__media,
#match-prods .prod__media,
#landing-solutions .mcard__media,
#landing-cases .mcard__media,
#match-sols .mcard__media,
#journey .jstep--big img { aspect-ratio: auto; height: 290px; }
/* на телефоне колонки узкие: кадр ниже, но общий для всех блоков */
@media (max-width: 640px) {
  #landing-prods .prod__media,
  #match-prods .prod__media,
  #landing-solutions .mcard__media,
  #landing-cases .mcard__media,
  #match-sols .mcard__media,
  #journey .jstep--big img { height: 200px; }
}


/* партнёрские карточки в разделах решений и кейсов (кабинет партнёра, модерация) */
.partner-cards { display: grid; gap: var(--space-4); }
.partner-card { padding: var(--space-5); }
/* изображение карточки слева от текста (флоу карточек 06.09, строка 1):
   фото поставщика или заглушка на белом фоне, кадр общий для всех карточек */
.partner-card { display: grid; grid-template-columns: minmax(180px, 280px) 1fr; gap: var(--space-4); align-items: start; }
.partner-card__media { display: block; border-radius: var(--radius-s); overflow: hidden; background: #fff;
  border: 1px solid var(--border); }
.partner-card__media img { display: block; width: 100%; height: auto; aspect-ratio: 4/3; object-fit: contain; padding: var(--space-2); }
.partner-card__body { min-width: 0; }
.partner-card__t { margin: 6px 0 8px; font-size: 22px; }
.partner-card__t a { color: inherit; text-decoration: none; }
.partner-card__t a:hover { color: var(--accent); }
.partner-card__d { margin: 0 0 var(--space-2); }
.partner-card__chips { margin: var(--space-2) 0; }
.partner-card__price { font: 700 18px/1.3 var(--font-display); margin: var(--space-2) 0 4px;
  color: var(--accent); }
@media (max-width: 640px) { .partner-card { grid-template-columns: 1fr; } }
/* страница карточки партнёра: галерея слева, описание и цена справа */
.partner-detail .panel { min-width: 0; }
/* ссылки на решения и кейсы партнёров в блоке связей: картинка, название, цена */
.partner-links { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); margin-top: var(--space-3); }
.partner-link { display: grid; grid-template-columns: 120px 1fr; gap: var(--space-3); align-items: start;
  padding: var(--space-3); background: var(--white); border-radius: var(--radius); box-shadow: var(--shadow-card);
  text-decoration: none; color: inherit; }
.partner-link:hover .partner-link__t { color: var(--accent); }
.partner-link__img { display: block; width: 100%; height: auto; aspect-ratio: 4/3; object-fit: contain; background: #fff;
  border: 1px solid var(--border); border-radius: var(--radius-s); }
.partner-link__b { display: grid; gap: 4px; min-width: 0; }
.partner-link__t { font: 600 16px/1.3 var(--font-display); }
.partner-link__d { font-size: 13px; color: var(--text-2); }
.partner-link__p { font: 600 14px/1.3 var(--font-body); }
@media (max-width: 640px) { .partner-links { grid-template-columns: 1fr; } }
/* калькулятор эффективности карточки партнёра (partner-calc.js) */
.pcalc__fields { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.pcalc .mc-field span i { display: block; font-style: normal; color: var(--accent); }
.pcalc__formula { margin: var(--space-2) 0 0; padding-left: 18px; font-size: 12px; color: var(--text-2); }
.pcalc__formula li { margin: 2px 0; }
@media (max-width: 640px) { .pcalc__fields { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* видео поставщика в галерее: свои кнопки, кадр как у снимка */
.gal__slide video, .gal__thumb video { display: block; width: 100%; height: auto; aspect-ratio: 16/11;
  max-height: 460px; object-fit: cover; background: #000; }
.gal__thumb video { pointer-events: none; }
.galview__video { margin: auto; max-width: 100%; max-height: 100%; background: #000; }
@media (min-width: 981px) {
  .detail__gal .gal__slide > video { position: absolute; inset: 0; height: 100%; aspect-ratio: auto; max-height: none; }
}
.partner-card__dl { display: grid; grid-template-columns: max-content 1fr; gap: 6px 16px; margin: 12px 0; }
.partner-card__dl dt { color: var(--text-2); font-size: 14px; }
.partner-card__dl dd { margin: 0; }
@media (max-width: 640px) { .partner-card__dl { grid-template-columns: 1fr; } }

/* карточка-кейс партнёра (06.09): ссылки на решения и капча в формах */
.partner-card__links { margin: var(--space-3) 0 0; padding-left: 18px; }
.partner-card__links li { margin: 4px 0; }
