/* ==========================================================================
   Цветофор — главная страница
   Методология: BEM. Подход: mobile-first, единственная точка перелома 1024px,
   потому что в макете ровно две ширины — 400 и 1440.
   ========================================================================== */

/* --------------------------------------------------------------- Базовое */

body {
  font-family: "Helvetica Neue", "HelveticaNeue", Helvetica, Arial,
    "Nimbus Sans", sans-serif;
  font-size: 14px;
  color: #000000;
  background-color: #ffffff;
}

@media (min-width: 1024px) {
  body {
    font-size: 18px;
  }
}

:focus-visible {
  outline: 2px solid #dc0978;
  outline-offset: 2px;
  border-radius: 4px;
}

/* Утилиты ---------------------------------------------------------------- */

/* Безусловно, а не `:not(:focus)`. Вариант с фокусом придуман для
   ссылки «Перейти к содержимому», но у неё своё правило (.skip-link).
   Здесь так прячутся переключатели, у которых видимая часть — подпись:
   по клику радиокнопка получала фокус, выходила из-под правила,
   становилась видной серым кружком и сдвигала всё ниже. Фокус при
   этом не пропадает: обводка рисуется на подписи — `:focus-visible + label` */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  inset-inline-start: 16px;
  inset-block-start: 16px;
  z-index: 100;
  padding: 12px 22px;
  border-radius: 15px;
  background-color: #dc0978;
  color: #ffffff;
  font-weight: 500;
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: none;
}

.container {
  width: 100%;
  max-width: calc(1202px + 20px * 2);
  margin-inline: auto;
  padding-inline: 20px;
}

/* Секция и её заголовок --------------------------------------------------- */

/* 24 между секциями на мобильной (макет 328:37: категории кончаются на
   664, фильтры начинаются на 688; фильтры 856 — «Популярные букеты» 880).
   Под баннером отбивка своя — 32 */
.section {
  margin-block-start: 24px;
}

.hero + .section {
  margin-block-start: 32px;
}

.section__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-block-end: 22px;
}

.section__head .section__title {
  margin-block-end: 0;
}

/* Ссылка «смотреть все» — только на мобильных: на десктопе её роль
   выполняет плитка «Все категории» в самой сетке */
.section__more {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 32px;
  height: 32px;
}

/* Не рисуем шеврон границами: из двух border он выходит мельче и острее
   нарисованного в макете. Тот же файл, что и у остальных шевронов */
.section__more--chevron::after {
  content: "";
  width: 13px;
  height: 20px;
  background: url("../../assets/icons/chevron-forward.svg") center / contain no-repeat;
  opacity: 0.8;
}

/* В макете заголовок секции занимает ровно свой кегль (32→32), поэтому
   интерлиньяж равен единице: с 1.15 всё, что ниже, уезжало на 5px */
.section__title {
  margin-block-end: 22px;
  font-size: 20px;
  font-weight: 700;
  line-height: 1;
}

@media (min-width: 1024px) {
  .section__title {
    font-size: 32px;
  }
}

/* Белая карточка-секция: Filters, Advantages, App */
.panel {
  padding: 20px;
  border-radius: 25px;
  background-color: #ffffff;
  box-shadow: 0 4px 12px 0 rgb(205 205 205 / 0.25);
}

@media (min-width: 1024px) {
  .panel {
    padding: 32px;
  }
}

/* Преимущества на мобильной — не карточка: в макете (328:512) четыре
   плитки лежат прямо на странице, ни подложки, ни тени, ни паддинга.
   Белая карточка добавляла рамку, которой в макете нет, и съедала
   по 22px с каждой стороны — колонки вставали на 42 и 232 вместо 20 и 210 */
.advantages.panel {
  padding: 0;
  border-radius: 0;
  background-color: transparent;
  box-shadow: none;
}

@media (min-width: 1024px) {
  .section,
  .hero + .section {
    margin-block-start: 44px;
  }

  /* Фильтры прижаты к сетке категорий: в макете между ними 32,
     а не 44 как между остальными секциями (893 → 925) */
  .section--tight {
    margin-block-start: 32px;
  }

  .section__title {
    margin-block-end: 44px;
  }

  .section__head {
    margin-block-end: 44px;
  }

  .section__more {
    display: none;
  }
}

/* Баннер контентной страницы («Контакты», «О нас», дальше «Способы оплаты»).
   Общая только оболочка: скруглённая коробка 1202×460 с фото в подложке.
   Цвет, геометрия фото и декор — в CSS конкретной страницы: в макете они
   у каждой свои. ------------------------------------------------------- */

.page-banner {
  position: relative;
  display: flex;
  min-height: 360px;
  margin-block-start: 16px;
  border-radius: 25px;
  overflow: hidden;
  isolation: isolate;
}

/* Баннер прижат к краям контейнера, а не к его паддингам */
.page-banner.container {
  width: auto;
  max-width: 1202px;
  margin-inline: 20px;
}

.page-banner__photo,
.page-banner__blob {
  position: absolute;
  z-index: -1;
  max-width: none;
  pointer-events: none;
}

.page-banner__body {
  position: relative;
  max-width: 591px;
}

.page-banner__crumb {
  opacity: 0.5;
}

.page-banner__crumb:hover {
  opacity: 1;
}

.page-banner__title {
  /* Отступ здесь, а не в модификаторе: `--overlay .page-banner__title` —
     это (0,2,0) и перебивало бы страничные 54 и 135 на десктопе */
  margin-block-start: 22px;
  font-family: "LT Remark", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial,
    "Nimbus Sans", sans-serif;
  font-size: 30px;
  font-weight: 700;
  line-height: 1.1;
}

@media (min-width: 1024px) {
  .page-banner__title {
    font-size: 64px;
  }
}

/* Баннер поверх фотографии («О нас», «Способы оплаты»): на 400 фото
   занимает всю площадь, текст белый и прижат к низу; на 1440 фото уходит
   вбок, текст тёмный и по центру. Это два решения из макета, а не одно
   масштабированное, — поэтому модификатор, а не набор переопределений
   на каждой странице. Странице остаётся цвет подложки и геометрия фото. */

.page-banner--overlay {
  align-items: flex-end;
  padding: 40px;
  color: #ffffff;
}

/* Затемнение между фото и текстом: без него белый текст на светлом
   букете нечитаем. Равномерные 29% из макета дают 2.1:1, поэтому
   градиент — густо снизу, где лежит текст, и почти прозрачно сверху. */
.page-banner--overlay::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: linear-gradient(
    to top,
    rgb(0 0 0 / 0.38) 0 45%,
    rgb(0 0 0 / 0.06) 100%
  );
}

.page-banner--overlay .page-banner__photo {
  z-index: -2;
}

.page-banner--overlay .page-banner__crumbs {
  font-size: 16px;
  line-height: 1.2;
}

.page-banner--overlay .page-banner__crumb {
  color: inherit;
}

/* Общая розовая обводка фокуса на затемнённом фото даёт 1.9:1
   при пороге 3:1 для нетекстовых элементов */
.page-banner--overlay .page-banner__crumb:focus-visible {
  outline-color: #ffffff;
}

/* Паддинг обычного баннера здесь не задаём: страничный CSS грузится позже,
   и его мобильное правило перебило бы десктопное отсюда. */
@media (min-width: 1024px) {
  .page-banner {
    min-height: 460px;
  }

  .page-banner.container {
    margin-inline: auto;
  }

  /* Текст прижат к верху, а не центрирован: во всех трёх макетах
     с фотографией крошки начинаются на 194 при баннере с 127.
     У «Контактов» и «Способов оплаты» это совпадало с центром случайно,
     а у «О нас» с его лишним абзацем блок уезжал вниз на 15px */
  .page-banner--overlay {
    align-items: start;
    padding: 67px 80px;
    color: #0c0004;
  }

  /* 64/76 из макета, а не 1.1 (=70.4) */
  .page-banner--overlay .page-banner__title {
    line-height: 76px;
  }

  /* Слева остаётся цветная подложка — затемнение не нужно
     и мешало бы тёмному тексту */
  .page-banner--overlay::before {
    content: none;
  }

  .page-banner--overlay .page-banner__crumbs {
    font-size: 20px;
    line-height: 28px;
  }

  .page-banner--overlay .page-banner__crumb:focus-visible {
    outline-color: #dc0978;
  }
}

/* ================================================================ Header */

.header {
  background-color: #ffffff;
}

.header__inner {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 16px;
  min-height: 64px;
}

@media (min-width: 1024px) {
  .header__inner {
    min-height: 111px;
  }
}

.header__inner > .logo {
  justify-self: center;
}

