/*
 * Правки темы поверх вёрстки.
 *
 * Файлы в assets/css/ и ui-kit/ принадлежат верстальщику и пересобираются
 * его скриптом — свои правила держим отдельно, иначе они пропадут при
 * следующей сборке. Этот файл подключается последним.
 *
 * Каждое правило — с объяснением, почему оно понадобилось. Если причина
 * исчезнет (например, верстальщик учтёт её у себя), правило нужно удалить,
 * а не оставлять «на всякий случай».
 */

/*
 * Ссылка «Перейти к содержимому» нужна для клавиатуры, но класса под неё
 * в UI-ките нет — без стиля она просто висела текстом наверху страницы.
 */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 12px 20px;
  background: var(--color-surface);
  color: var(--color-primary);
  border-radius: 0 0 8px 0;
}

.skip-link:focus {
  left: 0;
}

/*
 * Фотографии товаров вписываем целиком, а не кадрируем.
 *
 * В макете снимки были подготовлены заранее — обрезаны ровно под рамку
 * карточки, и cover ничего не портил. Настоящие фотографии приходят из 1С
 * и с versmet.ru в произвольных пропорциях: у высокого стеллажа cover
 * срезает верх и низ, у широкого верстака — бока, и от изделия остаётся
 * фрагмент, по которому его не узнать. Поэтому здесь contain: поле вокруг
 * снимка лучше, чем обрезанное изделие.
 *
 * Сюжетные фотографии (галерея, проекты, блог, обложки страниц) оставлены
 * с cover: там кадрирование как раз уместно — снимок должен заполнить
 * прямоугольник целиком.
 */
.product-card__img,
.subcategory-card__img,
.catalog-menu__img,
.quickview__img,
.quickview__thumb img,
.cart-item__img,
.config-card__img,
.variety-swatch__img,
.pdp-gallery__img,
.pdp-gallery__thumb img,
.pdp-lightbox__img {
  object-fit: contain;
}

/*
 * Ссылка вокруг снимка в карточке — наша: в макете картинка не кликалась.
 * Без размеров она сжимается по содержимому, и height:100% у картинки
 * упирается в неопределённую высоту. Растягиваем ссылку на всю рамку,
 * тогда снимок вписывается в неё, а не в свой собственный размер.
 */
.product-card__media > a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.product-card__media > a > .product-card__img {
  width: 100%;
  height: 100%;
}

/*
 * Скрытый счётчик должен быть скрыт.
 *
 * Счётчики в шапке рисуются всегда — их обновляет скрипт, когда меняется
 * корзина или избранное, — а пустой прячется атрибутом hidden. Но правило
 * .badge-counter{display:inline-flex} из UI-кита сильнее того display:none,
 * который браузер даёт [hidden] по умолчанию, и над «Корзиной» висел
 * оранжевый нолик.
 */
.badge-counter[hidden] {
  display: none;
}

/*
 * Одинаковый отступ сверху у всех страниц.
 *
 * В вёрстке он у каждой страницы свой и лежит на крошках: у большинства
 * 34 px, а у галереи 66 px и у каталога 65 px — ровно вдвое больше.
 * По просьбе заказчика приводим к общему значению; расхождение с макетом
 * намеренное, и если верстальщик поправит у себя, это правило нужно убрать.
 *
 * Только на широких экранах: с 1023 px и ниже вёрстка и так даёт 35 px.
 */
@media (min-width: 1024px) {
  .gallery-page__crumbs,
  .catalog-head {
    padding-top: 34px;
  }
}

/*
 * Исполнения и документы — ссылки, а не кнопки.
 *
 * В вёрстке это <button>: макет переключал исполнение на клиенте. У нас
 * каждое исполнение — отдельный товар со своим адресом, а документ —
 * файл, поэтому там ссылки. Подчёркивание от ссылки здесь лишнее.
 */
.variety-swatch,
.config-card,
.pdp-doc-tile {
  text-decoration: none;
}

/*
 * Раскрытое описание не обрезаем.
 *
 * В вёрстке у раскрытого описания max-height 400 px — ровно под текст
 * макета. Настоящие описания из 1С бывают вдвое длиннее, и часть текста
 * пропадала бы без следа.
 */
.pdp-summary__desc.is-expanded {
  max-height: none;
}

/*
 * Описание — блок, а не абзац: в нём бывают списки, а <ul> внутри <p>
 * недопустим. Внутренние отступы делаем как у абзаца в макете.
 */
.pdp-summary__desc > :first-child {
  margin-top: 0;
}

.pdp-summary__desc > :last-child {
  margin-bottom: 0;
}

/*
 * Форма отзыва без скрипта.
 *
 * В вёрстке её показывал только скрипт, и без него кнопка «Оставить отзыв»
 * не делала ничего. Кнопка и крестик стали ссылками, а открытие держится
 * на :target — скрипт, когда он есть, переход по якорю отменяет.
 */
