/* Компоненты витрины PROGIX.
 *
 * Каждый блок соответствует элементу макета. Отдельные страницы собираются
 * из этих классов и не заводят собственных кнопок, полей и карточек:
 * если чего-то не хватает — компонент добавляется сюда, а не в шаблон страницы.
 */

/* --- Кнопки -------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  height: 48px;
  padding-inline: var(--sp-6);
  border-radius: var(--r-md);
  border: 1px solid transparent;
  background: var(--c-brand);
  color: #fff;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  white-space: nowrap;
  transition: background var(--t-fast), border-color var(--t-fast),
              transform var(--t-fast), box-shadow var(--t-fast), color var(--t-fast);
}

.btn:hover { background: var(--c-brand-hover); transform: var(--hover-lift); box-shadow: var(--shadow-hover); }
.btn:active { transform: none; background: var(--c-brand-active); }
.btn[disabled] { opacity: 0.5; pointer-events: none; }
.btn svg { width: 18px; height: 18px; flex: 0 0 auto; }
.btn-sm svg { width: 16px; height: 16px; }

.btn-outline { background: transparent; border-color: var(--c-border-strong); color: var(--c-ink); }
.btn-outline:hover { background: var(--c-surface); border-color: var(--c-brand); color: var(--c-brand); }

.btn-ghost { background: transparent; color: var(--c-brand); }
.btn-ghost:hover { background: var(--c-brand-tint); box-shadow: none; }

.btn-light { background: #fff; color: var(--c-ink); border-color: var(--c-border); }
.btn-light:hover { background: var(--c-surface); color: var(--c-brand); }

/* Тёмная кнопка на светлой брендовой подложке — такой в макете «Подписаться». */
.btn-dark { background: var(--c-ink); color: #fff; }
.btn-dark:hover { background: var(--c-ink-90); }

.btn-sm { height: 38px; padding-inline: var(--sp-4); font-size: var(--fs-xs); }
.btn-lg { height: 54px; padding-inline: var(--sp-7); font-size: var(--fs-base); }
.btn-block { width: 100%; }

/* Ставится и без базового .btn, поэтому флекс задаём здесь же: иначе иконка
   ложится по базовой линии текста и уезжает из центра квадрата. */
.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border-radius: var(--r-md);
  background: transparent;
  border: 1px solid var(--c-border);
  color: var(--c-ink-70);
}
.btn-icon:hover { color: var(--c-brand); border-color: var(--c-brand); background: var(--c-brand-tint); transform: none; box-shadow: none; }
.btn-icon.is-active { color: var(--c-brand); border-color: var(--c-brand); background: var(--c-brand-tint); }

/* Малый размер иконочной кнопки. Нужен отдельным правилом: .btn-icon задаёт
   свои width и height, и одного .btn-sm с его height не хватает. */
.btn-icon.btn-sm { width: 34px; height: 34px; }
.btn-icon.btn-sm .ic { width: 16px; height: 16px; }

/* Кнопка «Смотреть все» рядом с заголовками блоков на главной */
/* Ссылка, оформленная кнопкой. inline-flex обязателен: у строчного элемента
   height не работает вовсе, и текст прижимается к верху вместо центра. */
.btn-more {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  height: 32px;
  /* Высота фиксирована, поэтому подпись переносить нельзя: на телефоне
     «Смотреть каталог» вставало в две строки и вылезало из своей рамки.
     Ширину рядом с заголовком кнопка себе оставляет, ужимается заголовок. */
  flex: 0 0 auto;
  white-space: nowrap;
  padding-inline: var(--sp-4);
  border-radius: var(--r-sm);
  background: #fff;
  /* В макете это светло-индиговая обводка и индиговый текст, а не серая
     нейтральная кнопка: рядом с чёрным заголовком она читается как ссылка. */
  border: 1px solid var(--c-brand-tint-border);
  color: var(--c-brand);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
}
.btn-more:hover { color: #fff; background: var(--c-brand); border-color: var(--c-brand); transform: none; box-shadow: none; }

/* --- Поля ---------------------------------------------------------------- */

.field { display: flex; flex-direction: column; gap: var(--sp-2); }

.field-label { font-size: var(--fs-xs); font-weight: var(--fw-medium); color: var(--c-ink-70); }
.field-label .req { color: var(--c-danger); }
.field-hint { font-size: var(--fs-2xs); color: var(--c-muted); }
.field-error { font-size: var(--fs-2xs); color: var(--c-danger); }

.input,
.textarea,
.select {
  width: 100%;
  height: 48px;
  padding: 0 var(--sp-4);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-md);
  background: #fff;
  font-size: var(--fs-sm);
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}