.logo {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.logo__mark {
  width: 37px;
  height: auto;
}

.logo__word {
  width: 61px;
  height: auto;
}

.city {
  display: none;
  align-items: center;
  gap: 12px;
  font-size: 16px;
  font-weight: 500;
}

/* Приглушён только текст: иконка в макете (256:1650) в полном цвете,
   а раньше opacity висел на всей ссылке и гасил и её */
.city__name {
  opacity: 0.5;
}

.city__icon {
  width: 15px;
  height: 20px;
}

/* Навигация: на мобильных скрыта — в макете это отдельный экран «Меню» */
.nav {
  display: none;
}

.nav__list {
  display: flex;
  gap: 22px;
  font-size: 16px;
  font-weight: 500;
}

.nav__link:hover,
.nav__link:focus-visible {
  color: #dc0978;
}

/* «Вы здесь». В макете состояния нет; берём ту же подчёркнутую пару, что
   у вкладки описания на карточке товара. Цветом одним обойтись нельзя —
   это было бы единственным признаком (WCAG 1.4.1), поэтому ещё и линия. */
.nav__link[aria-current="page"] {
  color: #dc0978;
  padding-block-end: 4px;
  border-block-end: 2px solid #dc0978;
}

.header__phone {
  display: none;
  align-items: center;
  gap: 9px;
  margin-inline-start: auto;
  color: #dc0978;
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
}

@media (min-width: 1024px) {
  .header__phone {
    font-size: 18px;
  }
}

.header__actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-inline-start: auto;
}

/* На мобильных иконки без розовой плитки (макет 328:411),
   но зона нажатия остаётся 40px */
.icon-btn {
  position: relative;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  transition: background-color 0.15s ease;
}

.icon-btn img {
  width: 22px;
  height: 22px;
  object-fit: contain;
}

/* Поиск на мобильных не показываем — в макете его нет */
.header__search {
  display: none;
}

/* Бургер: ссылка на экран меню. Работает без JS,
   скрипт может перехватить клик и открыть шторку. */
.burger__bars,
.burger__bars::before,
.burger__bars::after {
  display: block;
  width: 20px;
  height: 2px;
  border-radius: 2px;
  background-color: #dc0978;
}

.burger__bars {
  position: relative;
}

.burger__bars::before,
.burger__bars::after {
  content: "";
  position: absolute;
  inset-inline-start: 0;
}

.burger__bars::before { inset-block-start: -6px; }
.burger__bars::after  { inset-block-start: 6px; }

/* Бейдж отступает от угла кнопки на 5 (256:1599 — кнопка 1266..1321,
   бейдж 1298..1316 при верхе 37 и кнопке с 32), а не лежит вплотную */
.icon-btn__counter {
  position: absolute;
  inset-block-start: 5px;
  inset-inline-end: 5px;
  display: grid;
  place-items: center;
  min-width: 18px;
  height: 18px;
  padding-inline: 4px;
  border-radius: 10px;
  background-color: #ad0017;
  color: #ffffff;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
}

@media (min-width: 1024px) {
  .logo__mark { width: 56px; }
  .logo__word { width: 92px; }

  .city,
  .nav,
  .header__phone {
    display: flex;
  }

  .header__inner {
    gap: 22px;
  }

  /* Отступы из макета задаются один раз. Раньше к общему gap: 22
     добавлялись ещё margin у города, меню и действий — 110px сверху,
     из-за которых меню переносилось на две строки уже на 1200px. */
  .nav {
    margin-inline-start: 44px;
  }

  .header__actions {
    gap: 16px;
  }

  /* Пункты шапки не переносятся: перенос здесь всегда означает,
     что чему-то не хватило места, и это надо чинить, а не прятать */
  .nav__link,
  .city,
  .header__phone {
    white-space: nowrap;
  }

  .header__inner {
    display: flex;
  }

  .icon-btn {
    width: 55px;
    height: 55px;
    background-color: #fff4f6;
  }

  .icon-btn:hover {
    background-color: #fee9ed;
  }

  .icon-btn img {
    width: 26px;
    height: 26px;
  }

  .header__search {
    display: grid;
  }

  .header__search img {
    width: 28px;
    height: 28px;
  }

  /* Глифы в шапке разного размера (256:1578): поиск 28, профиль 26,
     корзина 32 — общего размера у них нет */
  .header__cart img {
    width: 32px;
    height: 32px;
  }

  .burger {
    display: none;
  }
}

/* ============================================ Плашка установки приложения */
/* Мобильный блок из макета 323:196. На десктопе его роль выполняет
   секция «Скачайте приложение» внизу страницы. */

/* Подложка белая, а не розовая: в макете (323:196) она сливается с
   шапкой, а от страницы плашку отделяет только тень снизу.

   Плашка вынута из потока и лежит поверх первого блока: в макете баннер
   начинается на 88, а сама плашка занимает 64..156 — то есть заходит на
   него на 68px. В потоке она отодвигала всю страницу на 92 вниз. */
.app-strip {
  position: absolute;
  inset-block-start: 64px;
  inset-inline: 0;
  z-index: 4;
  background-color: #ffffff;
  box-shadow: 0 4px 12px 0 rgb(205 205 205 / 0.25);
}

@media (min-width: 1024px) {
  .app-strip {
    inset-block-start: 111px;
  }
}

/* Место под плашку: от низа шапки до верха баннера в макете 24 */
.app-strip ~ #main {
  padding-block-start: 24px;
}

/* Зазоры из макета неодинаковые: 21 после крестика, 13 после значка.
   Общий gap ставил значок на 58 вместо 67 и уводил всю строку влево */
.app-strip__inner {
  display: flex;
  align-items: center;
  gap: 21px;
  min-height: 92px;
}

.app-strip__close {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 26px;
  height: 26px;
}

.cross,
.cross::before,
.cross::after {
  display: block;
  width: 16px;
  height: 2px;
  border-radius: 2px;
  background-color: #000000;
  opacity: 0.5;
}

.cross {
  position: relative;
  background: none;
}

.cross::before,
.cross::after {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
}

.cross::before { transform: rotate(45deg); }
.cross::after  { transform: rotate(-45deg); }

.app-strip__icon {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
}

/* Ширина 84 из макета: надпись обязана лечь в две строки («Установите» /
   «приложение»), иначе она тянется в одну и сдвигает кнопку */
.app-strip__text {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 84px;
  margin-inline-start: -8px;
  opacity: 0.5;
}

.app-strip__label {
  font-size: 14px;
  font-weight: 500;
  line-height: 16px;
}

.app-strip__word {
  width: 71px;
  height: auto;
}

/* 155x48, розовый баннерный и радиус 20 — как у кнопок hero, а не общие
   130x48 брендовым с радиусом 15: кривизну угла видно по растру макета
   (край выходит на полную ширину через 17.5px — это ровно r=20) */
.btn--install {
  flex-shrink: 0;
  margin-inline-start: auto;
  line-height: 16px;
  min-width: 155px;
  min-height: 48px;
  padding-inline: 16px;
  border-radius: 20px;
  background-color: #e23f8f;
  color: #ffffff;
  font-size: 16px;
}

.btn--install:hover {
  background-color: #dc0978;
}

/* ================================================================== Hero */

.hero {
  position: relative;
  display: flex;
  align-items: flex-start;
  min-height: 360px;
  margin-block-start: 0;
  /* 42 сверху и 20 снизу: в макете заголовок начинается на 130 при
     баннере с 88, а нижняя кнопка кончается на 428 при низе 448 */
  padding-block: 42px 20px;
  border-radius: 25px;
  background-color: #f5d6da;
  color: #ffffff;
  overflow: hidden;
  isolation: isolate;
}

/* Контейнерные отступы гасим: у секции собственная внутренняя геометрия */
.hero.container {
  max-width: 1202px;
  margin-inline: 20px;
  width: auto;
  padding-inline: 20px;
}

@media (min-width: 1024px) {
  .hero.container {
    padding-inline: 32px;
  }
}

.hero__bg,
.hero__blob {
  position: absolute;
  z-index: -1;
  pointer-events: none;
}

/* Левый край фото на несколько единиц светлее фона баннера, и на стыке
   была видна вертикальная полоса. Маска растворяет край. */
/* На мобильной фото занимает весь баннер и показывает свою правую
   половину — там, где в макете видны бутоны. Маска левого края нужна
   только десктопу, где фото приставлено к розовой заливке */