.review-form-backdrop:target {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

/*
 * Один снимок — во всю ширину колонки.
 *
 * В вёрстке слева от фотографии стоит лента миниатюр, а ширина самой
 * фотографии ограничена 690 px. Миниатюры показываются, только когда есть
 * что листать, — а таких товаров 39 из 1847 с фотографией. У остальных
 * слева оставалась пустая полоса в 133 px, и снимок висел, не совпадая
 * с левым краем страницы.
 *
 * Высоту это не удорожает: правая колонка всё равно выше галереи.
 * Только на широких экранах — ниже 1024 px лента и так превращается в точки.
 */
@media (min-width: 1024px) {
  .pdp-gallery--wide .pdp-gallery__media,
  .pdp-gallery--wide .pdp-gallery__copyright {
    max-width: none;
  }
}

/*
 * «Показать все» в фильтрах.
 *
 * В вёрстке это ссылка, и стиль .filters__show-all рассчитан на неё: ни
 * сброса рамки, ни шрифта там нет. У нас стояла <button>, и она приезжала
 * с собственным оформлением браузера — серым фоном, рамкой и чужим
 * шрифтом. Теперь это <label> при скрытом флажке: выглядит как в макете,
 * а список раскрывается правилом ниже — без скрипта.
 */
.filters__show-all-toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  opacity: 0;
  pointer-events: none;
}

.filters__show-all {
  cursor: pointer;
}

.filter-section__body .checkbox--extra {
  display: none;
}

.filters__show-all-toggle:checked ~ .checkbox--extra {
  display: inline-flex;
}

/* Список раскрыт — предлагать раскрыть его больше нечего. */
.filters__show-all-toggle:checked ~ .filters__show-all {
  display: none;
}

/* Флажок не виден, поэтому рамку фокуса рисуем на подписи. */
.filters__show-all-toggle:focus-visible ~ .filters__show-all {
  outline: 2px solid var(--color-primary);
  outline-offset: 3px;
}

/*
 * Снимок в строке корзины.
 *
 * В design-2 снимок лежит в обёртке .cart-item__media, её высоту задаёт
 * aspect-ratio, а у картинки height: 100%. WordPress проставляет тегу <img>
 * атрибуты width и height — реальные размеры файла, и у вертикального
 * превью атрибут вытягивал бы картинку. Правило класса сильнее атрибута,
 * но только пока оно есть — держим его явно.
 */
.cart-item__media .cart-item__img {
  height: 100%;
}

/*
 * Название позиции ведёт на товар — в вёрстке это просто текст, поэтому
 * ссылку приводим к его виду.
 */
.cart-item__title a {
  color: inherit;
  text-decoration: none;
}

/*
 * Количество — поле ввода, а не подпись.
 *
 * В вёрстке между кнопками стоит <span>, у нас <input>: без скрипта
 * количество должно быть исправимо руками. Пустое поле ввода занимает
 * ширину по умолчанию (около 180 px) и растягивало степпер на треть строки.
 */
input.cart-item__stepper-value {
  width: 56px;
  border: 0;
  text-align: center;
  font-family: var(--font-family);
  -moz-appearance: textfield;
  appearance: textfield;
}

input.cart-item__stepper-value::-webkit-outer-spin-button,
input.cart-item__stepper-value::-webkit-inner-spin-button {
  margin: 0;
  -webkit-appearance: none;
  appearance: none;
}

/*
 * Форма заказа: переключатели-таблетки.
 *
 * В вёрстке это <button> и класс tab-pill--active, который ставит скрипт.
 * У нас за ними стоят настоящие радиокнопки: выбор уходит на сервер вместе
 * с формой, и переключение работает без JavaScript. Сам ввод не виден, но
 * доступен с клавиатуры — рамку фокуса рисуем на таблетке.
 */
.checkout-form__pill-input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  opacity: 0;
  pointer-events: none;
}

.checkout-form__toggle .tab-pill:has(.checkout-form__pill-input:checked) {
  background: var(--color-primary);
  border-color: transparent;
  color: var(--color-text-invert);
}

.checkout-form__toggle .tab-pill:has(.checkout-form__pill-input:focus-visible) {
  outline: 2px solid var(--color-primary);
  outline-offset: 3px;
}

/*
 * Что показывать — решает отмеченная таблетка.
 *
 * Адрес нужен только при доставке, реквизиты — только юрлицу. Скрываем их
 * правилом, а не скриптом: с выключенным JavaScript человек увидит лишние
 * поля, но заполнить и отправить форму сможет.
 */
.checkout-form [data-delivery-address],
.checkout-form [data-requisites-section] {
  display: none;
}

.checkout-form:has(input[name="versmet_delivery"][value="delivery"]:checked) [data-delivery-address] {
  display: grid;
}

.checkout-form:has(input[name="versmet_delivery"][value="delivery"]:checked) [data-pickup-address] {
  display: none;
}

.checkout-form:has(input[name="versmet_buyer_type"][value="company"]:checked) [data-requisites-section] {
  display: block;
}

/* Список способов оплаты — без маркеров и отступов списка. */
.checkout-form .payment_methods {
  margin: 0;
  padding: 0;
  list-style: none;
}