.textarea { height: auto; min-height: 110px; padding: var(--sp-3) var(--sp-4); line-height: var(--lh-base); resize: vertical; }

.input:focus,
.textarea:focus,
.select:focus {
  outline: 0;
  border-color: var(--c-brand);
  box-shadow: 0 0 0 3px rgba(71, 78, 117, 0.14);
}

.input::placeholder, .textarea::placeholder { color: var(--c-muted-light); }
.input.has-error { border-color: var(--c-danger); }

/* Поле с плавающей подписью — так подписаны поля в макете:
   мелкий заголовок внутри рамки, значение под ним. */
.field-boxed {
  position: relative;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-md);
  padding: var(--sp-2) var(--sp-4) var(--sp-1);
  background: #fff;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.field-boxed:focus-within { border-color: var(--c-brand); box-shadow: 0 0 0 3px rgba(71, 78, 117, 0.14); }
.field-boxed > span { display: block; font-size: var(--fs-2xs); color: var(--c-muted); }
.field-boxed > input {
  width: 100%;
  height: 26px;
  border: 0;
  padding: 0;
  background: none;
  font-size: var(--fs-sm);
}
.field-boxed > input:focus { outline: 0; }

/* --- Чекбоксы и радио ---------------------------------------------------- */
/* Из «ТЗ»: галочки не должны быть проставлены автоматически и не должны быть
   из стандартного набора HTML. Поэтому нативный input скрыт, а рисуется свой. */

.check {
  /* Сторона квадрата — переменной: по ней же считается сдвиг, который ставит
     квадрат на центр первой строки подписи. Меняя размер, менять сдвиг
     отдельно не нужно. */
  --check-box: 20px;
  display: inline-flex;
  align-items: flex-start;
  gap: var(--sp-3);
  cursor: pointer;
  font-size: var(--fs-sm);
  line-height: 1.4;
}

/* Кегль подписи объявляем на самой галочке, а не только на подписи: сдвиг
   квадрата считается через 1lh, а эта единица берётся из типографики того
   элемента, где стоит. Подпись «согласия» мельче обычной (12 против 14) —
   без этой строки квадрат равнялся бы по чужой строке и уезжал вниз. */
.check:has(.consent) {
  font-size: var(--fs-2xs);
  line-height: 1.45;
}

.check > input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.check > .box {
  flex: 0 0 auto;
  width: var(--check-box);
  height: var(--check-box);
  /* Общий центр у квадрата и у первой строки подписи. 1lh — высота этой
     строки; половина её разницы с квадратом и есть нужный сдвиг. Прижимать
     квадрат к верху (margin-top: 1px) было верно только при кегле 14:
     у подписи 12 px строка ниже, и квадрат оказывался на 2,5 px ниже текста.
     Первое значение — запасное, для браузеров без единицы lh. */
  margin-top: 0;
  margin-top: calc((1lh - var(--check-box)) / 2);
  border: 1.5px solid var(--c-border-strong);
  border-radius: var(--r-sm);
  background: #fff;
  position: relative;
  transition: border-color var(--t-fast), background var(--t-fast);
}