.hero__bg {
  object-position: 62% center;
  inset-block-end: 0;
  inset-inline-end: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Мобильная подложка. В макете (328:38) баннер — это фотография под
   плотной розовой пеленой: замер даёт ровный (175,150,155) по всей
   левой половине и проступающие пионы справа. Сплошная заливка
   brand-200, как было, съедала фотографию целиком.

   Пелена тут же и решает контраст: белый на (175,150,155) — 2.6:1,
   поэтому к розовому подмешан чёрный сверху, где лежит текст. Тот же
   приём, что у мобильного баннера «О нас» (§11). */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(
      180deg,
      color-mix(in srgb, #000000 34%, transparent) 0,
      color-mix(in srgb, #000000 24%, transparent) 62%,
      color-mix(in srgb, #000000 8%, transparent) 100%
    ),
    color-mix(in srgb, #f5d6da 62%, transparent);
}

/* Розовое пятно есть только в десктопном макете: в мобильном (328:40)
   эллипс лежит выше баннера и в кадр не попадает */
.hero__blob {
  display: none;
  inset-block-start: -76px;
  inset-inline-start: -256px;
  width: 637px;
  height: 610px;
  max-width: none;
}

.hero__content {
  position: relative;
  z-index: 1;
  max-width: 591px;
  text-align: center;
}

/* 30/36 из мобильного макета (328:51 — слой 268x72, две строки) */
.hero__title {
  font-family: "LT Remark", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial,
    "Nimbus Sans", sans-serif;
  font-size: 30px;
  font-weight: 700;
  line-height: 36px;
  color: inherit;
  text-wrap: balance;
}

@media (min-width: 1024px) {
  .hero__title {
    font-size: 64px;
  }
}

/* 16/24 (328:557 — слой 313x48): текст на фотографии белый, без
   приглушения — гасить его на снимке нечем */
.hero__text {
  margin-block-start: 12px;
  font-size: 16px;
  line-height: 24px;
  color: inherit;
}

/* 38 до первой кнопки и 16 между ними — из макета (300 и 372 при
   подзаголовке, кончающемся на 262) */
.hero__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  margin-block-start: 38px;
}

@media (min-width: 1024px) {
  /* Специфичность .hero.container — иначе базовое правило ниже перебьёт */
  .hero.container {
    min-height: 460px;
    margin-block-start: 16px;
    margin-inline: auto;
    padding-block: 0;
    padding-inline: 80px;
  }

  .hero::before {
    display: none;
  }

  /* Десктопный баннер — розовая заливка с фотографией сбоку и тёмным
     текстом; мобильный — фотография во всю площадь с белым текстом.
     Это два разных решения макета, а не одно масштабированное */
  .hero__title {
    color: #0c0004;
    line-height: 1.19;
  }

  .hero__blob {
    display: block;
  }

  .hero__content {
    text-align: start;
  }

  .hero__actions {
    justify-content: flex-start;
  }

  /* Левый край фото на несколько единиц светлее заливки баннера, и на
     стыке была видна вертикальная полоса — маска растворяет край.
     На мобильной стыка нет: фото занимает баннер целиком */
  .hero__bg {
    -webkit-mask-image: linear-gradient(to right, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 80px);
    mask-image: linear-gradient(to right, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 80px);
    /* В макете (25:398) картинка вписана по высоте и обрезана справа —
       видна её левая часть с крупными бутонами */
    object-position: left center;
    width: 1110px;
    height: 460px;
    object-fit: cover;
  }

  /* Отступы из макета (14:32): заголовок на 57 от верха баннера,
     подзаголовок на 230, кнопки на 329 */
  .hero__content {
    padding-block-start: 57px;
  }

  .hero__text {
    margin-block-start: 19px;
    font-size: 20px;
    line-height: 28px;
    color: #0c0004;
    opacity: 0.8;
  }

  .hero__actions {
    /* 20 между кнопками: в макете вторая начинается на 331 при первой
       80..311 (24:394 и 29:400) */
    gap: 20px;
    margin-block-start: 43px;
  }

  /* На десктопе преимущества — белая карточка с тенью (15:39);
     карточка снята только на мобильной */
  .advantages.panel {
    padding: 32px;
    border-radius: 25px;
    background-color: #ffffff;
    box-shadow: 0 4px 12px 0 rgb(205 205 205 / 0.25);
  }

  .btn--hero-outline {
    padding-block: 13px;
  }
}

/* ============================================================== Кнопки */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  border-radius: 15px;
  font-weight: 500;
  text-align: center;
  transition: background-color 0.15s ease, color 0.15s ease, opacity 0.15s ease;
}

.btn--primary {
  padding: 8px 22px;
  min-height: 40px;
  background-color: #dc0978;
  color: #ffffff;
  font-size: 14px;
}

.btn--primary:hover {
  background-color: #e23f8f;
}

.btn--hero,
.btn--hero-outline {
  flex: 0 1 231px;
  min-height: 56px;
  padding: 15px 32px;
  border-radius: 20px;
  font-size: 16px;
  line-height: 26px;
}

.btn--hero {
  background-color: #e23f8f;
  color: #ffffff;
}

.btn--hero:hover {
  background-color: #dc0978;
}

/* Рамка остаётся brand-400 как в макете, а текст — brand-500:
   #e23f8f на белом даёт 3.93:1 и не проходит AA для 16px */
/* Паддинг на 2 меньше залитой кнопки: рамка идёт внутрь, и с общими 15
   кнопка вырастала до 60 при 56 в макете — второй ряд уезжал вниз */
.btn--hero-outline {
  padding-block: 13px;
  border: 2px solid #e23f8f;
  background-color: #ffffff;
  color: #dc0978;
}

.btn--hero-outline:hover {
  background-color: #fff4f6;
}

.btn--outline {
  border: 1px solid #dc0978;
  background-color: #ffffff;
  color: #dc0978;
}

.btn--outline:hover {
  background-color: #fff4f6;
}

/* Размеры из макета (121:107): 307 x 66, внутренний отступ 22,
   строка 22 — кнопка выше обычной и с крупным скруглением */
/* 320x54, надпись 20/22 (328:555 и 328:556 — слой «Получить» 90x22) */
.btn--promo {
  min-height: 54px;
  padding: 22px;
  border-radius: 25px;
  background-color: #dc0978;
  color: #ffffff;
  font-size: 20px;
  line-height: 22px;
}

@media (min-width: 1024px) {
  .btn--promo {
    font-size: 28px;
  }
}

.btn--promo:hover {
  background-color: #e23f8f;
}

.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.5;
  pointer-events: none;
}

@media (min-width: 1024px) {
  .btn--primary {
    min-height: 59px;
    font-size: 20px;
  }

  /* 231×56 из макета (24:394): padding 15 + строка 26 + padding 15.
     С min-height: 0 высоту задавал контент и выходило 60 */
  .btn--hero,
  .btn--hero-outline {
    flex: 0 0 231px;
    height: 56px;
    min-height: 0;
  }

  .btn--promo {
    min-width: 307px;
  }
}

/* Блок, которого нет в десктопном макете (сетка категорий
   на «Открытой категории») */
.section--mobile-only {
  display: block;
}

/* ========================================================== Категории */

/* Мобильная лента: в макете помещается ровно 4 плитки по 80px,
   остальные доступны горизонтальной прокруткой — ни одна категория
   не теряется */
/* scroll-padding обязателен: точка привязки по умолчанию совпадает с
   краем области прокрутки, и браузер сразу подтягивал ленту на 20px —
   первая плитка вставала вплотную к краю экрана вместо отступа макета */
.categories {
  display: flex;
  gap: 13px;
  margin-inline: calc(20px * -1);
  padding-inline: 20px;
  scroll-padding-inline: 20px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.categories::-webkit-scrollbar {
  display: none;
}

.categories__item {
  flex: 0 0 80px;
  scroll-snap-align: start;
}

/* Вариант «сеткой»: без прокрутки (макет 323:1212). Колонки набираются
   по минимальной ширине плитки, а не долями от контейнера: на 400 это те же
   4 в ряд по 80, но между ширинами макета сетка добавляет колонки вместо
   того, чтобы растягивать плитку — при 1000px было 4 плитки по 226. */
.categories--grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
  gap: 20px 13px;
  margin-inline: 0;
  padding-inline: 0;
  overflow-x: visible;
}

/* 16 между фото и подписью: в макете (328:55) фото кончается на 604,
   подпись начинается на 620 */
.category {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  text-align: center;
}

.category__media {
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 1;
  border-radius: 25px;
  background-color: #ffedf0;
  overflow: hidden;
}

/* cover, а не contain: в макете (37:422 и соседние) фото крупнее плитки
   126×126 и подрезано ею. С contain картинка вылезала за пределы плитки
   и на глаз казалась увеличенной */
/* aspect-ratio, а не height: 100%: высота плитки задана пропорцией, и
   процентная высота ребёнка в неё не разрешается — картинка вытягивалась
   по своей пропорции и вылезала за плитку */
.category__media img {
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
}



/* 15/22 Bold: «Доставка сегодня» рядом набрана тем же кеглем, а высоту
   даёт двухстрочная подпись — «Кустовые розы» в макете 79x44. У
   однострочных Figma показывает 16, это её обычная нестыковка */
.category__name {
  /* Место под две строки: в макете (328:54) лента категорий 140 высотой
     независимо от длины подписи, и в сетке (323:1212) ряды идут с шагом
     160. По содержимому однострочные ряды были на 22px ниже */
  min-block-size: 44px;
  font-size: 15px;
  font-weight: 700;
  line-height: 22px;
  text-wrap: balance;
}

/* Текущая категория: рамка brand-500 и подложка на тон плотнее обычной
   плитки (323:1212 — замер по рендеру даёт рамку (220,9,120) и заливку
   (252,212,223)). Без этого в списке не видно, какая категория открыта */
.category[aria-current="page"] .category__media {
  border: 2px solid #dc0978;
  background-color: #f5d6da;
}

/* Плитка «Все категории» */
.dots {
  display: flex;
  gap: 8px;
}

.dots i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: #dc0978;
}