/*
 * Сообщения WooCommerce.
 *
 * «Товар добавлен в корзину», «Заполните поле» и прочие ответы сервера
 * выводит WooCommerce своей разметкой, а в вёрстке такого компонента нет:
 * сообщения приезжали системным шрифтом с рамкой браузера. Приводим их
 * к виду плашки из сводки заказа — синей для обычных, красной для ошибок.
 */
.woocommerce-message,
.woocommerce-info,
.woocommerce-error,
.woocommerce-notices-wrapper .woocommerce-message,
.woocommerce-notices-wrapper .woocommerce-info,
.woocommerce-notices-wrapper .woocommerce-error {
  margin: 0 0 16px;
  padding: 16px;
  border: 0;
  border-radius: 16px;
  background: var(--color-surface-blue);
  color: var(--color-dark);
  font-size: 16px;
  line-height: 1.4;
  list-style: none;
}

.woocommerce-error {
  background: #fff1f1;
  color: var(--color-danger);
}

.woocommerce-message li,
.woocommerce-info li,
.woocommerce-error li {
  list-style: none;
}

.woocommerce-message li + li,
.woocommerce-info li + li,
.woocommerce-error li + li {
  margin-top: 8px;
}

.woocommerce-message a,
.woocommerce-info a,
.woocommerce-error a {
  color: inherit;
}

/* Кнопки внутри сообщений WooCommerce уводят в корзину — оформляем ссылкой. */
.woocommerce-message .button,
.woocommerce-info .button {
  display: inline-block;
  margin-left: 8px;
  color: var(--color-primary);
  text-decoration: none;
  border-bottom: 1px solid var(--color-primary);
}

/*
 * WooCommerce переводит фокус на сообщение (tabindex="-1", role="alert"),
 * чтобы его прочитала озвучка. Браузер рисует вокруг такого элемента чёрную
 * системную рамку — для мыши она лишняя, а для клавиатуры пусть будет своей.
 */
.woocommerce-message:focus:not(:focus-visible),
.woocommerce-info:focus:not(:focus-visible),
.woocommerce-error:focus:not(:focus-visible) {
  outline: none;
}

.woocommerce-message:focus-visible,
.woocommerce-info:focus-visible,
.woocommerce-error:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/*
 * Вкладки рубрик в сравнении — ссылки, а не кнопки.
 *
 * В вёрстке рубрику переключал скрипт, поэтому там <button>. У нас рубрика
 * выбирается адресом (?group=…), чтобы переключение работало без скрипта, —
 * и ссылка приносит с собой подчёркивание, которого в макете нет.
 */
.comparison-categories__track .tab-pill {
  text-decoration: none;
}

/*
 * «В наличии» в избранном — ссылка в разметке переключателя.
 *
 * В вёрстке это <label> с флажком, который слушал скрипт. У нас отбор живёт
 * в адресе, чтобы страница работала без JavaScript, и на месте label стоит
 * ссылка — со всем, что ссылка приносит: цветом и подчёркиванием.
 */
.favorites-toolbar__stock {
  color: inherit;
  text-decoration: none;
}

/*
 * Положение «включено». В ките его задаёт :checked у настоящего флажка,
 * здесь флажка нет — берём то же оформление по aria-checked.
 */
.favorites-toolbar__stock[aria-checked="true"] .switch__handle {
  transform: translateX(22px);
  background: var(--color-primary);
}