.check > .box::after {
  content: '';
  position: absolute;
  inset: 0;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none'%3E%3Cpath d='M5 10.5l3.2 3.2L15 7' stroke='white' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 18px no-repeat;
  opacity: 0;
  transform: scale(0.7);
  transition: opacity var(--t-fast), transform var(--t-fast);
}

.check > input:checked + .box { background: var(--c-brand); border-color: var(--c-brand); }
.check > input:checked + .box::after { opacity: 1; transform: none; }
.check > input:focus-visible + .box { box-shadow: 0 0 0 3px rgba(71, 78, 117, 0.2); }
.check:hover > .box { border-color: var(--c-brand); }

.check-round > .box { border-radius: 50%; }
.check-round > .box::after { background-size: 16px; }

.radio > .box { border-radius: 50%; }
.radio > .box::after {
  background: none;
  inset: 4px;
  border-radius: 50%;
  background-color: #fff;
}

/* --- Карточка товара ------------------------------------------------------ */
/* Размеры сняты с узла 944:441 макета: карточка 280x456, изображение 280x280
   во всю ширину без полей, текст с отступом 13, кнопка 186x40 по центру,
   иконки сравнения и избранного справа поверх изображения. */

.product-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: var(--r-lg);
  overflow: hidden;
  transition: transform var(--t-base), box-shadow var(--t-base), border-color var(--t-base);
}

/* Зум и тень при наведении — сквозное требование из фреймов «ТЗ». */
.product-card:hover {
  transform: var(--hover-lift);
  box-shadow: var(--shadow-hover);
  border-color: transparent;
  z-index: 2;
}

.product-card__media {
  position: relative;
  aspect-ratio: 1 / 1;
  /* В макете область снимка белая, а не серая: товары сняты на белом,
     и серая подложка выдаёт себя ободком по краю фотографии. */
  background: #fff;
  overflow: hidden;
}
/* Зум снимка при наведении — сквозное требование из фрейма «ТЗ». */
.product-card__media img { transition: transform var(--t-slide); }
.product-card:hover .product-card__media img { transform: var(--hover-zoom); }

.product-card__media img { width: 100%; height: 100%; object-fit: contain; }

/* Сравнение и избранное лежат поверх снимка одной строкой в правом верхнем
   углу: по требованию заказчика они идут друг за другом, а не в столбик. */
.product-card__tools {
  position: absolute;
  top: var(--sp-3);
  right: var(--sp-3);
  display: flex;
  align-items: center;
  gap: var(--sp-1);
}

/* В макете это голые значки поверх снимка: ни плашки, ни рамки. Белая
   подложка на белой фотографии читалась как случайное пятно. */
.product-card__tools .btn-icon {
  width: 30px;
  height: 30px;
  border: 0;
  background: transparent;
  color: var(--c-ink);
}
.product-card__tools .btn-icon:hover { background: transparent; color: var(--c-brand); transform: var(--hover-zoom); }
/* Отмеченное состояние: и сердце, и сравнение заливаются брендовым цветом —
   в общем списке должно быть видно, что товар уже отложен. */
.product-card__tools .btn-icon.is-active { background: transparent; border: 0; color: var(--c-brand); }
/* Сетки у значков разные — 31×26 у сравнения, 24×24 у сердца. Коробка одна на
   двоих, рисунок вписывает в неё preserveAspectRatio: только так они выходят
   одного размера. Задавать каждому свои width/height нельзя — непрямоугольный
   значок сплющит. Второй селектор не лишний: у правила .btn-icon.btn-sm .ic
   вес выше, и без него сердце оставалось 16 px против 20 px у сравнения. */
.product-card__tools .btn-icon svg,
.product-card__tools .btn-icon.btn-sm .ic { width: 20px; height: 20px; }
.product-card__tools .btn-icon.is-active svg { stroke-width: 2.4; }

/* Метка прижата к левому краю карточки — в макете x=0, без отступа.
   Углы слева прямые, справа скруглённые: метка выглядит приклеенной к краю,
   а не висящей отдельной плашкой. */