@media (min-width: 1024px) {
  .section--mobile-only {
    display: none;
  }

  /* flex-wrap обязателен: восемь плиток по 126 с зазором 22 требуют 1162,
     и на ноутбуке 1024 лента вылезала за экран горизонтальной прокруткой */
  .categories {
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 22px;
    margin-inline: 0;
    padding-inline: 0;
    overflow-x: visible;
  }

  .categories__item {
    flex: 0 0 126px;
  }

  /* Дорожки фиксированные, а остаток раскидывает space-between из .categories:
     на 1202 это ровно 8 плиток по 126 с зазором 27.71, как в макете, а на
     узком десктопе колонок становится меньше — без переполнения */
  .categories--grid {
    grid-template-columns: repeat(auto-fill, 126px);
  }

  .category {
    gap: 16px;
  }

  /* 22: подпись в две строки занимает 44 (37:424 — «Розы из Эквадора»
     110x44), и только с ним плитка встаёт в свои 186. У однострочных
     подписей Figma показывает 18 — это её собственная нестыковка,
     проверять по двухстрочной */
  .category__name {
    min-block-size: 0;
    font-size: 18px;
    font-weight: 500;
    line-height: 22px;
  }
}

/* ============================================================= Фильтры */

.filters {
  display: flex;
  flex-direction: column;
  gap: 22px;
}

.filters__group {
  display: flex;
  align-items: center;
  gap: 16px;
}

/* 16 на мобильной (323:224 — «Цена:» 44x22), 20 на десктопе */
.filters__label {
  font-size: 16px;
  font-weight: 500;
  line-height: 22px;
}

/* min-width: 0 обязателен: у флекс-элемента минимальный размер по умолчанию
   равен min-content, и строка цены не сжималась — на 360px это давало
   горизонтальную прокрутку всей страницы */
.filters__range {
  display: flex;
  flex: 1 1 auto;
  min-width: 0;
  align-items: center;
  gap: 16px;
}

.filters__dash {
  width: 25px;
  height: 25px;
  flex-shrink: 0;
}

.filters__unit {
  font-size: 16px;
  font-weight: 500;
}

/* Поля формы — единый паттерн, см. CLAUDE.md §4.2 */
.field {
  min-height: 54px;
  padding: 8px 22px;
  border: 1px solid rgb(0 0 0 / 0.15);
  border-radius: 15px;
  background-color: #ffffff;
  font-size: 18px;
  font-weight: 500;
}

@media (min-width: 1024px) {
  .field {
    font-size: 20px;
  }
}

.field::placeholder {
  color: #000000;
  opacity: 0.5;
}

/* В макете (136:27) значение набрано чёрным с opacity 0.5 — то есть
   серым. Было чёрным в полную силу и выбивалось из ряда */
.field--num {
  flex: 1 1 92px;
  width: 92px;
  min-width: 0;
  color: #000000;
  opacity: 0.5;
  text-align: center;
  appearance: textfield;
}

.field--num:focus {
  opacity: 1;
}

.field--num::-webkit-outer-spin-button,
.field--num::-webkit-inner-spin-button {
  appearance: none;
  margin: 0;
}

/* 202 из макета — как база, а не как минимум: ниже 400px селект ужимается
   вместе с рядом, вместо того чтобы выталкивать его за экран */
.field--select {
  flex: 0 1 202px;
  min-width: 0;
  padding-inline-end: 46px;
  color: #dc0978;
  appearance: none;
  /* Шеврон 20×13 — как в макете (136:42). Раньше он рисовался двумя
     градиентами и выглядел мелким остроугольным треугольником */
  background-image: url("../../assets/icons/chevron.svg");
  background-position: calc(100% - 22px) center;
  background-size: 20px 13px;
  background-repeat: no-repeat;
}

/* Переключателя вида в мобильном макете нет */
.filters__view {
  display: none;
  gap: 22px;
}

.view-btn {
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  border: 2px solid #b3b3b3;
  border-radius: 15px;
  transition: border-color 0.15s ease;
}

.view-btn:hover {
  border-color: #e23f8f;
}

.view-btn.is-active {
  border-color: #dc0978;
}

@media (min-width: 1024px) {
  .filters__label,
  .filters__unit {
    font-size: 20px;
  }

  .filters {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 32px;
  }

  .filters__group {
    gap: 44px;
  }

  .filters__group:first-child {
    gap: 16px;
  }

  .filters__view {
    display: flex;
  }

  .filters__range {
    flex: 0 0 auto;
  }

  .field--num {
    flex: 0 0 109px;
    width: 109px;
  }
}

/* На странице каталога заголовок, фильтры и сетка живут в одной секции —
   нужен собственный отступ между фильтрами и товарами */
.products--spaced {
  margin-block-start: 32px;
}

@media (min-width: 1024px) {
  .products--spaced {
    margin-block-start: 44px;
  }
}

/* ======================================================= Сетка товаров */

/* Колонки не задаются числом, а набираются по минимальной ширине карточки.
   На обеих ширинах макета счёт выходит ровно тот же (2 по 170 на 400,
   4 по 284 на 1440), а между ними сетка добавляет колонки вместо того,
   чтобы растягивать карточку: при 1000px было 2 карточки по 463. */
.products {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 20px;
}

@media (min-width: 1024px) {
  .products {
    grid-template-columns: repeat(auto-fill, minmax(284px, 1fr));
    gap: 22px;
  }
}

.products > li {
  display: flex;
}

/* ====================================================== Карточка товара */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  border-radius: 15px;
  background-color: #ffffff;
  box-shadow: 0 4px 12px 0 rgb(205 205 205 / 0.25);
  overflow: hidden;
}

@media (min-width: 1024px) {
  .card {
    border-radius: 25px;
  }
}

.card__media {
  position: relative;
  aspect-ratio: 170 / 164;
  overflow: hidden;
}

.card__photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.25s ease;
}



/* z-index обязателен: ссылка карточки растянута псевдоэлементом поверх
   всего блока и без него перехватывает клик по «избранному» */
/* Кнопка избранного лежит в форме: без скрипта это обычная отправка на
   /favorites/toggle, со скриптом — переключение на месте. Позиционируется
   форма, а не кнопка, иначе внутри карточки появлялся бы пустой блок */
.card__fav {
  position: absolute;
  z-index: 1;
  inset-block-start: 10px;
  inset-inline-end: 10px;
}

.card__like {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background-color: #ffffff;
}

.card__like img {
  width: 20px;
  height: 20px;
}

/* В избранном: залитое розовое сердце. Цвет не единственный признак —
   меняется и доступное имя кнопки («Убрать … из избранного») */
.card__like[aria-pressed="true"] {
  background-color: #fff4f6;
}

.card__like[aria-pressed="true"] img {
  content: url("../../assets/icons/heart-filled.svg");
}

.card__body {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  gap: 8px;
  padding: 12px 12px 12px;
}

@media (min-width: 1024px) {
  .card__body {
    padding: 12px 22px 22px;
  }
}

/* 18/18 на мобильной (328:244 — слой 146x18) */
.card__title {
  font-size: 18px;
  font-weight: 500;
  line-height: 18px;
}

@media (min-width: 1024px) {
  .card__title {
    font-size: 20px;
  }
}

/* Растягиваем ссылку на всю карточку — вся карточка кликабельна,
   но в дереве доступности остаётся одна ссылка с внятным текстом */
.card__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.card__prices {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 8px;
}

.card__price {
  font-size: 20px;
  font-weight: 700;
  white-space: nowrap;
}

@media (min-width: 1024px) {
  .card__price {
    font-size: 22px;
  }
}

.card__price-old {
  font-size: 14px;
  font-weight: 500;
  opacity: 0.3;
  white-space: nowrap;
}

@media (min-width: 1024px) {
  .card__price-old {
    font-size: 18px;
  }
}

.card__delivery {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-block-start: auto;
  font-size: 12px;
}

@media (min-width: 1024px) {
  .card__delivery {
    font-size: 17px;
  }
}

.card__delivery img {
  width: 21px;
  height: 16px;
  flex-shrink: 0;
}

/* nowrap: строка доставки в макете (328:246) укладывается ровно в 134
   из 146 доступных, и любой лишний пиксель ломает «от 200 ₽» на две
   строки — карточка вырастает и весь ряд едет вниз */
.card__shipping {
  opacity: 0.5;
  white-space: nowrap;
}

/* Общие элементы строки доставки: используются и в карточке товара
   в каталоге, и на странице товара — поэтому самостоятельные блоки,
   а не элементы .card */
/* В макете (140:370) точка вместе с отступами занимает 27px, поэтому
   «Сегодня» начинается заметно правее, чем при обычном зазоре */
.dot-sep {
  width: 4px;
  height: 4px;
  margin-inline: 8px;
  border-radius: 50%;
  background-color: currentColor;
  opacity: 0.5;
}

/* 12 на мобильной («Сегодня» — слой 48x12), 18 на десктопе: при 14
   строка доставки не помещалась в карточку 146 и переносилась */
.delivery-term {
  color: #20890b;
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
}

@media (min-width: 1024px) {
  .delivery-term {
    font-size: 17px;
  }
}