.favorites-toolbar__stock:focus-visible .switch__track {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/*
 * Названия в прайсе ведут на товар.
 *
 * В вёрстке это просто текст, но список из шести тысяч позиций без ссылок
 * бесполезен — по названию хочется перейти в карточку. Оформление оставляем
 * текстовым, чтобы таблица не рябила синим.
 */
.price-table .data-table__name a,
.price-card .data-row__title a {
  color: inherit;
  text-decoration: none;
}

.price-table .data-table__name a:hover,
.price-card .data-row__title a:hover {
  color: var(--color-primary);
}

/* Ссылка «Все N товаров раздела» стоит рядом с «Развернуть». */
.price-group__all {
  align-self: flex-start;
  margin-left: 14px;
  font-size: 14px;
  font-weight: 500;
}

/*
 * Отступ пагинации в прайсе.
 *
 * В макете прайс выведен целиком, без страниц, поэтому места для пагинации
 * там не предусмотрено — у нас она есть, и без отступа сверху номера страниц
 * прилипают к карточке с таблицами. Снизу отступа не даём: пагинация стоит
 * последней, и за неё отвечает нижний отступ самой страницы — иначе до
 * подвала выходило 224 px вместо 160, как на остальных страницах.
 */
.price-page__pagination {
  display: flex;
  justify-content: flex-start;
  margin: 32px 0 0;
}

.price-page__pagination:empty {
  margin: 0;
}

/*
 * Логотипы перевозчиков.
 *
 * В вёрстке они нарисованы прямо в разметке, и у каждого свой размер. У нас
 * это загруженные картинки, поэтому размер задаётся по форме логотипа:
 * широкий занимает плитку по ширине, квадратный — 64 px. object-fit меняем
 * на contain: cover обрезал бы вытянутые логотипы.
 */
.payment-partners__logo {
  object-fit: contain;
}

.payment-partners__item--lg .payment-partners__logo {
  width: 100%;
  height: auto;
  max-height: 48px;
}

/*
 * Рубрики блога — ссылки, а не кнопки.
 *
 * В вёрстке рубрику переключал скрипт, у нас она в адресе, чтобы лента
 * работала без JavaScript. Ссылка приносит подчёркивание, которого в макете
 * нет.
 */
.blog-filters__track .tab-pill,
.stocks-filters__track .tab-pill {
  text-decoration: none;
}

/*
 * Подпись на плитке раздела — не больше трёх строк.
 *
 * В вёрстке подпись короткая, и высоту плитки держит картинка. Текст
 * пишет заказчик, и длинная фраза выдавливает картинку до нуля: в плитке
 * остаётся один текст. Лишнее прячем многоточием.
 */
.category-card__subtitle,
.main-category-card__subtitle {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}

/*
 * Таблица инструкций — во всю высоту.
 *
 * В вёрстке она обрезана по 425 px и разворачивается кнопкой: у дизайнера
 * все документы лежали на одной странице. У нас их тысячи, они разбиты
 * постранично, и обрезать двадцать строк незачем.
 */
.instructions-table-wrap {
  max-height: none;
}

.instructions-table-wrap::after {
  content: none;
}

/*
 * Выбранный раздел в ленте плиток над таблицей.
 *
 * Плитки в вёрстке — ссылки без состояния: отбирать ими документы дизайнер
 * не предполагал. Отмечаем выбранную рамкой, иначе непонятно, почему в
 * таблице осталась часть документов.
 */
.instructions-cats .subcategory-card.is-active {
  border-color: var(--color-primary);
  box-shadow: inset 0 0 0 1px var(--color-primary);
}

/*
 * Плеер с роликом о товаре.
 *
 * В вёрстке видео не было, поэтому и стилей у него нет: iframe вставал
 * обычной строчной вставкой 300×150 сразу под фотографией — то есть за
 * границей блока, который обрезает всё лишнее. На экране не менялось
 * ничего. Кладём плеер поверх фотографии на всю её площадь.
 */
.pdp-gallery__media .pdp-gallery__video {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  border: 0;
  background: #000;
}

/*
 * Скрытая фотография должна исчезать.
 *
 * Скрипт прячет её на время видео через hidden, но правило .pdp-gallery__img
 * задаёт display: block и перебивает встроенное [hidden] браузера.
 */
.pdp-gallery__img[hidden] {
  display: none;
}

/*
 * Сообщение поверх плеера, когда ролик не открылся.
 *
 * Видео лежит на YouTube и RuTube, и до части посетителей эти площадки не
 * доходят. Вместо чёрного прямоугольника предлагаем открыть ролик там, где
 * он работает.
 */
.pdp-gallery__video-notice {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 24px;
  text-align: center;
  background: var(--color-surface-muted);
}

.pdp-gallery__video-notice p {
  margin: 0;
  color: var(--color-text-secondary);
}

/*
 * Подписка на статьи: согласие и ошибка.
 *
 * В вёрстке у галочки согласия нет самого поля — только нарисованный
 * квадрат, отметить его нельзя. У нас поле настоящее, прячем его так же,
 * как у остальных галочек ui-kit, а квадрат рисуется соседним span.
 */
.subscribe__agree {
  position: relative;
  cursor: pointer;
}

.subscribe__agree .checkbox__box {
  flex-shrink: 0;
}

.subscribe__error {
  margin: 0;
  font-size: 14px;
  line-height: 1.4;
  color: var(--color-danger, #e5484d);
}

/*
 * Уведомление «Ссылка скопирована».
 *
 * В UI-Kit всплывающих уведомлений нет, поэтому плашка собрана из того же,
 * из чего cookie-баннер: белая поверхность, скругление 24px, тень попапа,
 * шрифт и цвета из токенов. Появляется внизу по центру и сама исчезает.
 */
.toast {
  position: fixed;
  left: 50%;
  bottom: 32px;
  z-index: 1100;
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: calc(100vw - 32px);
  padding: 12px 20px 12px 14px;
  background: var(--color-surface);
  border-radius: 24px;
  box-shadow: var(--shadow-popup);
  box-sizing: border-box;
  font-family: var(--font-family);
  font-size: var(--font-size-md);
  line-height: var(--line-height-base);
  color: var(--color-dark);
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, 16px);
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.toast.is-visible {
  opacity: 1;
  pointer-events: auto;
  transform: translate(-50%, 0);
}

/* Ссылка в плашке — компонент .link из UI-Kit, но синяя: тут это действие. */
.toast__link {
  flex-shrink: 0;
  margin-left: 8px;
  font-size: var(--font-size-md);
  color: var(--color-primary);
  border-bottom-color: currentColor;
}

.toast__link:hover {
  color: var(--color-primary-hover);
  border-bottom-color: currentColor;
}

.toast--warning .toast__icon {
  color: var(--color-warning);
}

.toast__icon {
  display: inline-flex;
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  color: var(--color-success);
}

.toast__icon svg {
  width: 100%;
  height: 100%;
}

/* На планшете и телефоне снизу плавающее меню — поднимаемся над ним. */
@media (max-width: 1023px) {
  .toast {
    bottom: 112px;
  }
}

/* На телефоне ссылка уходит на вторую строку под текст. */
@media (max-width: 599px) {
  .toast {
    flex-wrap: wrap;
    width: calc(100vw - 32px);
  }

  .toast__link {
    margin-left: 32px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .toast {
    transition: none;
  }
}

/*
 * Крошки на карточке товара в одну строку — и не шире экрана.
 *
 * На телефоне вёрстка держит крошки одной строкой и сжимает с многоточием
 * только последнее звено, а ссылки не сжимает вовсе. В макете разделы
 * называются коротко, у нас — как в 1С: «Оборудование для хранения и
 * перевозки грузов». Такая ссылка не помещается и выталкивает всю
 * страницу за край: появляется прокрутка вбок, а плашки уведомлений и
 * всплывающие окна съезжают вправо. Поэтому сжиматься с многоточием
 * могут и ссылки, а сама строка не выходит за ширину контейнера.
 */
@media (max-width: 1023px) {
  .pdp-breadcrumbs-row .breadcrumbs {
    max-width: 100%;
    min-width: 0;
  }

  .pdp-breadcrumbs-row .breadcrumbs__link {
    flex-shrink: 1;
    min-width: 0;
    max-width: 40%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }

  /* «Главная» и «Каталог» короткие — пусть читаются целиком. */
  .pdp-breadcrumbs-row .breadcrumbs__link:first-child,
  .pdp-breadcrumbs-row .breadcrumbs__link:nth-child(3) {
    flex-shrink: 0;
    max-width: none;
  }
}

/*
 * Цифры на баннере главной — одной строкой.
 *
 * У дизайнера «2500+» без пробела, у нас из админки «6 500+» и «1 млн+».
 * На телефоне колонка сжимается до самого узкого слова: число рвётся по
 * пробелу на «6» и «500+», а подпись под ним — по слову на строку. Число
 * переносить нельзя; колонка тогда держит его ширину, и «позиций в»
 * помещается в строку, как в макете.
 */
.hero__stat-value {
  white-space: nowrap;
}

/*
 * Кнопка «Фильтры» и панель фильтров на телефоне.
 *
 * Кнопка стала ссылкой на окно с фильтрами — подчёркивание ссылки ей не
 * нужно. Скрипт открывает окно классом is-open; без скрипта переход по
 * якорю открывает его через :target, так что фильтры доступны и тогда.
 */
.filters-trigger {
  text-decoration: none;
}

@media (max-width: 1023px) {
  .modal[data-catalog-filters]:target {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity 0.2s ease;
  }

  .modal[data-catalog-filters]:target .filters {
    transform: translateX(0);
  }
}

/*
 * Пагинация на телефоне — в ширину экрана.
 *
 * Кнопки в UI-Kit по 48 px и не сжимаются. На второй странице каталога их
 * семь («‹ 1 2 3 … 272 ›»), в середине — девять, это до 480 px при 358 px
 * свободного места: строка выталкивала всю страницу за край экрана. На
 * узком экране кнопки поменьше, а если и так не влезут — переносятся.
 */
@media (max-width: 479px) {
  .pagination {
    flex-wrap: wrap;
    justify-content: center;
    gap: 4px;
    max-width: 100%;
  }

  .pagination__item {
    width: 36px;
    height: 36px;
    border-radius: 10px;
    font-size: 14px;
  }

  .pagination__item svg {
    width: 20px;
    height: 20px;
  }
}

/*
 * Длинные ссылки в колонках футера переносятся.
 *
 * У ссылки UI-Kit ширина max-content: текст не переносится никогда. В макете
 * разделы каталога названы коротко, у нас — как в 1С: «Оборудование для
 * хранения и перевозки грузов». На узком телефоне (360 px) такая ссылка
 * вылезала за белую плашку футера. Строчная ссылка переносится по словам,
 * и подчёркивание при наведении идёт под каждой строкой.
 */
.footer__col-list .link {
  display: inline;
  width: auto;
  max-width: 100%;
  overflow-wrap: anywhere;
}

/*
 * Окна с заявкой из design-2: «Заказать звонок», «Связаться с нами» и
 * «Получить консультацию».
 *
 * Кнопки открытия — ссылки на якорь окна. Скрипт открывает окно классом
 * is-open; без скрипта переход по якорю показывает его через :target, и
 * туда же сервер возвращает ответ на заявку. У ссылки-кнопки подчёркивание
 * не нужно.
 */
.header__call-btn,
.burger-menu__call-btn,
.page-hero__cta,
.footer__btn,
.seo__eyebrow {
  text-decoration: none;
}

.modal--request:target {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.2s ease;
}

/*
 * Ответ на заявку в светлом окне «Купить в 1 клик».
 *
 * Блок ответа из design-2 рассчитан на тёмную плашку заявки: заголовок и
 * текст у него белые, и на белом окне их не видно.
 */
.modal__dialog .cta__success-title,
.modal__dialog .cta__success-text {
  color: var(--color-dark);
}

/*
 * Шапка держится у верхнего края и прячется при прокрутке вниз.
 *
 * sticky, а не fixed: место в потоке за шапкой сохраняется, и страница при
 * загрузке не подпрыгивает — подпорка под шапку не нужна. Прячем сдвигом
 * вверх: так она уезжает плавно и не трогает раскладку.
 *
 * Высоту шапки скрипт кладёт в --header-height. По ней считается отступ
 * прокрутки: без него переходы по ссылкам-якорям (отзывы, характеристики)
 * и прокрутка к началу списка в каталоге ставили бы цель под шапку.
 */
html {
  scroll-padding-top: var(--header-height, 0px);
}

.header {
  position: sticky;
  top: 0;
  z-index: 940;
  transition: top 0.25s ease;
}

/*
 * Прячем сдвигом точки прилипания, а не transform.
 *
 * Внутри шапки лежат окна поиска, города и бургер-меню — они position: fixed.
 * Любой transform на предке делает его точкой отсчёта для fixed-потомков:
 * окна переставали быть привязанными к экрану, а высота страницы прыгала на
 * высоту шапки — вместе с ней уезжала и прокрутка. С отрицательным top такого
 * не происходит: шапка просто прилипает чуть выше края экрана.
 */
/* Класс именно header--hidden: общий is-hidden занят корзиной, там у него display: none. */
.header--hidden {
  top: calc(-1 * var(--header-height, 200px));
}

@media (prefers-reduced-motion: reduce) {
  .header {
    transition: none;
  }
}

/*
 * Рельса категорий в «Популярных товарах» на телефоне прокручивается.
 *
 * Рельса — прокручиваемый ряд (overflow-x: auto в media.css), и на ней же
 * анимация появления. Правило .motion-ready .reveal ставит overflow-x: clip
 * (в первой версии вёрстки — hidden) и по специфичности перебивает рельсу:
 * категории, не влезшие в ширину, было не достать. Прокручиваемому ряду
 * страховка reveal не нужна — содержимое и так остаётся внутри него.
 */
@media (max-width: 767px) {
  .motion-ready .popular__tabs.reveal {
    overflow-x: auto;
  }
}

/*
 * «Показать все N результатов» в попапе поиска — ссылка на месте счётчика.
 * В макете её нет: там попап показывал весь демо-список целиком.
 */
.search-popup__more {
  width: auto;
  font-size: inherit;
  color: var(--color-primary);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/*
 * Карточки в лентах товаров («Новинки производства» и другие) — одной высоты.
 *
 * Ячейки ленты тянутся по самой высокой карточке, но сама карточка внутри
 * ячейки была по своему содержимому: с названием в одну строку она выходила
 * ниже соседних (434 px против 451 px). Ячейка теперь флекс-контейнер —
 * карточка растягивается на всю её высоту, а цена и кнопки прижаты к низу,
 * чтобы стояли на одной линии у всех карточек.
 */
.product-row__item {
  display: flex;
}

.product-row__item > .product-card {
  flex: 1 1 auto;
}

.product-row__item > .product-card .product-card__body {
  flex: 1 1 auto;
}

.product-row__item > .product-card .product-card__purchase {
  margin-top: auto;
}

/*
 * Окно с роликом о производстве (плашка на фото в «Собственном
 * производстве»). В макете его нет — плашка там ссылка «#». Плеер 16:9
 * во всю доступную ширину, но не выше экрана; крестик — как у просмотра фото.
 */
.video-modal__dialog {
  position: relative;
  z-index: 1;
  width: min(1100px, 100%, (100vh - 96px) * 16 / 9);
  width: min(1100px, 100%, (100dvh - 96px) * 16 / 9);
}

.video-modal__frame {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: 24px;
  overflow: hidden;
  background: #000;
}

.video-modal__frame iframe,
.video-modal__frame video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.video-modal__close {
  position: absolute;
  top: -56px;
  right: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 0;
  border-radius: 12px;
  background: var(--color-surface);
  color: var(--color-dark);
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.video-modal__close:hover {
  background: var(--color-border-light);
}

.video-modal__close svg {
  width: 24px;
  height: 24px;
}

/*
 * На телефоне окна прижаты к верху экрана (media.css), и крестик над
 * плеером уходил за край. Ролик ставим по центру — над ним остаётся место.
 */
.modal.video-modal {
  align-items: center;
}

@media (max-width: 767px) {
  .video-modal__frame {
    border-radius: 16px;
  }
}

/*
 * Название раздела над второй колонкой мега-меню — во всю ширину.
 *
 * Ячейки заголовков повторяют сетку колонок, и заголовку доставалось 342 px
 * колонки: «Оборудование для бочек, еврокубов, биг-бэгов» вставало в три
 * строки, хотя справа пусто. Ячейка с названием тянется до правого края,
 * а левая по-прежнему стоит над первой колонкой.
 */
@media (min-width: 1024px) {
  .catalog-mega__title-slot:nth-child(2) {
    max-width: none;
  }
}

/*
 * Незаполненные согласия в форме заказа — красным.
 *
 * У полей подсветка есть в UI-ките (.text-field--error), у согласий не было:
 * в вёрстке форму никто не проверял. Сообщение об ошибке рядом — по образцу
 * .checkout-form__consent-error из стилей корзины.
 */
.checkout-form__consent--error {
  color: var(--color-danger);
}

.checkout-form__consent--error .checkbox__box {
  border-color: var(--color-danger);
}

/*
 * Поле с ошибкой остаётся красным и под курсором.
 *
 * В UI-ките подпись сфокусированного поля перекрашивается в бледный серый,
 * и правило сильнее подсветки ошибки: первое незаполненное поле получает
 * фокус — и перестаёт выглядеть незаполненным.
 */
.text-field--error .text-field__box:focus-within .text-field__label {
  color: var(--color-danger);
}

/*
 * Корзина во время обновления.
 *
 * Действия в корзине уходят запросом, без перезагрузки страницы. Пока сервер
 * считает, список приглушён и не нажимается: иначе можно успеть нажать
 * «плюс» ещё раз и получить ответ на устаревшее состояние.
 */
[data-cart-page].is-cart-loading .cart-form {
  opacity: 0.6;
  pointer-events: none;
  transition: opacity 0.15s ease;
}

/*
 * Лента миниатюр на странице товара — ровно четыре снимка.
 *
 * В макете у товара четыре миниатюры, из 1С приходит и семь, и десять.
 * Привязка высоты к картинке давала случайный остаток: снизу выглядывала
 * половина пятой миниатюры, а сверху отступ съедался. Поэтому высота
 * считается от содержимого: четыре миниатюры по 80 px, три промежутка по
 * 8 px и по 8 px отступа сверху и снизу — 360 px. Лишние миниатюры
 * прокручиваются стрелками над и под лентой, полосу прокрутки прячем.
 *
 * Если снимков меньше четырёх, лента просто короче: это max-height.
 *
 * Только на широком экране: до 1023 px лента миниатюр скрыта вёрсткой.
 */
@media (min-width: 1024px) {
  .pdp-gallery__thumb-list {
    max-height: 360px;
    min-height: 0;
    overflow-y: auto;
    scroll-behavior: smooth;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }

  .pdp-gallery__thumb-list::-webkit-scrollbar {
    display: none;
  }
}

/*
 * Отзывы к товару на широком экране: карточки колонкой, сводка справа.
 *
 * В вёрстке блок — flex с переносом: карточка отзыва тянется от 480 px,
 * сводка от 320 px. С одним отзывом (как в макете) карточка занимает всю
 * ширину, а со вторым они делят строку пополам и сводка сжимается —
 * блок выглядит иначе, чем в макете. Раскладываем сеткой: отзывы идут
 * друг под другом в левой колонке, сводка стоит справа от первого.
 */
@media (min-width: 1024px) {
  .pdp-reviews__body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 520px;
    align-items: start;
  }

  .pdp-reviews__body .pdp-review-card {
    grid-column: 1;
  }

  .pdp-reviews__body .pdp-rating-summary {
    grid-column: 2;
    grid-row: 1;
    max-width: none;
  }
}

/*
 * Отзывы на телефоне: сводка сверху, отзывы — в своём порядке.
 *
 * В вёрстке блок переворачивается целиком (column-reverse): так сводка,
 * которая в разметке идёт последней, оказывается над отзывами. С одним
 * отзывом это незаметно, а с несколькими переворачивается и их порядок —
 * первым показывался самый старый. Ставим обычную колонку, а сводку
 * поднимаем наверх отдельно.
 */
@media (max-width: 1023px) {
  .pdp-reviews__body {
    flex-direction: column;
  }

  .pdp-reviews__body .pdp-rating-summary {
    order: -1;
  }
}

/*
 * Перенос строки в заголовке первого экрана нужен только там, где кнопки
 * стоят справа от заголовка: он задаёт, где кончается первая строка, чтобы
 * они поместились рядом. Ниже 1024 px кнопки уходят под слайдер, и
 * заготовленный перенос только рвёт фразу не там, где она рвётся сама.
 */
@media (max-width: 1023px) {
  .hero__title br {
    display: none;
  }
}

/*
 * Текст блока «Собственное производство» разбит на абзацы, у каждого своя
 * выделенная первая строка. Колонка раскидывает содержимое по высоте
 * (justify-content: space-between), поэтому абзацы собраны в один блок:
 * иначе интервал между ними зависел бы от высоты соседней колонки.
 */
.about__texts {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.about__text-accent {
  display: block;
  color: var(--color-primary);
}

/*
 * Заголовок над подвалом: выделенная часть — тем же синим, что и в
 * заголовках секций. В вёрстке заголовок был сплошным, поэтому правила
 * для выделения в ней нет.
 */
.footer__cta-title span {
  color: var(--color-primary);
}

/*
 * Подпись под логотипом в подвале: заказчик просит её синей — в вёрстке
 * это была серая строка о производстве мебели.
 */
.footer__tagline {
  color: var(--color-primary);
}

/*
 * Кружок цвета в карточке товара: пустая кнопка без содержимого сжимается
 * флексом до нуля, если ряд не помещается. Ширину фиксируем — иначе часть
 * цветов исчезает из ряда.
 */
.pdp-swatch,
.pdp-swatches__more {
  flex: 0 0 32px;
}

/*
 * Списки в текстах, перенесённых с versmet.ru. В вёрстке описание товара —
 * сплошной абзац, поэтому отступа под маркеры нет: без него кружки списка
 * уезжают за край колонки.
 */
.pdp-summary__desc ul,
.pdp-summary__desc ol,
.pdp-usage-text ul,
.pdp-usage-text ol {
  margin: 0 0 8px;
  padding-left: 20px;
}

.pdp-summary__desc li,
.pdp-usage-text li {
  margin-bottom: 4px;
}

.pdp-usage-text p {
  margin: 0 0 10px;
}

/*
 * Цвета показываем все сразу: в вёрстке ряд обрезался четырьмя кружками с
 * кнопкой «Показать ещё», но цветов у товара пять-семь — прятать нечего.
 */
[data-pdp-colors-container] .pdp-swatch:nth-child(n+5) {
  display: inline-flex;
}

/*
 * Цифры на кадре первого экрана.
 *
 * В вёрстке фотография была тёмной, и белые цифры читались на ней сами по
 * себе. Заказчик прислал светлые кадры — на них текст пропадает. Кладём под
 * цифры мягкую тень: на тёмных кадрах её почти не видно, на светлых она
 * возвращает читаемость.
 */
.hero__slide::after {
  content: "";
  position: absolute;
  inset: 0 0 0 auto;
  width: 46%;
  background: linear-gradient(to right, rgba(41, 53, 67, 0) 0%, rgba(41, 53, 67, 0.5) 72%);
  pointer-events: none;
}

.hero__stats {
  z-index: 1;
}

/* На телефоне цифры стоят строкой внизу — и тень нужна снизу. */
@media (max-width: 767px) {
  .hero__slide::after {
    inset: auto 0 0 0;
    width: auto;
    height: 45%;
    background: linear-gradient(to bottom, rgba(41, 53, 67, 0) 0%, rgba(41, 53, 67, 0.55) 75%);
  }
}

/*
 * Заполненное поле не должно пропадать.
 *
 * В вёрстке у заполненного поля рамка становится прозрачной: там поля стоят
 * на тёмной плашке заявки, белый прямоугольник виден и без неё. На светлом
 * фоне — форма отзыва, оформление заказа, окно «купить в 1 клик» — поле
 * после заполнения исчезало с экрана. Рамку возвращаем везде, кроме тёмной
 * плашки.
 */
.text-field--filled .text-field__box {
  border-color: var(--color-border-light);
}

.cta__box .text-field--filled .text-field__box {
  border-color: transparent;
}

/*
 * Подсказка об обязательных полях в форме отзыва: в вёрстке её не было,
 * но без неё человек узнаёт о требованиях только из ошибки.
 */
.review-form__hint {
  margin: 0;
  font-size: 13px;
  line-height: 1.4;
  color: var(--color-text-secondary);
}

/*
 * Комментарий к доставке — во всю ширину блока адреса.
 *
 * Он стоит в одной сетке с городом и улицей, а те идут в две колонки; поле
 * на пол-строки для текста неудобно.
 */
.checkout-form__comment {
  grid-column: 1 / -1;
}

/*
 * Согласие в окне «Купить в 1 клик» — тёмным по светлому.
 *
 * Разметка согласия взята у блока заявки с главной, а там он лежит на тёмной
 * подложке: UI-кит красит и текст, и рамку флажка в белый. Фон этого окна
 * светлый, и строка пропадала целиком — заказчик заметил пропавший флажок.
 * У окон «Заказать звонок» и «Связаться» такое правило есть (.modal--request),
 * у этого не было.
 */
#one-click-modal .cta__consent-text,
#one-click-modal .cta__consent-text a {
  color: var(--color-dark);
}

#one-click-modal .cta__consent .checkbox__box {
  border-color: var(--color-dark);
}

/*
 * Лента со стрелками по бокам.
 *
 * Обёртка общая: ряд с data-hscroll ставится между двумя кнопками, и тот же
 * скрипт их гасит на концах и прячет целиком, когда листать нечего. На
 * телефоне кнопок нет: они съели бы треть ширины экрана, а лента и так
 * листается пальцем.
 */
.hscroll-row {
  display: flex;
  align-items: center;
  gap: 16px;
}

.hscroll-row__track {
  flex: 1;
  min-width: 0;
}

.hscroll-row__btn {
  flex: none;
}

.hscroll-row.is-hscroll-static .hscroll-row__btn {
  display: none;
}

@media (max-width: 767px) {
  .hscroll-row__btn {
    display: none;
  }
}