.product-card__labels .label {
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  padding-inline: var(--sp-2) var(--sp-3);
}

.product-card__labels {
  position: absolute;
  left: 0;
  bottom: 12px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-1);
}

.product-card__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 12px 13px 11px;
}

.product-card__prices { display: flex; align-items: baseline; gap: var(--sp-2); }
.product-card__price { font-size: var(--fs-lg); font-weight: var(--fw-bold); line-height: 22px; }
.product-card__price-old {
  font-size: var(--fs-sm);
  color: var(--c-muted);
  text-decoration: line-through;
}

/* Три строки названия — фиксированная высота, иначе карточки в ряду
   разъезжаются по низу. Кегль и интерлиньяж из макета: 16 / 19. */
.product-card__name {
  margin-top: 4px;
  font-size: var(--fs-base);
  line-height: 19px;
  min-height: 57px;
}
.product-card__name:hover { color: var(--c-brand); }

.product-card__meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-top: auto;
  padding-top: 9px;
  font-size: var(--fs-xs);
  color: var(--c-muted);
}

/* В макете кнопка 186 из 280 по центру, но на узкой карточке это выглядит
   случайной шириной и ломает ритм сетки. Делаем во всю ширину карточки —
   так и попасть проще, и ряд карточек читается ровнее. */
.product-card .buy-row { margin-top: 9px; }
.product-card .buy-row .btn,
.product-card .buy-row .qty { height: 40px; }

/* Артикул копируется по клику по всей площади — требование из «ТЗ». */
.sku-copy { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; min-width: 0; }
.sku-copy:hover { color: var(--c-brand); }
.sku-copy svg { width: 11px; height: 11px; }
/* Артикулы бывают длинные («ZKT4OKR50325»), а на узкой карточке рядом ещё
   и рейтинг. Без обрезки строка вылезала за карточку и её срезал overflow. */
.sku-copy__text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.product-card__meta .rating { flex: 0 0 auto; }

/* --- Плашки --------------------------------------------------------------- */

.label {
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding-inline: var(--sp-2);
  border-radius: var(--r-sm);
  background: var(--c-label-new);
  color: #fff;
  font-size: var(--fs-2xs);
  font-weight: var(--fw-medium);
}

.badge-discount {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding-inline: 6px;
  border-radius: var(--r-sm);
  background: var(--c-discount);
  color: var(--c-discount-ink);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 26px;
  padding-inline: var(--sp-3);
  border-radius: var(--r-pill);
  background: var(--c-surface);
  color: var(--c-ink-70);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-medium);
}
.badge-success { background: #e8f6ee; color: #17794a; }
.badge-warning { background: #fdf3e3; color: #96660f; }
.badge-danger { background: #fbeceb; color: var(--c-danger); }

/* Плашки «1 725 ₽ при заказе от 50 000 ₽» на карточке товара */
.tier-price {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  background: var(--c-brand-tint);
  border: 1px solid var(--c-brand-tint-border);
  font-size: var(--fs-xs);
}
.tier-price b { font-size: var(--fs-sm); font-weight: var(--fw-bold); }
.tier-price span { color: var(--c-muted); }

/* --- Рейтинг --------------------------------------------------------------- */

/* Звезда в макете тёмная, не золотая: жёлтый в этой палитре нигде
   не встречается и на карточке читается как чужой. */
.rating { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-xs); }
.rating__star { width: 14px; height: 14px; color: var(--c-ink); }
.rating__value { font-weight: var(--fw-semibold); color: var(--c-ink); }
.rating__count { color: var(--c-muted); }

/* --- Счётчик количества ----------------------------------------------------- */

.qty {
  display: inline-flex;
  align-items: center;
  height: 44px;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-md);
  overflow: hidden;
}
.qty button { width: 40px; height: 100%; color: var(--c-ink-70); }
.qty button:hover { background: var(--c-surface); color: var(--c-brand); }
.qty input {
  width: 46px;
  height: 100%;
  border: 0;
  text-align: center;
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  -moz-appearance: textfield;
}
.qty input::-webkit-outer-spin-button,
.qty input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.qty input:focus { outline: 0; }

/* --- Блок покупки ----------------------------------------------------------- */
/* Пока товара нет в корзине — одна кнопка «В корзину» во всю ширину. Как только
   он там, на её месте счётчик слева и переход в корзину справа: заказчик просил,
   чтобы количество можно было менять с любой страницы, где виден товар. */

.buy-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-2);
}
.buy-row__qty,
.buy-row__go { display: none; }