.card__buy {
  position: relative;
  z-index: 1;
  width: 100%;
}

.card__split {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 4px;
  font-size: 14px;
}

/* 71×22 из макета (239:2621): логотип 16, отступ 5 слева */
.split {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding-inline: 5px 6px;
  border-radius: 15px 2px 2px 15px;
  background-color: #edeff2;
}

/* 16×16 из макета (239:2622) */
.split__logo {
  width: 16px;
  height: 16px;
}

.split__sum {
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
}

.card__split-note {
  white-space: nowrap;
  font-weight: 500;
  opacity: 0.5;
}

/* Бейджи ---------------------------------------------------------------- */

.badge {
  position: absolute;
  z-index: 1;
  inset-block-start: 10px;
  inset-inline-start: 10px;
  display: grid;
  place-items: center;
  min-height: 22px;
  padding-inline: 14px;
  color: #ffffff;
  font-size: 14px;
  line-height: 1;
}

.badge--sale {
  border-radius: 15px;
  background-color: #dc0978;
}

/* «Хит» в макете (140:328) светло-розовый с брендовым текстом,
   а не сплошной brand-500 с белым */
.badge--hit {
  border-radius: 15px;
  background-color: #ffe2e7;
  color: #dc0978;
}

/* В макете фон бейджа полупрозрачный (0.9): на светлом фото белый текст
   даёт 3.32:1 при пороге 4.5. Непрозрачная заливка — 4.52:1. */
.badge--new {
  border-radius: 50px;
  background-color: #20890b;
  font-size: 14px;
}

@media (min-width: 1024px) {
  .card__media {
    aspect-ratio: 284 / 225;
  }

  /* Отступы задаются обёртке: позиционируется она, и правило на самой
     кнопке ничего не двигало — «лайк» оставался на 10px вместо 16 */
  .card__fav {
    inset-block-start: 16px;
    inset-inline-end: 16px;
  }

  .card__like {
    width: 35px;
    height: 35px;
    border-radius: 25px;
  }

  /* Вертикали внутри карточки из макета (140:281): фото 225, название
     245, цена 287, строка доставки 325, кнопка 368, чип Сплита 443,
     низ карточки 487. Отступы заданы поштучно — при общем gap карточка
     вырастала до 497 и все секции ниже уезжали. */
  .card__body {
    gap: 0;
    padding: 20px 22px 16px;
  }

  .card__title {
    line-height: 1.2;
  }

  .card__prices {
    gap: 16px;
    margin-block-start: 18px;
  }

  .card__delivery {
    margin-block-start: 7px;
  }

  /* Отступ на обёртке-форме, а не на кнопке: иначе он считался дважды */
  .card__add {
    margin-block-start: 19px;
  }

  .card__split {
    margin-block-start: 15px;
  }

  .card__delivery {
    gap: 8px;
  }

  .card__delivery img {
    width: 24px;
    height: 18px;
  }

  .delivery-term {
    font-size: 18px;
  }

  .badge {
    inset-block-start: 16px;
    inset-inline-start: 16px;
    min-height: 32px;
    font-size: 18px;
  }

  /* 66×32 из макета: с прежним padding «−20%» растягивал бейдж до 77 */
  .badge--sale,
  .badge--hit {
    width: 66px;
    padding-inline: 0;
  }

  /* «Новинка» — 14px и на десктопе (140:355): базовое правило перебивал
     общий .badge с 18px */
  .badge--new {
    font-size: 14px;
  }

  .split {
    padding-inline: 6px;
  }

  .split__sum {
    font-size: 20px;
  }

  .card__split {
    font-size: 20px;
  }
}

/* ======================================================== Преимущества */

/* Зазор 20 из макета (328:513 — колонки на 20 и 210 при ширине 170,
   ряды с шагом 193) */
.advantages {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 33px 20px;
}

/* Линии между колонками нужны только на десктопе: на мобильной блок
   складывается в две колонки и разделителей в макете нет */
.advantages__rule {
  display: none;
}

.advantage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  min-width: 0;
  text-align: center;
}

/* align-items: center даёт детям ширину по контенту — без max-width
   длинная подпись вылезает за колонку вместо переноса */
.advantage > * {
  max-width: 100%;
}

/* Плитка 102×102 и иконка в своём размере — как в макете (37:454).
   Было 80×80 с иконкой, ужатой до 47px: пропорции ломались, грузовик
   выглядел приплюснутым */
/* 80x80 на мобильной (328:514), 102x102 на десктопе */
.advantage__icon {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 80px;
  height: 80px;
  border-radius: 15px;
  background-color: #ffebef;
}

.advantage__icon img {
  width: auto;
  height: auto;
  max-width: 70px;
  max-height: 70px;
}

.advantage:first-child .advantage__icon {
  background-color: #fee9ed;
}

/* 18px: в макете (37:455) заголовок «Доставка сегодня» — 20/18,
   с интерлиньяжем 22 панель вырастала на 4px и всё ниже уезжало */
/* 16/22 на мобильной. Спор решают переносы: при 15 «Фото перед
   отправкой» укладывается в колонку 170 одной строкой, а в макете
   (328:528) она в две — значит кегль крупнее. По чернилам 15 Bold и
   16 Medium расходятся с макетом одинаково, на 2% в разные стороны */
.advantage__title {
  font-size: 16px;
  font-weight: 500;
  line-height: 22px;
}

/* 0.7 на мобильной: модальный тон подписи в рендере (328:520) — ровно
   (77,77,77). На десктопе тот же текст 0.8.

   Отрицательная отбивка: после плитки-иконки в макете 16, а между
   заголовком и подписью 11 — один gap на колонку двух чисел не даёт */
.advantage__text {
  margin-block-start: -5px;
  font-size: 14px;
  line-height: 21px;
  opacity: 0.7;
}

@media (min-width: 1024px) {
  .advantage__text {
    font-size: 18px;
  }
}

@media (min-width: 1024px) {
  /* gap здесь не нужен: промежутки распределяет space-between, а с ним
     они складывались и колонки уезжали вправо */
  .advantages {
    display: flex;
    justify-content: space-between;
    gap: 0;
  }

  .advantage__text {
    margin-block-start: 0;
    opacity: 0.8;
  }

  /* Ширина колонки из макета: 190, у «Фото перед отправкой» — 223,
     иначе заголовок переносится в две строки */
  .advantage {
    position: relative;
    flex: 0 0 auto;
    width: 190px;
    gap: 16px;
  }

  /* Колонка «Фото перед отправкой» шире остальных — 223 в макете.
     Раньше она выбиралась по nth-child(2), но между пунктами появились
     разделители, и вторым ребёнком стал уже не пункт. */
  .advantage--wide {
    width: 223px;
  }

  /* Разделители — обычные элементы в том же ряду: тогда space-between
     сам ставит их по центру промежутков (280 / 618 / 922 в макете).
     Псевдоэлементом линия висела на фиксированных −32px от колонки и
     оказывалась на 25px правее нужного. */
  .advantages__rule {
    display: block;
    align-self: center;
    width: 1px;
    height: 159px;
    background-color: #e5e5e5;
  }

  .advantage__icon {
    width: 102px;
    height: 102px;
  }

  .advantage__icon img {
    max-height: 70px;
  }

  /* 18px и зазор 12 до подписи — так в макете (37:466): блок текста
     занимает 51px, а не 59, и панель получается ровно 237 */
  .advantage__title {
    font-size: 20px;
    line-height: 18px;
  }

  .advantage {
    gap: 12px;
  }

  .advantage__title {
    margin-block-start: 4px;
  }

  /* У «Фото перед отправкой» в макете (37:470) интерлиньяж 22, и именно
     он задаёт высоту всей панели — 237 */
  .advantage--wide .advantage__title {
    line-height: 22px;
  }
}

/* =============================================== Промо «Скидка 10%» */

/* Мобильные размеры из макета (328:550): паддинг 20, зазор 20, подложка
   brand-150. Общие 22 и brand-50 давали колонку под заголовок 244
   вместо 250 — «Скидка 10% на первый заказ» не укладывалась в две строки */
.promo {
  position: relative;
  display: grid;
  grid-template-columns: 50px 1fr;
  align-items: center;
  gap: 20px;
  padding: 20px;
  border-radius: 25px;
  background-color: #ffebef;
  overflow: hidden;
}

/* Фото-подложка справа (макет 136:17): исходник из Figma, ужатый до
   762x281 — ровно того размера, каким он стоит в макете. Размытия на нём
   нет, мягкость даёт сама фотография и прозрачность 33%. */
.promo__bg {
  /* В мобильном макете (328:550) подложки нет вовсе */
  display: none;
  position: absolute;
  inset-block-end: -80px;
  inset-inline-start: calc(50% + 270px);
  translate: -50% 0;
  z-index: 0;
  width: 762px;
  max-width: none;
  height: 281px;
  object-fit: cover;
  opacity: 0.33;
  /* Левый край фото на несколько единиц темнее панели, и на стыке видна
     вертикальная полоса. В макете её растворяет размытие слоя, здесь —
     маска: перепад падает с 5.7 до 1 единицы, как в макете */
  -webkit-mask-image: linear-gradient(to right, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 30px);
  mask-image: linear-gradient(to right, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 30px);
  pointer-events: none;
}