/* Счётчик занимает всю оставшуюся ширину, кнопка перехода — квадрат под
   значок: с подписью ряд не помещался в карточку шириной 280. */
.buy-row.is-in-cart { grid-template-columns: minmax(0, 1fr) auto; }
.buy-row.is-in-cart .buy-row__add { display: none; }
.buy-row.is-in-cart .buy-row__qty,
.buy-row.is-in-cart .buy-row__go { display: inline-flex; animation: buy-swap var(--t-base) both; }

/* Счётчик рядом с кнопкой уже обычного: на карточке шириной 280 они делят
   строку, и стандартные 126 px не оставляют места подписи.
   Ширины здесь — желаемые, а не жёсткие: на самой узкой карточке (телефон
   390, сетка в два столбца, карточка 173) на ряд остаётся 147 px, и счётчик
   ужимается до них сам. min-width у поля обязателен: без него <input>
   держит ширину под двадцать знаков и ужиматься отказывается. */
.buy-row .qty { justify-content: center; min-width: 0; }
.buy-row .qty button { width: 38px; min-width: 30px; }
.buy-row .qty input { width: 44px; min-width: 0; }
.buy-row__go { width: 40px; padding-inline: 0; }

/* Крупный вариант — на странице товара: там блок покупки главный на экране. */
.buy-row--big .btn, .buy-row--big .qty { height: 48px; }
.buy-row--big .qty button { width: 44px; }
.buy-row--big .qty input { width: 54px; }
.buy-row--big .buy-row__go { width: 48px; }

/* Подмена кнопки счётчиком — не рывок: новое проявляется на месте прежнего. */
@keyframes buy-swap {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}

/* Счётчик и переход в корзину остаются в одной строке на любой ширине.
   Раньше ниже 640 они вставали в столбик, и карточка с товаром в корзине
   становилась на 48 px выше соседней — ряд сетки разъезжался по низу. */


/* --- Плитки и карточки ------------------------------------------------------ */

.tile {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--sp-4);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  overflow: hidden;
  transition: transform var(--t-base), box-shadow var(--t-base);
  min-height: 190px;
}
.tile:hover { transform: var(--hover-lift); box-shadow: var(--shadow-hover); }
/* Плитка без снимка — это просто подпись: прижимать её к верху не за что,
   в пустой коробке она смотрится сползшей. */
.tile:not(:has(.tile__img)) { justify-content: center; }
.tile:not(:has(.tile__img)) .tile__title { max-width: 100%; }
/* Подпись плитки в макете — 21 px полужирным («Сетевые» = 81 px по обмеру). */
.tile__title {
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-tight);
  position: relative;
  z-index: 1;
  max-width: 62%;
}
/* Фото занимает плитку целиком, подпись лежит поверх — так в макете. */
.tile__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.card {
  background: #fff;
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  padding: var(--sp-6);
}
.card-flat { border: 0; background: var(--c-surface); }

/* --- Формы согласия --------------------------------------------------------- */

.consent { font-size: var(--fs-2xs); line-height: 1.45; color: var(--c-muted); }
.consent a { color: var(--c-brand); text-decoration: underline; }

/* --- Текст из редактора --------------------------------------------------- */
/* Содержимое, набранное в TinyMCE: описания товаров и разделов, страницы,
   новости. Живёт здесь, а не в content.css, потому что такой текст есть
   и на карточке товара, где content.css не подключён. */