.promo > *:not(.promo__bg) {
  position: relative;
  z-index: 1;
}

.promo__icon {
  width: 50px;
  height: 50px;
}

.promo__title {
  font-size: 20px;
  font-weight: 700;
  /* 28/28 из макета (121:113): с 1.2 заголовок был на 6px выше и весь
     блок текста съезжал вверх относительно кнопки */
  line-height: 1;
  text-wrap: balance;
}

@media (min-width: 1024px) {
  .promo__title {
    font-size: 28px;
  }
}

.promo__note,
.btn--promo {
  grid-column: 1 / -1;
}

/* 18/20 из макета (328:553 — слой 320x60, три строки) */
.promo__note {
  font-size: 18px;
  font-weight: 500;
  line-height: 20px;
  opacity: 0.5;
}

@media (min-width: 1024px) {
  .promo__note {
    font-size: 20px;
  }
}

@media (min-width: 1024px) {
  .promo__bg {
    display: block;
  }

  .promo {
    grid-template-columns: 100px minmax(0, 559px) 1fr;
    grid-template-rows: auto auto;
    align-items: center;
    gap: 16px 44px;
    min-height: 196px;
    padding: 32px 44px;
    background-color: #fff4f6;
  }

  .promo__note {
    line-height: 1.4;
  }

  .btn--promo {
    font-size: 20px;
  }

  .promo__icon {
    grid-row: 1 / 3;
    align-self: center;
    width: 100px;
    height: 100px;
  }

  .promo__title {
    grid-column: 2;
    align-self: end;
  }

  .promo__note {
    grid-column: 2;
    grid-row: 2;
    align-self: start;
    line-height: 28px;
  }

  /* В макете (121:107) кнопка стоит на 826 от левого края панели, то есть
     не прижата к правому краю: между ней и краем остаётся 25px */
  .btn--promo {
    grid-column: 3;
    grid-row: 1 / 3;
    justify-self: start;
    align-self: center;
    margin-inline-start: 35px;
  }
}

/* ==================================================== Баннер приложения */

/* На мобильных не показываем: сверху страницы уже стоит .app-strip
   с теми же ссылками на магазины (так и в макете) */
.app {
  display: none;
  position: relative;
  overflow: hidden;
}

.app__content {
  position: relative;
  z-index: 1;
}

.app__heading {
  display: flex;
  flex-direction: column;
  gap: 13px;
  align-items: flex-start;
}

/* Блок Title в макете 355×81 — это 32 (заголовок) + 13 (gap) + 36
   (логотип), поэтому у заголовка интерлиньяж равен кеглю */
.app__title {
  font-size: 20px;
  font-weight: 700;
  line-height: 1;
}

@media (min-width: 1024px) {
  .app__title {
    font-size: 32px;
  }
}

.app__wordmark {
  width: 160px;
  height: auto;
}

.app__features {
  display: grid;
  gap: 22px;
  margin-block-start: 32px;
}

.app__feature {
  display: flex;
  align-items: center;
  gap: 16px;
  font-size: 18px;
  font-weight: 500;
  line-height: 24px;
}

@media (min-width: 1024px) {
  .app__feature {
    font-size: 20px;
  }
}

.app__feature img {
  width: 46px;
  height: 46px;
  flex-shrink: 0;
}

.app__stores {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-block-start: 32px;
}

.store {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 137px;
  height: 49px;
  padding-inline: 13px;
  border-radius: 5px;
  background-color: #000000;
  color: #ffffff;
}

.store__logo {
  flex-shrink: 0;
}

.store__text {
  display: flex;
  flex-direction: column;
  line-height: 1.1;
}

.store__hint {
  font-size: 10px;
}

/* В кнопку 137px «Google Play» помещается в одну строку только так:
   в макете это SF Pro Display, он уже Helvetica Neue при том же кегле */
.store__name {
  font-size: 15px;
  white-space: nowrap;
}

.app__art {
  display: none;
}

@media (min-width: 1024px) {
  .app-strip ~ #main {
    padding-block-start: 0;
  }

  /* Плашка установки — мобильная; на десктопе работает секция .app */
  .app-strip {
    display: none;
  }

  .app {
    display: block;
    min-height: 438px;
    padding: 80px;
  }

  .app__wordmark {
    width: 212px;
  }

  /* Отступы из макета (193:44): заголовок на 80, фичи на 211,
     кнопки магазинов на 309 от верха панели */
  .app__features {
    grid-auto-flow: column;
    justify-content: start;
    gap: 44px;
    margin-block-start: 50px;
  }

  .app__stores {
    margin-block-start: 50px;
  }

  /* Арт занимает весь баннер: координаты слоёв взяты из макета
     (194:130, 199:3, 213:53) и отсчитываются от его левого края */
  .app__art {
    display: block;
    position: absolute;
    inset: 0;
    pointer-events: none;
  }

  .app__blob,
  .app__bouquet,
  .app__phone {
    position: absolute;
    max-width: none;
  }

  /* Figma отдаёт рамку уже повёрнутого узла, а CSS вращает вокруг центра
     элемента — поэтому координаты пересчитаны из центра рамки:
     эллипс 429×456 (194:130), телефон 646×822 (213:53) */
  .app__blob {
    inset-block-start: 72px;
    inset-inline-start: 773px;
    width: 429px;
    height: 456px;
    rotate: 20.41deg;
  }

  .app__bouquet {
    inset-block-start: 46px;
    inset-inline-start: 571px;
    width: 624px;
    opacity: 0.81;
  }

  /* В макете мокап лежит в рамке 646×822 и показан не целиком: картинка
     увеличена до 217% и сдвинута. Повторяем это обрезкой — иначе телефон
     оказывается мельче и «лежит» не под тем углом. */
  .app__phone {
    inset-block-start: -4px;
    inset-inline-start: 621px;
    width: 646px;
    height: 822px;
    overflow: hidden;
    rotate: -7.39deg;
  }

  .app__phone img {
    position: absolute;
    inset-block-start: -22.23%;
    inset-inline-start: -71.27%;
    width: 217.37%;
    height: 127.09%;
    max-width: none;
  }
}

/* ================================================================ Футер */

.footer {
  margin-block-start: 44px;
  padding-block: 32px 22px;
  background-color: #ffffff;
}

.footer__top {
  display: grid;
  gap: 32px;
}

/* 168x60 из макета (328:449): 140 давало логотип заметно мельче
   нарисованного — это первое, что видно в подвале */
.footer__logo {
  width: 168px;
  height: auto;
}

.footer__tagline {
  margin-block-start: 22px;
  font-size: 14px;
  font-weight: 500;
  line-height: 26px;
  opacity: 0.5;
}

@media (min-width: 1024px) {
  .footer__tagline {
    font-size: 18px;
  }
}

/* Интерлиньяж 18 из макета (104:695 — заголовок и ссылки слоями
   по 18), а не браузерные 25.2: каждая строка была на 7px выше,
   и подвал вырос с 468 до 506 на всех страницах */
/* На мобильной заголовок колонки 16/16 (328:461 — «Информация» 104x16),
   на десктопе 18/18 */
.footer__title {
  margin-block-end: 20px;
  font-size: 16px;
  font-weight: 500;
  line-height: 16px;
}

/* Интерлиньяж на самом списке: ссылка внутри <li> строчная,
   и высоту пункта задаёт не она, а строка самого пункта */
/* Шаг пунктов 30 из макета (328:465 и ниже — 3366, 3396, 3426) */
.footer__list {
  display: grid;
  gap: 12px;
  line-height: 18px;
}

/* На мобильной ссылки колонок чёрные: в рендере макета (328:448) их
   модальный тон — (0,0,0), приглушены только слоган, правовые ссылки и
   копирайт. На десктопе, наоборот, приглушено всё — отсюда медиазапрос */
.footer__link {
  font-size: 14px;
  font-weight: 500;
  line-height: 18px;
  transition: opacity 0.15s ease, color 0.15s ease;
}

@media (min-width: 1024px) {
  .footer__link {
    font-size: 18px;
  }
}

.footer__link:hover,
.footer__link:focus-visible {
  opacity: 1;
  color: #dc0978;
}

.footer__muted {
  font-size: 14px;
  font-weight: 500;
  line-height: 18px;
}

@media (min-width: 1024px) {
  .footer__muted {
    font-size: 18px;
  }
}

.footer__contacts {
  display: grid;
  gap: 22px;
}

/* Строка контакта в подвале: тот же Medium, что и ссылки рядом
   (104:716) — Regular в полную силу выбивался. Гасим строку целиком:
   в макете иконка и текст одинаково приглушены (замер по рендеру —
   у обоих самый тёмный пиксель ровно 50% чёрного).

   Прозрачность обязана быть ровно одна. Когда она стояла и на строке,
   и на тексте внутри, они перемножились: 0.5 × 0.5 = 0.25, и блок
   контактов стал вдвое бледнее макета. */