.prose {
  color: var(--c-ink-90);
  line-height: var(--lh-loose);
}

/* Мера строки. На полной ширине контейнера абзац растягивается до 120 знаков —
   глаз теряет начало следующей строки. Ограничиваем сами абзацы и списки,
   а не блок целиком: таблицы и картинки внутри остаются во всю ширину. */
.prose > p,
.prose > ul,
.prose > ol,
.prose > dl,
.prose > blockquote,
.prose > h2,
.prose > h3 { max-width: 78ch; }

/* Текст во всю ширину блока: одна колонка при такой ширине нарушила бы меру
   строки, а узкая колонка оставила бы половину блока пустой. */
.prose-2col { columns: 2; column-gap: var(--sp-9); }
.prose-2col > *, .prose-2col li { max-width: none; break-inside: avoid; }
.prose-2col > *:first-child { margin-top: 0; }

.prose > * + * { margin-top: var(--sp-4); }
.prose h2 { font-size: var(--fs-h3); font-weight: var(--fw-bold); margin-top: var(--sp-7); }
.prose h3 { font-size: var(--fs-lg); font-weight: var(--fw-semibold); margin-top: var(--sp-6); }
.prose ul, .prose ol { padding-left: var(--sp-6); }
.prose ul { list-style: disc; }
.prose ol { list-style: decimal; }
.prose li { margin-top: var(--sp-2); }
.prose li::marker { color: var(--c-brand); }
.prose a { color: var(--c-brand); text-decoration: underline; }
.prose img { border-radius: var(--r-lg); }
.prose table { width: 100%; font-size: var(--fs-sm); }
.prose td, .prose th { padding: var(--sp-3); border-bottom: 1px solid var(--c-border); text-align: left; }

/* --- Пустые состояния ------------------------------------------------------- */

/* Сброс обнуляет margin у p и h3, поэтому расстояния задаём здесь явно —
   иначе заголовок, текст и кнопка склеиваются в одну строку. */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-9) var(--sp-5);
  text-align: center;
  color: var(--c-muted);
}
.empty h3 { color: var(--c-ink); }
.empty p { max-width: 46ch; line-height: var(--lh-base); }
.empty .btn { margin-top: var(--sp-2); }

/* --- Пагинация -------------------------------------------------------------- */

.pagination { display: flex; align-items: center; justify-content: center; gap: var(--sp-2); }
.pagination a, .pagination span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  height: 34px;
  padding-inline: var(--sp-2);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  color: var(--c-ink-70);
}
.pagination a:hover { background: var(--c-surface); color: var(--c-brand); }
.pagination .is-current { background: var(--c-brand); color: #fff; font-weight: var(--fw-semibold); }

/* --- Всплывающее уведомление ------------------------------------------------ */
/* Уведомления не копятся стопкой и не наезжают друг на друга: место у них одно
   на всех — ячейка грида, — поэтому новое встаёт ровно туда, где стояло
   прежнее, а прежнее в этот же момент уходит. */

#toast-host {
  position: fixed;
  left: 50%;
  bottom: var(--sp-7);
  transform: translateX(-50%);
  z-index: 90;
  display: grid;
  justify-items: center;
  /* Сообщение не должно перехватывать клики по тому, что под ним. */
  pointer-events: none;
}

.toast {
  grid-area: 1 / 1;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--r-pill);
  background: var(--c-ink);
  color: #fff;
  font-size: var(--fs-sm);
  text-align: center;
  box-shadow: var(--shadow-pop);
  /* Появление и уход зашиты в одну анимацию длиной в жизнь уведомления
     (site.js убирает узел через 2,6 с): иначе оно исчезает рывком. */
  animation: toast-life 2.6s ease both;
}

/* Пришло новое — предыдущее перестало быть последним и уходит плавно. */
/* Токен --t-base уже несёт и длительность, и кривую: второй ease здесь сделал
   бы свойство недействительным, и уведомления снова копились бы стопкой. */