.contact {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  font-weight: 500;
}

.contact .footer__link,
.contact .footer__muted {
  opacity: 1;
}

.contact img {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: 16px 22px;
  margin-block-start: 32px;
  padding-block-start: 22px;
  border-block-start: 1px solid #e5e5e5;
}

/* Копирайт и правовые ссылки — 26 (104:661…663), а не 18 как выше */
.footer__copy {
  order: 1; /* в мобильном макете копирайт стоит под правовыми ссылками */
  flex-basis: 100%;
  font-size: 14px;
  font-weight: 500;
  line-height: 26px;
  opacity: 0.5;
}

@media (min-width: 1024px) {
  .footer__copy {
    font-size: 18px;
  }
}

.footer__copy small {
  font-size: inherit;
}

@media (min-width: 1024px) {
  /* На десктопе приглушены и ссылки колонок, и строки контактов
     (104:695, 104:716) — на мобильной они в полную силу */
  .footer__link,
  .footer__muted,
  .contact {
    opacity: 0.5;
  }

  .contact .footer__link,
  .contact .footer__muted {
    opacity: 1;
  }

  .footer__title {
    margin-block-end: 22px;
    font-size: 18px;
    line-height: 18px;
  }

  .footer__list {
    gap: 16px;
  }

  .footer {
    padding-block: 44px 76px;
  }

  .footer__top {
    /* minmax, а не жёсткие ширины: сумма 976 плюс зазоры не влезала
       в контейнер 984 на ширине 1024 */
    grid-template-columns: minmax(0, 240px) minmax(0, 200px) minmax(0, 260px) minmax(0, 276px);
    justify-content: space-between;
    gap: 22px;
  }

  .footer__logo {
    width: 168px;
  }

  .footer__bottom {
    margin-block-start: 99px;
    gap: 22px 44px;
  }

  .footer__copy {
    order: 0;
    flex-basis: auto;
    margin-inline-end: auto;
  }
}

/* ------------------------------------------------------------ Дополнения */

/* Заголовок с подписью («Так же может понравиться» на странице товара):
   в макете он мельче обычного заголовка секции — 20/20 против 32 */
.section__head--stacked {
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
  margin-block-end: 22px;
}

/* 20/20 на обеих ширинах (295:1385 — «Так же может понравиться» слой
   268x20): --fs-body-lg на 400 равен 18, и заголовок был мельче */
.section__head--stacked .section__title {
  font-size: 20px;
  line-height: 20px;
}

@media (min-width: 1024px) {
  .section__head--stacked .section__title {
    font-size: 32px;
  }
}

@media (min-width: 1024px) {
  .section__head--stacked .section__title {
    font-size: 20px;
  }
}

.section__sub {
  font-size: 14px;
  line-height: 18px;
  opacity: 0.5;
}

@media (min-width: 1024px) {
  .section__sub {
    font-size: 18px;
  }
}

.addons {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 22px;
}

/* Рекомендации в корзине идут по три в ряд (295:1618 — шесть плиток
   90x181 с шагом 112.67), а не по две */
.addons--compact {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 22px 22px;
}

.addons > li {
  display: flex;
}

.addon {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 16px;
  border-radius: 15px;
  background-color: #ffffff;
  box-shadow: 0 4px 12px 0 rgb(205 205 205 / 0.25);
}

.addon__media {
  display: block;
  height: 106px;
  border-radius: 15px;
  overflow: hidden;
}

.addon__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.addon__title {
  margin-block-start: 22px;
  font-size: 16px;
  font-weight: 500;
  line-height: 20px;
}

.addon__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.addon__price {
  margin-block-start: auto;
  padding-block-start: 16px;
  padding-inline-end: 44px;
  font-size: 18px;
  font-weight: 700;
}

@media (min-width: 1024px) {
  .addon__price {
    font-size: 20px;
  }
}

/* Позиционируется форма, а не кнопка: иначе в колонке карточки
   оставался бы пустой блок от обёртки */
.addon__form {
  position: absolute;
  z-index: 1;
  inset-block-end: 16px;
  inset-inline-end: 16px;
}

.addon__add {
  display: grid;
  place-items: center;
  width: 35px;
  height: 35px;
  border-radius: 50%;
  background-color: #dc0978;
}

.addon__add:hover {
  background-color: #e23f8f;
}


/* Шеврон-стрелка. Самостоятельный блок: встречается и в «Особенном
   подарке», и в ссылке «Подробнее» корзины — элементом .gift быть не может. */
/* 20×13 из макета. Уголок из двух границ давал квадратные 10×10 —
   он заметно мельче и острее нарисованного. Рисуем маской, чтобы
   цвет наследовался от текста. */
/* Фоном, а не маской. mask-image со сторонним SVG в Chrome подчиняется
   правилу общего источника, и на странице, открытой файлом с диска
   (file://), маска не рисуется вовсе — иконка молча пропадает. Цвет у
   этих шевронов постоянный, наследовать его неоткуда, так что фон ничего
   не отнимает. */
.chevron {
  flex-shrink: 0;
  width: 20px;
  height: 13px;
  background: url("../../assets/icons/chevron.svg") center / contain no-repeat;
  opacity: 0.8;
}

/* Шеврон вправо (в макете это SF Symbol chevron.forward, 13x20). Поворот
   запечён в сам файл: повёрнутый через rotate псевдоэлемент рисовался не
   везде. В макете он в полную силу */
.chevron--forward {
  width: 13px;
  height: 20px;
  background-image: url("../../assets/icons/chevron-forward.svg");
  opacity: 1;
}

/* Дополнения: десктопная сетка (общая для товара и корзины) */
@media (min-width: 1024px) {
  .addons {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }

  .addons--compact {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}


/* ==========================================================================
   Общие блоки страниц заказа: заголовок страницы, итоги, гарантия
   (используются и корзиной, и оформлением заказа)
   ========================================================================== */

/* Заголовок занимает ровно свой кегль (39:625 — 36/36): с 1.15 он был
   на 5px выше и всё под ним съезжало */
/* 40/40 на десктопе и 20/20 на мобильной. Слой «Корзина» в макете
   170x40, а та же строка в браузере при 40 даёт ровно 170 (при 36 — 153);
   на мобильной 85x20 (300:1555). Раньше считалось, что 40 — это
   высота слоя при кегле 36 */
.page-title {
  margin-block-start: 32px;
  font-size: 20px;
  font-weight: 700;
  line-height: 1;
}

@media (min-width: 1024px) {
  .page-title {
    font-size: 40px;
  }
}

.totals__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-block-end: 16px;
  font-size: 16px;
  font-weight: 500;
  line-height: 16px;
}

.totals__count {
  opacity: 0.5;
  white-space: nowrap;
}

.totals__list {
  display: grid;
  gap: 16px;
  margin: 0;
}

.totals__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  font-size: 16px;
  font-weight: 500;
  line-height: 16px;
}

.totals__row dd {
  margin: 0;
  white-space: nowrap;
}

.totals__key,
.totals__val {
  opacity: 0.5;
}

.totals__rule {
  height: 0;
  margin-block: 16px;
  border: 0;
  border-block-start: 1px solid #e5e5e5;
}

.totals__sum {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  font-weight: 500;
  line-height: 20px;
}

.totals__sum-key {
  font-size: 16px;
}

.totals__sum-val {
  font-size: 18px;
  font-weight: 700;
  white-space: nowrap;
}

@media (min-width: 1024px) {
  .totals__sum-val {
    font-size: 20px;
  }
}

.totals__cta {
  width: 100%;
  min-height: 48px;
  margin-block-start: 16px;
  font-size: 16px;
  line-height: 16px;
}

/* Блок гарантии есть только в десктопных макетах (53:115, 234:2 и
   соседние); ни на одном из четырёх мобильных шагов оформления и в
   мобильной корзине его нет. Он же давал горизонтальную прокрутку:
   его минимальная ширина 384 при колонке 360 растягивала всю сетку */
.guarantee {
  display: none;
  align-items: center;
  gap: 18px;
  padding: 22px;
  border-radius: 15px;
  background-color: #fff4f6;
}

@media (min-width: 1024px) {
  .guarantee {
    display: flex;
  }
}

.guarantee__icon {
  flex-shrink: 0;
  width: 53px;
  height: 53px;
}