.toast:not(:last-child) { animation: toast-out var(--t-base) both; }

@keyframes toast-life {
  0% { opacity: 0; transform: translateY(10px) scale(0.96); }
  6% { opacity: 1; transform: none; }
  93% { opacity: 1; transform: none; }
  100% { opacity: 0; transform: translateY(-6px) scale(0.98); }
}

@keyframes toast-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateY(-6px) scale(0.98); }
}

/* Длительность уведомления задана в секундах, а не токеном: её диктует site.js.
   Поэтому и при отключённом движении оно само не станет мгновенным — убираем
   у него хотя бы сдвиг, оставляя проявление и уход. */
@media (prefers-reduced-motion: reduce) {
  @keyframes toast-life {
    0% { opacity: 0; }
    6%, 93% { opacity: 1; }
    100% { opacity: 0; }
  }
  @keyframes toast-out {
    from { opacity: 1; }
    to { opacity: 0; }
  }
}

/* На телефоне под уведомлением стоит нижняя панель навигации. */
@media (max-width: 900px) {
  #toast-host { bottom: calc(64px + var(--sp-4)); }
}

/* --- Модальное окно --------------------------------------------------------- */

.modal-scrim {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-5);
  background: rgba(30, 32, 42, 0.45);
  backdrop-filter: blur(3px);
}

.modal {
  width: min(560px, 100%);
  max-height: calc(100dvh - 60px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--r-xl);
  background: #fff;
  box-shadow: var(--shadow-pop);
}
.modal__head { display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-6) var(--sp-6) var(--sp-3); }

/* Полоса прокрутки внутри окна видна всегда. На телефоне система рисует её
   накладной и гасит через секунду — по неподвижному окну не понять, что
   содержимое листается. Механика та же, что у панели фильтра в catalog.css:
   scrollbar-color возвращаем в auto, иначе Chrome считает, что полосу описали
   стандартными свойствами, игнорирует ::-webkit-scrollbar и снова рисует
   исчезающую. scrollbar-gutter резервирует место, чтобы текст не дёргался.
   Цвет — общий для всего сайта --c-scroll. Правило одно на все окна сразу. */
.modal__body {
  padding: 0 var(--sp-6) var(--sp-5);
  overflow-y: auto;
  scrollbar-color: auto;
  scrollbar-gutter: stable;
}
.modal__body::-webkit-scrollbar { width: 8px; }
.modal__body::-webkit-scrollbar-track { background: transparent; }
.modal__body::-webkit-scrollbar-thumb {
  background: var(--c-scroll);
  background-clip: padding-box;
  border: 2px solid transparent;
  border-radius: var(--r-pill);
}
/* Firefox псевдоэлемента не знает — там полосу красят стандартные свойства. */
@supports not selector(::-webkit-scrollbar) {
  .modal__body { scrollbar-color: var(--c-scroll) transparent; scrollbar-width: thin; }
}
.modal__foot { display: flex; gap: var(--sp-3); padding: var(--sp-4) var(--sp-6) var(--sp-6); }

/* Подтверждение вместо системного окна Chrome. Появляется и уходит плавно —
   мгновенное затемнение читалось бы как рывок страницы. */
.confirm-scrim { animation: scrim-in var(--t-base) both; }
.confirm-scrim.is-leaving { animation: scrim-in var(--t-base) reverse both; }
.confirm { width: min(440px, 100%); }
.confirm__text { color: var(--c-ink-70); line-height: var(--lh-base); }
.confirm .modal__foot .btn { flex: 1; }

@keyframes scrim-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
.confirm-scrim .modal { animation: modal-pop var(--t-base) both; }
@keyframes modal-pop {
  from { opacity: 0; transform: translateY(10px) scale(0.98); }
  to { opacity: 1; transform: none; }
}