.guarantee__text {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Заголовок блока гарантии в макете (234:4) брендовый и жирный,
   а не чёрный: розовым он и читается как обещание, а не как подпись */
/* В макете (56:8) заголовок ровно 270 при таком же свободном месте —
   запаса нет вовсе, и в браузере с чуть другими метриками он срывался
   на вторую строку. Держим строку принудительно: лишние пиксели уходят
   в поля панели, перенос был заметнее */
.guarantee__title {
  color: #dc0978;
  font-size: 16px;
  font-weight: 700;
  line-height: 16px;
  white-space: nowrap;
}

.guarantee__note {
  font-size: 14px;
  font-weight: 500;
  line-height: 18px;
  opacity: 0.5;
}


/* Заголовок страницы: десктопный отступ */
@media (min-width: 1024px) {
  .page-title {
    margin-block-start: 44px;
  }
}


/* ==========================================================================
   Поля формы — общий примитив (оформление заказа, контакты)
   ========================================================================== */

.req {
  color: #ca0606;
}

/* Высота 50 из макета (44:1073 — ряд полей 751x50) задаётся
   min-block-size, а не паддингом: с вертикальными 16 и рамкой
   получалось 58, и каждый ряд сдвигал всё ниже на 8px */
.field-wrap {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  min-block-size: 50px;
  padding-inline: 16px;
  border: 1px solid rgb(0 0 0 / 0.15);
  border-radius: 15px;
  background-color: #ffffff;
}

.field-wrap:focus-within {
  border-color: #dc0978;
}

.field-wrap:has(:focus-visible) {
  outline: 2px solid #dc0978;
  outline-offset: 1px;
}

.field-wrap__icon {
  flex-shrink: 0;
}

.field-wrap__input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: none;
  font-size: 16px;
}

.field-wrap__input:focus {
  outline: none;
}

.field-wrap__input::placeholder {
  color: #000000;
  opacity: 0.5;
}

.field-wrap__input--select {
  appearance: none;
  color: #000000;
  cursor: pointer;
  background-image: url("../../assets/icons/chevron.svg");
  background-position: calc(100% - 4px) center;
  background-size: 20px 13px;
  background-repeat: no-repeat;
}

/* ============================================ Оверлеи: меню и город */

/* Открываются по :target — то есть обычной ссылкой, без JS. Скрытое
   состояние — display: none, поэтому панель не висит в порядке обхода,
   пока закрыта. Скрипт добавляет Esc, клик мимо панели и возврат фокуса. */

.overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 200;
  isolation: isolate;
}

.overlay:target {
  display: flex;
}

/* Пока оверлей открыт, страница под ним не должна прокручиваться.
   :has() делает это без JS — как и само открытие. */
body:has(.overlay:target) {
  overflow: hidden;
}

.overlay::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: rgb(0 0 0 / 0.25);
}

.overlay--center {
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.overlay__panel {
  position: relative;
  overflow-y: auto;
  overscroll-behavior: contain;
  background-color: #ffffff;
}

.overlay__close {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 26px;
  height: 26px;
}

/* ------------------------------------------------------ Шторка меню */

.drawer {
  display: flex;
  flex-direction: column;
  gap: 20px;
  width: 340px;
  max-width: 85%;
  height: 100%;
  padding: 20px;
}

@media (min-width: 1024px) {
  .drawer {
    gap: 32px;
  }
}

.drawer__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.drawer__search {
  gap: 10px;
  min-height: 48px;
  padding-block: 0;
}

.drawer__find {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  opacity: 0.5;
}

.menu {
  display: grid;
}

/* Разделители из макета — линии между пунктами, а не рамка списка */
.menu__item + .menu__item {
  border-block-start: 1px solid rgb(0 0 0 / 0.15);
}

/* Отступы 20/20 из макета лежат на ссылке, а не на пункте: так строка
   целиком кликабельна — 56px вместо 16px у одного текста */
.menu__link {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-block: 20px;
  font-size: 16px;
  font-weight: 500;
  line-height: 1;
}

@media (min-width: 1024px) {
  .menu__link {
    padding-block: 32px;
  }
}

.menu__link:hover {
  color: #dc0978;
}

.menu__value {
  margin-inline-start: auto;
  opacity: 0.5;
}

/* Контакты прижаты к низу шторки */
.drawer__foot {
  display: grid;
  gap: 20px;
  margin-block-start: auto;
  padding-block-start: 20px;
  border-block-start: 1px solid rgb(0 0 0 / 0.15);
}

@media (min-width: 1024px) {
  .drawer__foot {
    gap: 32px;
    padding-block-start: 32px;
  }
}

.drawer__row {
  display: flex;
  align-items: center;
  gap: 16px;
  font-size: 14px;
  font-weight: 500;
}

.drawer__row img {
  flex-shrink: 0;
}

/* --------------------------------------------------- Модалка города */

.city-modal {
  display: grid;
  gap: 32px;
  width: 360px;
  max-width: 100%;
  max-height: 100%;
  padding: 20px;
  border-radius: 25px;
  box-shadow: 0 4px 12px 0 rgb(205 205 205 / 0.25);
}

.city-modal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.city-modal__title {
  font-size: 20px;
  font-weight: 700;
  line-height: 22px;
}

@media (min-width: 1024px) {
  .city-modal__title {
    font-size: 22px;
  }
}

/* Высота 50 из макета задаётся min-height, иначе паддинги поля дают 56 */
.city-modal__field {
  min-height: 50px;
  padding-block: 0;
}

.city-list {
  display: grid;
}

/* Шаг 50 из макета набирается отступами самой ссылки: строка целиком
   становится зоной нажатия, а не 18px текста */
.city-list__link {
  display: block;
  padding-block: 16px;
  font-size: 18px;
  font-weight: 500;
  line-height: 1;
  color: #dc0978;
}

@media (min-width: 1024px) {
  .city-list__link {
    font-size: 20px;
  }
}

.city-list__link:hover {
  text-decoration: underline;
}

.city-list__link[aria-current] {
  text-decoration: underline;
}

/* Шапка нарисована под 1440. От 1024 до ~1240 всё вместе не помещается —
   ещё на системном шрифте меню уезжало на две строки. Убираем телефон:
   он есть в подвале и в шторке меню, а на ноутбуке по нему не звонят. */
@media (min-width: 1024px) and (max-width: 1240px) {
  .header__phone {
    display: none;
  }
}

/* ==========================================================================
   Всплывающие уведомления
   ========================================================================== */

/*
 * По макету из правок: карточка с фото товара, розовым заголовком и
 * подписью. На мобильной всплывает сверху, на десктопе — справа снизу.
 * Контейнер помечен role="status" + aria-live, поэтому текст уведомления
 * читается диктором сам, без переноса фокуса.
 */
.toasts {
  position: fixed;
  z-index: 40;
  inset-block-start: 16px;
  inset-inline: 16px;
  display: grid;
  gap: 16px;
  justify-items: stretch;
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px;
  border-radius: 15px;
  background-color: #ffffff;
  box-shadow: 0 4px 12px 0 rgb(205 205 205 / 0.25);
  pointer-events: auto;
  animation: toast-in 0.2s ease-out;
}

/* Уведомление появляется рывком — уважаем системную настройку */
@media (prefers-reduced-motion: reduce) {
  .toast {
    animation: none;
  }
}

@keyframes toast-in {
  from { opacity: 0; translate: 0 -8px; }
  to   { opacity: 1; translate: 0 0; }
}

.toast__photo {
  flex-shrink: 0;
  width: 60px;
  height: 60px;
  border-radius: 15px;
  object-fit: cover;
}

.toast__text {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1 1 auto;
  min-width: 0;
}

.toast__title {
  color: #dc0978;
  font-size: 16px;
  font-weight: 700;
}

.toast__note {
  font-size: 14px;
  font-weight: 500;
  line-height: 21px;
  opacity: 0.5;
}

.toast__close {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  align-self: start;
}

@media (min-width: 1024px) {
  /* На десктопе — правый нижний угол, ширина как у карточки сводки */
  .toasts {
    inset-block: auto 32px;
    inset-inline: auto 32px;
    width: 385px;
  }

  .toast__photo {
    width: 74px;
    height: 74px;
  }

  @keyframes toast-in {
    from { opacity: 0; translate: 0 12px; }
    to   { opacity: 1; translate: 0 0; }
  }
}

/* ==========================================================================
   «Показать ещё» — дозагрузка каталога
   ========================================================================== */

.more {
  display: grid;
  justify-content: center;
  margin-block-start: 32px;
}

.more__btn {
  min-width: 240px;
  min-height: 59px;
  padding-inline: 32px;
}

/* Пока идёт запрос, кнопка занята: повторное нажатие ничего не добавит */
.more__btn[aria-busy="true"] {
  opacity: 0.8;
  cursor: progress;
}

/* ==========================================================================
   Ошибки полей формы
   ========================================================================== */

/*
 * Управляется двумя способами и оба дают одинаковый результат:
 *  1) с сервера — на обёртке класс is-error, следом <p class="field-error">;
 *  2) из скрипта — Cvetofor.setFieldError('customer-name', 'Свой текст').
 * Цвет не единственный признак: у поля aria-invalid, под ним текст, и он
 * связан с полем через aria-describedby.
 */
.field-wrap.is-error {
  border-color: #ca0606;
}

.field-wrap.is-error:focus-within {
  border-color: #ca0606;
  outline-color: #ca0606;
}

.field-error {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-block-start: 8px;
  color: #ca0606;
  font-size: 16px;
  font-weight: 500;
  line-height: 22px;
}

.field-error img {
  flex-shrink: 0;
}

/* Поле с ошибкой и его подпись — одна колонка сетки: сообщение не должно
   раздвигать соседнее поле в паре */
.field-group {
  display: grid;
  min-width: 0;
}