/* Опасное действие — удаление, отмена заказа. */
.btn-danger { background: var(--c-danger); border-color: var(--c-danger); }
.btn-danger:hover { background: #a93226; border-color: #a93226; }

@media (max-width: 560px) {
  .modal-scrim { align-items: flex-end; padding: 0; }
  .modal { width: 100%; border-radius: var(--r-xl) var(--r-xl) 0 0; }
}

/* --- Сенсорные экраны ------------------------------------------------------ */
/* На тач-устройствах нет наведения и нет курсорной точности: Apple HIG требует
   цель не меньше 44 pt. Поднимаем всё интерактивное до этой планки — иначе
   мелкие кнопки карточки товара невозможно нажать пальцем с первого раза. */

@media (hover: none), (pointer: coarse) {
  .btn { height: 52px; }
  .btn-sm { height: 44px; }
  .btn-lg { height: 56px; }
  .btn-more { height: 40px; }
  .btn-icon { width: 48px; height: 48px; }

  .input, .select { height: 52px; }
  .field-boxed { padding-block: var(--sp-3) var(--sp-2); }

  /* iOS увеличивает страницу, если поле мельче 16px. */
  .input, .textarea, .select, .field-boxed > input { font-size: 16px; }

  .check { padding-block: var(--sp-2); --check-box: 24px; }

  .qty { height: 48px; }
  .qty button { width: 46px; }

  /* Кнопка и счётчик на карточке заданы точечным правилом и обычную планку
     .btn-sm перебивают — поднимаем их до пальца отдельно. */
  .product-card .buy-row .btn,
  .product-card .buy-row .qty { height: 44px; }

  .pagination a, .pagination span { min-width: 44px; height: 44px; }

  /* Инструменты карточки товара по наведению не появятся — показываем всегда,
     и увеличиваем до нажимаемого пальцем размера. */
  .product-card__tools .btn-icon { width: 44px; height: 44px; }

  /* Полей у названия быть не должно: с -webkit-line-clamp содержимое
     дорисовывается в поле снизу, и из-под трёх строк выглядывает четвёртая.
     Высоты в 57 px под три строки хватает и пальцу. */
}

/* --- Иконки ---------------------------------------------------------------- */
/* Все иконки в сетке 24 и без атрибутов width/height: размер задаёт место,
   где иконка стоит. Здесь только запасной размер — если правила для места нет,
   svg без размеров растянулся бы до 300×150. */

.ic {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  display: block;
}

/* Толщина линии подстраивается под кегль: у мелкой иконки 1.75 выглядит жирно. */
.ic { stroke-width: 1.75; }
.btn-sm .ic, .rating .ic, .product-card__meta .ic { stroke-width: 2; }

.rating .ic { width: 14px; height: 14px; color: var(--c-ink); }
.sku-copy .ic { width: 12px; height: 12px; }
.breadcrumbs .ic { width: 12px; height: 12px; }

/* Отметка «уже добавлено».
   Сердечко подменяется залитым, а не просто красится: контурная иконка
   в активном состоянии читается хуже, особенно поверх фотографии.

   Правило привязано к самой кнопке, а не к её месту на странице: пара
   «контур + заливка» лежит в разметке карточки, строки корзины и блока
   покупки на странице товара. Пока селектор начинался с .product-card__tools,
   на странице товара оба сердца показывались разом — рядом друг с другом. */

[data-favorite] .ic--heart-fill,
[data-favorite].is-active .ic--heart { display: none; }
[data-favorite].is-active .ic--heart-fill { display: block; }

/* Сравнение — то же самое: контурные столбики меняются на залитые. Одной
   только сменой цвета отметка не читалась: у значка почти нет площади. */
[data-compare] .ic-h--compare-fill,
[data-compare].is-active .ic-h--compare { display: none; }
[data-compare].is-active .ic-h--compare-fill { display: block; }

.btn-icon.is-active {
  color: var(--c-brand);
  border-color: var(--c-brand);
  background: var(--c-brand-tint);
}
