/* Besfo — оболочка: шапка, мегаменю, подвал, мобильная панель.
   Общая для всех страниц: правится здесь — меняется везде. */
/* Шрифт подключен через <link rel="stylesheet"> (см. ниже, сразу
     после закрытия этого style) — специально не в начале head, как
     было раньше. Причина: внешний CSS-файл блокирует рендеринг, а значит и разбор ЛЮБОГО HTML/CSS, что идет
     ПОСЛЕ него, пока не скачается. Если поставить его раньше нашего
     style, вся верстка (sticky-footer, скрытые по умолчанию блоки типа
     .catalog-panel и .mobile-bottom-nav) не применяется, пока шрифт не
     загрузится — страница на долю секунды рендерится «сырой», а потом
     резко перестраивается разом. Наш style должен идти первым.
     display=block: текст ненадолго невидим при холодной загрузке (обычно
     доли секунды благодаря preconnect + ранней загрузке через link),
     зато никогда не показывает неправильный вид шрифта — в отличие от
     swap/fallback (виден не тот шрифт, потом дергается) и optional
     (может вообще не подгрузиться, тогда font-weight:600 рисуется через
     Arial Bold — визуально толще, чем нужно). Пробовали и то, и другое —
     это было признано лучшим компромиссом. Начертания: 400 неявно как
     дефолт браузера, 500/600/700 — явно в CSS; 800 нигде не используется
     и убран. */
* { margin:0; padding:0; box-sizing:border-box; }
/* ПОДЧЕРКИВАНИЯ В ПРОЕКТЕ НЕТ. Ни у ссылок, ни у кнопок-слов, ни пунктиром.
   Снимается один раз здесь, а не по классу у каждой ссылки: так его нельзя
   забыть снять на новом элементе.

   Чем тогда ссылка отличается от текста. Цветом --color-action (#156FF8):
   4.51:1 на белом — читается как текст, и 3.86:1 против окружающего
   --color-text — то есть отличается от него заметно, с запасом над порогом
   3:1, который WCAG требует для различения ссылки без подчеркивания.
   Плата известна: человеку с нарушением цветовосприятия ссылка внутри абзаца
   дается труднее, чем подчеркнутая. Решение принято сознательно. */
a { text-decoration:none; }

/* Атрибут hidden ОБЯЗАН прятать элемент. Своим display: none он прячет его
   только из таблицы браузера, и любое наше объявление display перебивает его:
   элемент помечен hidden, скрипт считает его скрытым, а он на экране.
   На этом я уже дважды прокололся — стрелка колонки миниатюр и сводка
   отзывов, — поэтому правило стоит одно на весь проект.
   !important здесь не небрежность: у [hidden] и у класса одинаковый вес, и
   без него побеждает то, что написано ниже по файлу, то есть случайность. */
[hidden] { display: none !important; }

/* ── Место под жирное начертание ──────────────────────────────────────────
   Если выбранное состояние набрано жирнее обычного, ширина строки меняется
   при переключении, и соседи прыгают. На вкладках это выглядит поломкой:
   нажал «По дате» — «По полезности» рядом дернулось.

   Место резервируется заранее: скрипт замеряет, сколько элемент занял бы в
   жирном начертании, и ставит эту величину минимальной шириной. Перевод
   элемента в сетку с невидимой копией надписи не подошел — у части этих
   элементов внутри есть свои узлы (счетчик у вкладки), и сетка ломала их
   расположение. */
/* Элементы форм НЕ наследуют шрифт — браузер дает им свой, системный. Без
   этой строки каждая кнопка в проекте набрана не Inter, а гарнитурой
   операционной системы: кегль и вес мы задавали, а гарнитуру нет, и отличие
   заметно только рядом с обычным текстом. */
button, input, select, textarea { font-family: inherit; }
/* Спрайт знаков. Прячется классом, а не встроенным стилем: встроенные стили
   в разметке — это правило в обход системы, его нельзя ни переопределить, ни
   найти при правке. */
.sprite { display: none; }
/* overflow-x:hidden оставлен ТОЛЬКО на html: его overflow браузер
     пробрасывает на вьюпорт, так что горизонтальный скролл подрезается
     ровно как раньше.
     А вот height:100% на body убрано намеренно, это была мина. Связка
     `height:100%` + `overflow-x:hidden` на body давала: (1) высоту body
     ровно 100vh, (2) вычисленный overflow-y:auto — правило CSS, по
     которому overflow-y при overflow-x:hidden не может остаться visible.
     Вместе это делает САМ body скролл-контейнером: контент выше экрана
     скроллится ВНУТРИ body, а не в документе. Пока <main> почти пустой,
     это не видно. Как только туда ляжет каталог — window.scrollY навсегда
     останется 0 (ломается и блокировка скролла каталога ниже, и
     восстановление позиции), position:sticky перестанет срабатывать,
     а мобильные браузеры перестанут прятать адресную строку при скролле.
     Sticky-footer от этого не страдает: его держит min-height:100dvh +
     grid-template-rows, а не height:100%. */
html { overflow-x:hidden; }
body {
    font-family: var(--font-main); background:var(--color-white);
    min-height:100vh; min-height:100dvh;
    display:grid; grid-template-rows:auto 1fr auto;
    /* minmax(0, 1fr), а не значение по умолчанию. Когда задан только
       grid-template-rows, колонка создается неявно с размером auto, а
       минимум у auto — это min-content самого широкого содержимого.
       Строка быстрых ссылок в шапке — 8 пунктов с white-space:nowrap,
       вместе около 1500px. Колонка честно растягивалась под них,
       .container упирался в свой max-width:1440px — и ВСЯ страница,
       включая подвал, раскладывалась на 1440px независимо от ширины
       окна. Media query при этом отрабатывали правильно (отступы и
       раскладка брались от реальной ширины), поэтому со стороны это
       выглядело как «адаптив не работает». overflow-x:hidden на html
       только обрезал результат, из-за чего не было даже скроллбара,
       по которому проблему было бы видно.
       minmax(0, 1fr) убирает минимум в ноль: колонка больше не может
       стать шире окна, что бы внутрь ни положили. */
    grid-template-columns: minmax(0, 1fr);
  }
.breadcrumbs { background:var(--color-white); }
.breadcrumbs .container { display:flex; flex-wrap:wrap; align-items:center; padding-top:var(--gap-component); padding-bottom:var(--gap-block); min-height:60px; }
.breadcrumbs ol { display:flex; flex-wrap:wrap; align-items:center; list-style:none; gap:var(--gap-inner); }
.breadcrumbs li { display:flex; align-items:center; gap:var(--gap-inner); font-weight:var(--fw-body); }
.breadcrumbs li:not(:last-child)::after { content:'—'; color:var(--color-separator); font-size:var(--text-caption); }
/* Начертание Body (400), а не Interface (500). Крошки — путь по разделам, а
   не ярлык управления: 500 добавляет плотности коротким надписям на кнопках и
   в меню, а здесь строка длинная и читаемая, и лишний вес тянул ее к уровню
   заголовка, под которым она стоит.
   Кегль остается ступенью Interface, меняется только вес — сочетание
   14/20/400 в системе описано. */
.breadcrumbs a { display:inline-flex; align-items:center; padding:var(--gap-tight) 0; font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-body); color:var(--color-text-secondary); text-decoration:none; }
/* На телефоне крошки НЕ переносятся, а прокручиваются пальцем в одну строку.
   Перенос съедал до трех строк высоты в самом верху экрана — ровно там, где
   она нужнее всего, а путь по разделам читается и по горизонтали.
   overscroll-behavior-inline: contain — чтобы прокрутка крошек до упора не
   уводила за собой всю страницу или историю браузера (свайп «назад»).
   Поля контейнера переносятся на саму ленту: иначе последний пункт упирался
   бы в край экрана без отступа. */
@media (max-width: 1024px) {
  .breadcrumbs .container {
      flex-wrap:nowrap; overflow-x:auto; padding-left:0; padding-right:0;
      scrollbar-width:none; overscroll-behavior-inline:contain;
      -webkit-overflow-scrolling:touch;
    }
  .breadcrumbs .container::-webkit-scrollbar { display:none; }
  .breadcrumbs ol { flex-wrap:nowrap; padding:0 var(--container-pad); }
  .breadcrumbs li, .breadcrumbs a { white-space:nowrap; }
}
/* Высота заголовка равна его тексту. Прежде здесь стояла min-height: 64px —
   число, которое ничего не отмеряло: при одной строке текст занимает 36px, и
   оставшиеся 20 превращались в пустоту под заголовком. Заявленный отступ до
   следующего блока был 8px, видимый — около 30.
   Листингу это мешало уже давно, и он гасил min-height своим правилом. То,
   что правило понадобилось, и было признаком: значение лишнее не на одной
   странице, а вообще. Расстояние задают роли, а не запас по высоте. */
.page-title { font-size:var(--text-h1); line-height:var(--lh-h1); font-weight:var(--fw-h1); color:var(--color-text); padding:0 0 var(--gap-inner); text-align:left; box-sizing:border-box; }
/* ============================================================
     СПРАВОЧНАЯ СЕТКА ДЛЯ БУДУЩЕГО КАТАЛОГА (12 колонок, десктоп 1440px)
     ============================================================
     12 колонок × 98px + 11 промежутков × 24px = 1440px — сходится
     ровно с общей max-width сайта, ничего досчитывать не нужно.
     Мобилка (360-390px): 2 карточки в ряд по 158px, между ними
     12px, по бокам safe-margin 16px — тоже сходится ровно в 360px.
     Использовать через CSS Grid: grid-template-columns:repeat(12, 1fr);
     gap: var(--space-lg) — карточка на N колонок через grid-column:
     span N. Пока в файле нет самого каталога — эта сетка не применена
     нигде, просто зафиксирована как готовая к использованию.
     ============================================================ */
/* Без background-attachment:fixed. При fixed фон раскладывался по ВСЕМУ ОКНУ,
     а не по шапке: шапке доставался кусок примерно с 10% по 67% шкалы
     градиента, крайние цвета #D81E1E и #FF3B3B не появлялись на экране вообще,
     а видимый кусок зависел от высоты окна — на большом мониторе шапка ровнее
     и темнее, на ноутбуке контрастнее. Плюс fixed заставляет браузер
     перерисовывать фон при каждом скролле и не работает в iOS Safari.
     Теперь фон привязан к самой шапке: полный диапазон градиента, одинаковый
     вид при любом размере окна и на любом брейкпоинте. */
.site-header-real { background:var(--header-gradient); position:relative; border-radius:0 0 var(--radius-block) var(--radius-block); }
.container { width:100%; max-width:1440px; margin:0 auto; padding:0 var(--container-pad); }
.header-top { display:flex; align-items:center; height:48px; }
/* font-weight 500 — компромисс между прежними 600 (визуально
     перетяжеленные) и 400 (визуально серые).
     Причина, по которой 400 здесь не работает, оптическая, а не в цвете:
     текст и так чистый #ffffff, но при кегле 14px стебель буквы выходит
     примерно 1,3px, то есть глиф почти целиком состоит из сглаженных краев.
     Замер по скриншоту: у ленты на 400 полностью белых пикселей всего 7%,
     остальные 93% браузер смешивает с красным фоном — глаз усредняет эту
     массу и видит розовато-серый. Для сравнения, темный текст по белому
     дает 99% сплошных пикселей: светлое по темному теряет на сглаживании
     несравнимо больше.
     500 возвращает букве сердцевину, оставаясь заметно легче 600.
     Полужирным в шапке остается только кнопка «Каталог»: там начертание
     работает признаком действия, а не оформлением текста. */
.header-geo { display:flex; flex-wrap:wrap; align-items:center; gap:var(--gap-inner); color:var(--color-white); font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-ui); }
.header-geo__sep { width:4px; height:4px; border-radius:50%; background:var(--color-white); flex-shrink:0; position:relative; top:2px; visibility:hidden; }
body.fonts-ready .header-geo__sep { visibility:visible; }
.header-geo__city { display:flex; align-items:center; gap:var(--gap-tight); min-height:25px; cursor:pointer; opacity:1; transition:opacity .2s ease-in-out; border:0; background:none; padding:0; font:inherit; color:inherit; min-width:230px; }
/* ОПТИЧЕСКАЯ ПОДГОНКА ИКОНКИ, не отступ. Дробное значение компенсирует
     пустое поле внутри самого SVG: иконка нарисована в квадрате 24x24, но
     видимая метка занимает не весь квадрат, и по краю остается воздух.
     Без сдвига метка визуально стояла бы дальше от края и ближе к тексту,
     чем задано. Пара взаимно погашается (-3.6 слева, +3.6 справа), то есть
     на раскладку соседей не влияет. На шкалу отступов такие подгонки не
     распространяются — см. раздел 3 дизайн-системы. */
.header-geo__city svg { width:24px; height:24px; flex-shrink:0; margin-left:-3.6px; margin-right:3.6px; }
/* Обе кнопки гео-строки лежат в ряду высотой 48px и центрируются в нем,
     поэтому min-height:25px не меняет вид, только увеличивает цель. */
.header-geo__pickup { display:inline-flex; align-items:center; min-height:25px; color:var(--color-white); font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-ui); text-decoration:none; white-space:nowrap; cursor:pointer; opacity:1; transition:opacity .2s ease-in-out; border:0; background:none; padding:0; font-family:inherit; visibility:hidden; }
body.fonts-ready .header-geo__pickup { visibility:visible; }
/* Ссылка «Для бизнеса» — у правого края верхней строки, напротив города.
     Набор тот же, что у соседей по строке: белый, роль Interface, вес 500 —
     причина веса описана выше у .header-geo. Цель добирается min-height, как у
     кнопок гео-строки: строка 48px центрирует ее, вид не меняется. */
.header-b2b { display:inline-flex; align-items:center; min-height:25px; margin-left:auto; color:var(--color-white); font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-ui); white-space:nowrap; transition:opacity .2s ease-in-out; }
.header-b2b:active { opacity:.8; }
.header-main-row { display:flex; flex-wrap:nowrap; align-items:center; min-height:48px; }
.header-left { display:flex; align-items:center; gap:var(--gap-component); flex:0 0 auto; margin-right:var(--gap-component); }
.logo { display:flex; align-items:center; }
.logo svg { height:34px; width:auto; display:block; }
.search-form { position:relative; flex:1 1 260px; min-width:0; margin-right:var(--gap-section); }
.search-form .input-wrap {
    position:relative; height:48px; background:var(--color-white); border-radius:8px;
    display:flex; align-items:center; min-width:0;
    /* Контура НЕТ, и это не упущение. WCAG 1.4.11 требует 3:1 для границы
       элемента управления, но само правило оговаривает: граница не нужна,
       если элемент отличим другим способом. Здесь он отличим собственной
       заливкой — белое поле на красной шапке дает 5.56:1 при норме 3.
       Замерено по отрисованной странице, цвет шапки снят пипеткой (205,28,28).
       На белой подложке такой прием не сработал бы, и там контур обязателен. */
    border:0; box-sizing:border-box;
  }
.search-form input {
    flex:1; min-width:0; border:0; background:transparent; padding:var(--gap-inner) 48px var(--gap-inner) var(--gap-block); height:100%;
    font-family:inherit; font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-body); color:var(--color-text); outline:none;
  }
.search-form input::placeholder { color:var(--color-text-muted); transition: color .15s ease; }
.search-form .search-btn {
    /* Кнопка 25x25 при иконке 20x20 — размер цели по WCAG 2.2. Сдвиг right
       компенсирует прирост, чтобы лупа осталась ровно там же, где была:
       кнопка выросла на 5px, ее центр уехал бы влево на половину этого. */
    position:absolute; right:calc(16px - (25px - 20px) / 2); top:50%; transform:translateY(-50%);
    width:25px; height:25px; justify-content:center; background:none; border:0; padding:0; cursor:pointer;
    display:flex; align-items:center; justify-content:center;
    /* Цвет знака задается здесь, а не в самом SVG. В разметке у контура лупы
       стоял fill="#929292" — число в обход токенов, и перекрасить знак было
       нечем. Теперь он наследует цвет кнопки через currentColor. */
    color:var(--color-text-muted);
    transition: opacity .15s ease, color .15s ease;
  }
.account-menu {
    display:flex; align-items:center; gap:var(--gap-component); flex:0 0 auto; margin-left:auto;
    width:220px;
  }
/* На <=1024 подпись скрыта и целью остается иконка 24x24 — ровно на границе
     минимума. min-height:25px убирает пограничность, на вид не влияет. */
.account-menu .link {
    display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--gap-tight); min-height:25px;
    color:var(--color-white); text-decoration:none; cursor:pointer; position:relative;
  }

  @media (min-width: 1025px){
  .account-menu .account-item:nth-child(1) .link { min-width:66px; }
  .account-menu .account-item:nth-child(2) .link { min-width:53px; }
  .account-menu .account-item:nth-child(3) .link { min-width:52px; }
  }
.account-menu .icon { width:24px; height:24px; position:relative; display:flex; align-items:center; justify-content:center; }
.account-menu .icon svg { width:24px; height:24px; display:block; opacity:1; transition: opacity .2s ease-in-out; }
/* Ограничение по ширине — ТОЛЬКО у профиля: имя пользователя произвольной
     длины иначе растолкало бы соседние пункты. У корзины подписи быть
     обрезанной нельзя: там сумма, и «253 99…» вводит в заблуждение сильнее,
     чем чуть более широкий пункт. Она растет по содержимому. */
.account-menu [data-nav="profile"] .label { max-width:88px; overflow:hidden; text-overflow:ellipsis; }
.mobile-bottom-nav [data-nav="profile"] .label { max-width:84px; overflow:hidden; text-overflow:ellipsis; }
.account-menu .label { font-size:var(--text-caption); line-height:var(--lh-caption); font-weight:var(--fw-caption); color:var(--color-white); white-space:nowrap; opacity:1; transition: opacity .2s ease-in-out; }
/* hidden объявлен явно: у .nav-badge стоит display:flex, а он перебивает
     браузерное правило [hidden]{display:none}. Пустая корзина не показывает
     ноль — счетчика просто нет. */
.nav-badge[hidden] { display:none; }
.nav-amount {
    font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-ui);
    font-feature-settings:"tnum";
  }
.account-item { position:relative; }
/* Карточка показывается только там, где есть настоящее наведение мышью.
     На тач-экранах наведения не существует: палец либо не касается, либо уже
     нажал, — и карточка либо не появится, либо перехватит переход по ссылке.
     Поэтому весь блок закрыт media-условием (hover: hover). */
.nav-popover { display:none; }

  @media (hover: hover) and (pointer: fine){
  .nav-popover {
      position:absolute; top:100%; right:0; z-index:70;
      /* Ширина = прежняя рабочая область 232px плюс две набивки: при
         увеличении набивки (17.09.2026) содержимое не должно переноситься
         иначе. Набивка — роль всплывающей карточки. */
      display:block; width:calc(232px + 2 * var(--pad-box-lg)); margin-top:var(--gap-inner); padding:var(--pad-box-lg);
      background:var(--color-white); color:var(--color-text);
      border-radius:8px; box-shadow:var(--shadow-popover);
    }
  .nav-popover[hidden] { display:none; }
  /* Мост через зазор между ссылкой и карточкой. Без него курсор, идущий
       к карточке, на мгновение оказывается вне обоих элементов, наведение
       слетает и карточка закрывается прямо под рукой. Требование WCAG
       1.4.13: содержимое, показанное по наведению, должно быть достижимо
       указателем. */
  .nav-popover::before {
      content:''; position:absolute; left:0; right:0; top:-8px; height:8px;
    }
  .nav-popover__title { font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-h2); }
  .nav-popover__text {
      margin-top:var(--gap-inner);
      font-size:var(--text-caption); line-height:var(--lh-caption); font-weight:var(--fw-caption);
      color:var(--color-text-secondary);
    }
  .nav-popover__btn {
      display:flex; align-items:center; justify-content:center;
      margin-top:var(--gap-block); min-height:40px; padding:var(--gap-inner) var(--gap-block); border-radius:8px;
      /* Серая кнопка — навигация и вспомогательные действия («Открыть
         каталог»). Черных кнопок в проекте нет (решение заказчика 17.09.2026).
         Вид тот же, что у «Написать отзыв»: светлая плашка, основной текст,
         наведение и нажатие — на ступень темнее. */
      background:var(--color-gray-light); color:var(--color-text); text-decoration:none;
      font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-h2);
      transition:background-color .15s ease;
    }
  .nav-popover__btn:hover { background:var(--color-border); }
  .nav-popover__btn:active { background:var(--color-gray-pressed); }
  /* Главная кнопка конверсионного действия — вход или шаг к покупке: красная
     (решение заказчика 17.09.2026). «Войти» у гостя и «Перейти в корзину» в
     мини-корзине. Кнопка без модификатора — навигация («Перейти в каталог» в
     пустой корзине) и остается темной.
     Белый на --color-cta — 4.63:1, наведение темнее на ступень, как у
     «В корзину» в карточке. Правило наведения стоит ПОСЛЕ темного: вес
     селекторов одинаковый, и при обратном порядке кнопка темнела бы. */
  /* Цвет текста и нажатие заданы явно: базовая кнопка серая с темным
     текстом, и без этих строк красная унаследовала бы и то и другое. */
  .nav-popover__btn--cta { background:var(--color-cta); color:var(--color-white); }
  .nav-popover__btn--cta:hover,
  .nav-popover__btn--cta:active { background:var(--color-cta-hover); }
  /* Разделы кабинета. Строки 40px — тот же размер, что у пунктов в списках
   выбора: это перечень переходов, а не текст. */
/* Список разделов кабинета. Такой же список стоит в боковом меню кабинета:
     это одно меню, показанное в двух местах. */
  .nav-popover__menu { list-style: none; display: grid; gap: var(--gap-tight); margin-bottom: var(--gap-block); }
.nav-popover__menu a {
      display: flex; align-items: center; min-height: 40px;
      padding: 0 var(--gap-inner); border-radius: 8px;
      color: var(--color-text);
      font-size: var(--text-ui); line-height: var(--lh-ui); font-weight: var(--fw-body);
      transition: background-color .15s ease;
    }
/* Класс носят и ссылка («Зарегистрироваться»), и кнопка («Выйти»). Кнопке
   нужно снять браузерные стили: иначе у нее серая заливка и рамка, и
   вместо ссылки в карточке видна кнопка-коробка. Найдено 17.09.2026
   при сверке с меню кабинета. */
.nav-popover__link { display:flex; align-items:center; justify-content:center; width:100%; margin-top:var(--gap-inner); min-height:24px; padding:var(--gap-tight) 0; border:0; background:transparent; cursor:pointer; text-decoration:none; font-family:inherit; font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-ui); color:var(--color-action); }
  .nav-popover__link:hover { color:var(--color-action-hover); }
  /* Мини-корзина шире обычной карточки: в 264px не помещается строка
       «картинка + название в две строки + цена + удаление». */
  .nav-popover--cart { width:calc(368px + 2 * var(--pad-box-lg)); padding:var(--pad-box-lg); }
  /* Список прокручивается после четырех позиций. Ограничение по высоте, а
       не по числу строк: названия бывают в одну и в две строки, и обрезка по
       количеству давала бы карточку то короче, то длиннее экрана. */
  .cart-mini__list {
      max-height:296px; overflow-y:auto; overscroll-behavior:contain;
      /* Список вытянут до краев карточки: отрицательный отступ РАВЕН набивке
         карточки, и берется тот же токен — иначе при смене набивки список
         перестает доходить до краев. Своя набивка возвращает строки к линии
         содержимого карточки. */
      margin:0 calc(-1 * var(--pad-box-lg)); padding:0 var(--pad-box-lg);
    }
  .cart-mini__item {
      display:grid; grid-template-columns:48px 1fr auto 24px;
      align-items:center; gap:var(--gap-block);
      padding:var(--gap-inner) 0; border-bottom:1px solid var(--color-border-lighter);
    }
  .cart-mini__item:last-child { border-bottom:0; }
  .cart-mini__thumb {
      width:48px; height:48px; border-radius:8px; object-fit:contain;
      background:var(--color-gray-light);
    }
  /* Название в две строки с обрезкой: в каталоге автозапчастей они длинные
       («Комплекты тормозных дисков с колодками»), и без ограничения одна
       позиция растянула бы карточку на пол-экрана. */
  .cart-mini__name {
      display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
      font-size:var(--text-caption); line-height:var(--lh-caption); font-weight:var(--fw-caption);
      color:var(--color-text);
    }
  .cart-mini__qty {
      margin-top:var(--gap-tight);
      font-size:var(--text-caption); line-height:var(--lh-caption); font-weight:var(--fw-caption);
      color:var(--color-text-secondary);
    }
  .cart-mini__price {
      font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-h2);
      font-feature-settings:"tnum"; white-space:nowrap;
    }
  .cart-mini__remove {
      display:flex; align-items:center; justify-content:center;
      width:24px; height:24px; padding:0; border:0; background:none;
      color:var(--color-text-secondary); cursor:pointer;
      transition:color .15s ease;
    }
  .cart-mini__remove:hover { color:var(--color-brand-strong); }
  .cart-mini__remove svg { width:16px; height:16px; display:block; }
  .cart-mini__footer {
      display:flex; align-items:center; justify-content:space-between; gap:var(--gap-block);
      margin-top:var(--gap-block); padding-top:var(--gap-block); border-top:1px solid var(--color-border-lighter);
    }
  .cart-mini__total-label {
      font-size:var(--text-caption); line-height:var(--lh-caption); font-weight:var(--fw-caption);
      color:var(--color-text-secondary);
    }
  /* Итог — это цена, и роль у него в шкале своя: Price. */
  .cart-mini__total {
      font-size:var(--text-price); line-height:var(--lh-price); font-weight:var(--fw-price);
      font-feature-settings:"tnum"; white-space:nowrap;
    }
  .cart-mini__footer .nav-popover__btn { margin-top:0; flex-shrink:0; }
  }
.nav-badge {
    /* ИСКЛЮЧЕНИЕ ИЗ ШКАЛЫ: кегль 10px ниже минимума Caption (12px).
       Причина геометрическая. Кружок сидит на иконке 24px, и при диаметре
       24px он накрывает ее почти целиком — проверено, выглядит поломанным.
       Рабочий диаметр 16px, а 12px цифра в него не помещается. Из двух
       нарушений — кегль вне шкалы или нечитаемая иконка корзины — выбрано
       первое. Других микрокеглей в файле нет и заводить их нельзя.
       Ширина тянется по содержимому: min-width держит круг на одной цифре,
       две и больше растягивают его в пилюлю, border-radius 8px = половина
       высоты, поэтому торцы остаются полукруглыми.
       Привязан ЦЕНТР, а не правый край. При right:-5px рос бы только левый
       край, то есть пилюля вытягивалась бы внутрь иконки: «345» накрывала бы
       21 пиксель из 24 и от корзины оставалась бы полоска в три пикселя.
       С привязкой центра рост идет в обе стороны поровну — та же «345»
       закрывает 13px, остальное уходит наружу, и иконка остается узнаваемой
       при любом числе. */
    position:absolute; top:-5px; left:100%; transform:translateX(-50%);
    min-width:16px; height:16px; border-radius:8px; padding:0 var(--gap-tight);
    background:var(--color-badge-bg); color:var(--color-badge-text);
    font-size:10px; line-height:1; font-weight:700;
    display:flex; align-items:center; justify-content:center;
  }
/* min-width:0 по всей цепочке до скролл-контейнера: у флекс-элементов
     min-width по умолчанию auto, то есть «не меньше содержимого», и один
     такой элемент в цепочке отменяет способность ленты сжиматься —
     ровно та же грабля, что уже ловили на <input> в форме поиска. */
.header-bottom-row { height:48px; display:flex; align-items:center; min-width:0; }
.quick-nav-wrap {
  --nav-clear: 40px; --nav-ramp: 0px;
  position:relative; display:flex; align-items:center; width:100%; min-width:0; height:48px;
}
.quick-nav { display:flex; align-items:center; gap:var(--gap-component); overflow-x:auto; scrollbar-width:none; scroll-behavior:smooth; width:100%; min-width:0; padding-right:var(--gap-section); scroll-snap-type:x mandatory; scroll-padding:0 32px; }
.quick-nav::-webkit-scrollbar { display:none; }
/* min-height:25px — размер цели по WCAG 2.2 (минимум 24). Прибавка ничего
     не двигает: строка 48px, ссылка в ней центрируется, и 14px пустоты сверху
     и снизу от текста были и раньше — теперь часть их ловит клик. */
.quick-nav a {
    display:flex; align-items:center; min-height:25px;
    color:var(--color-white); font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-ui); text-decoration:none; white-space:nowrap;
    opacity:1; transition: opacity .2s ease-in-out;
    scroll-snap-align:start;
  }
.quick-nav__arrow {
    position:absolute; top:0; height:48px;
    display:flex; align-items:center;
    width:28px; padding:0; background:transparent; border:0;
    cursor:pointer; color:var(--color-white); z-index:2;
  }
.quick-nav__arrow--prev { left:0; justify-content:flex-start; }
.quick-nav__arrow--next { right:0; justify-content:flex-end; }
/* Ни маска-прямоугольник, ни кружок больше не рисуют градиент. Раньше оба
     закрашивали себя ТЕМ ЖЕ градиентом, что и шапка, и совпадали с ней
     попиксельно лишь потому, что у всех троих отсчет шел от окна (fixed).
     Стоило отвязать фон шапки — и под стрелкой появился бы прямоугольник
     другого оттенка. Теперь край ленты гасит mask-image (см. ниже): ссылки
     уходят в прозрачность, и сквозь них виден настоящий фон шапки. Совпадение
     получается по построению, а не по совпадению систем координат.
     Кружок оставлен как обертка шеврона и зона наведения, но прозрачный. */
.quick-nav__arrow-disc {
    position:relative; width:24px; height:24px; border-radius:50%;
    display:flex; align-items:center; justify-content:center;
    transition: background-color .15s ease;
  }
.quick-nav__arrow svg { width:16px; height:16px; display:block; }
/* Шеврон в спрайте один и смотрит вправо — «назад» получается разворотом
     на 180°. Раньше в файле лежали две почти одинаковые копии контура,
     отличавшиеся зеркальностью. Сдвиг на полпикселя оставлен: он ставит
     острие шеврона в оптический центр кружка (у контура толщина 3px, и
     геометрический центр смещен относительно видимого). */
.quick-nav__arrow--prev svg { transform: rotate(180deg) translateX(0.5px); }
.quick-nav__arrow--next svg { transform: translateX(-0.5px); }
.quick-nav__arrow.is-hidden { visibility:hidden; pointer-events:none; }
/* Затухание края ленты. Работает на ВСЕХ ширинах: выше 1024px вместе со
     стрелками (шеврон лежит поверх уже погашенных ссылок и потому читается),
     ниже — вместо них. Классы is-fade-left/right вешает JS там же, где считает
     видимость стрелок. Гасим только тот край, в сторону которого есть куда
     скроллить, иначе первый пункт выглядел бы полупрозрачным в самом начале
     ленты. #000 здесь — не цвет, а непрозрачная часть маски. */

/* ── Подсказки поиска ─────────────────────────────────────────────────────
   Панель выпадает из поля и накрывает страницу затемнением. Затемнение здесь
   не украшение: оно отсекает все, кроме поиска, и человек не ищет глазами,
   куда смотреть. */
.screen-dim {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(0, 0, 0, .5);
}
.screen-dim[hidden] { display: none; }

/* Поле поиска поднимается НАД затемнением вместе с подсказками: шапка целиком
   поднимать нельзя — тогда над затемнением окажутся и каталог, и корзина.
   position: relative у формы задан в ее базовом правиле выше. */
.site-header-real:has(.suggest:not([hidden])) .search-form { z-index: 41; }

.suggest {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 41;
  max-height: min(70vh, 560px);
  margin-top: var(--gap-inner);
  padding: var(--pad-box-lg);
  border-radius: 8px;
  background: var(--color-white);
  box-shadow: var(--shadow-popover);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.suggest[hidden] { display: none; }

.suggest__body { display: block; }
.suggest__title {
  margin-bottom: var(--gap-inner);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  font-weight: var(--fw-h2);
  color: var(--color-text-secondary);
}
.suggest__group + .suggest__group { margin-top: var(--gap-block); }

/* Популярные запросы — капсулы, как быстрые теги в листинге: короткие слова,
   которые нажимают, а не читают подряд. */
.suggest__tags { display: flex; flex-wrap: wrap; gap: var(--gap-inner); }
.suggest__tag {
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  padding: 0 var(--gap-block);
  border: 0;
  border-radius: 8px;
  cursor: pointer;
  background: var(--color-gray-light);
  color: var(--color-text);
  white-space: nowrap;
  font-family: inherit;
  font-size: var(--text-ui);
  line-height: var(--lh-ui);
  font-weight: var(--fw-body);
  transition: background-color .15s ease;
}

/* Строка подсказки: раздел или товар. Одна разметка на оба, разное только
   содержимое — иначе два похожих списка разъедутся по высоте и отступам. */
.suggest__item {
  display: flex;
  align-items: center;
  gap: var(--gap-block);
  min-height: 48px;
  padding: var(--gap-tight) var(--gap-inner);
  border-radius: 8px;
  color: var(--color-text);
  transition: background-color .15s ease;
}
.suggest__pic {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  border-radius: 4px;
  object-fit: contain;
  background: var(--color-gray-light);
}
.suggest__icon { width: 20px; height: 20px; flex-shrink: 0; color: var(--color-text-muted); }
.suggest__text { min-width: 0; }
.suggest__name {
  display: block;
  font-size: var(--text-body);
  line-height: var(--lh-body);
  font-weight: var(--fw-body);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.suggest__note {
  display: block;
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  font-weight: var(--fw-caption);
  color: var(--color-text-secondary);
}
.suggest__price {
  margin-left: auto;
  padding-left: var(--gap-block);
  white-space: nowrap;
  font-size: var(--text-ui);
  line-height: var(--lh-ui);
  font-weight: var(--fw-h2);
}
/* Совпавшая часть запроса выделяется весом, а не цветом: цвет тут спорил бы
   со ссылками, а вес читается и в черно-белом. */
.suggest__hit { font-weight: var(--fw-h2); }
.suggest__empty {
  padding: var(--gap-block) var(--gap-inner);
  font-size: var(--text-body);
  line-height: var(--lh-body);
  color: var(--color-text-secondary);
}

@media (max-width: 640px) {
  /* На телефоне подсказки во весь экран под шапкой: список длинный, а места
     под ним нет. */
  /* Набивка на телефоне прежняя, 16px: увеличение набивки 17.09.2026
     касается десктопа, мобильная версия — отдельная задача. */
  .suggest { position: fixed; top: var(--header-height, 96px); left: 0; right: 0;
             max-height: calc(100vh - var(--header-height, 96px)); margin-top: 0;
             border-radius: 0; padding: var(--pad-box); }
}

/* ── Окно отзыва: вход, проверка, форма ───────────────────────────────────
   Устроено как остальные окна проекта: нативный <dialog>, та же подложка, та
   же шапка с крестиком, прокручивается тело. */
.review-dialog::backdrop { background: rgba(0, 0, 0, .5); }
.review-dialog {
  /* Ширина ЗАВИСИТ ОТ ШАГА. Широкая она нужна только форме отзыва: там три
     поля в ряд и длинные текстовые поля. Вход, отказ и «отправлено» — одна
     колонка, и на 560px кнопки растягивались через весь экран без всякой
     пользы: чем длиннее кнопка, тем дальше от нее курсор после чтения
     надписи. */
  width: min(calc(332px + 2 * var(--pad-box-xl)), calc(100vw - var(--gap-section)));
  max-height: min(760px, calc(100vh - var(--gap-section)));
  margin: auto;
  /* Набивка окна — --pad-box-xl (32px, решение 17.09.2026). Ширина считается
     от прежней рабочей области плюс две набивки: содержимое внутри окна не
     перестраивается, растет только поле по краю. */
  padding: var(--pad-box-xl);
  border: 0;
  border-radius: 8px;
  background: var(--color-white);
  color: var(--color-text);
  overflow: hidden;
}
/* Широкими идут оба шага с формами: у отзыва три поля в ряд, у вопроса —
   большое поле текста, и в узком окне оно превращается в щель. Вход, отказ и
   «отправлено» остаются узкими: там одна колонка. */
.review-dialog[data-current="form"],
.review-dialog[data-current="question"] { width: min(calc(512px + 2 * var(--pad-box-xl)), calc(100vw - var(--gap-section))); }
.review-dialog[open] { display: flex; flex-direction: column; gap: var(--gap-block); }
/* Крестик выровнен по ВЕРХУ, а не по центру: заголовок переносится на две
   строки, и при выравнивании по центру крестик уезжал вниз относительно
   первой строки.
   Отрицательные поля компенсируют пустоту внутри кнопки: у нее бокс 36px
   вокруг знака в 20, то есть по 8px с каждой стороны. Без сдвига знак стоял
   заметно дальше от края окна, чем текст, — набивка выглядела разной. */
.review-dialog__head {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: var(--gap-block); flex-shrink: 0;
  }
.review-dialog__title {
    font-size: var(--text-h2); line-height: var(--lh-h2); font-weight: var(--fw-h2);
  }
.review-dialog__close {
    display: flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; flex-shrink: 0;
    /* Отрицательные поля компенсируют пустоту внутри кнопки: бокс 36px вокруг
       знака в 20, то есть по 8px с каждой стороны. Без сдвига знак стоял
       заметно дальше от края окна, чем текст. */
    margin: calc(var(--gap-inner) * -1) calc(var(--gap-inner) * -1) 0 0;
    padding: 0; border: 0; border-radius: 8px; cursor: pointer;
    background: none; color: var(--color-text-muted);
    transition: color .15s ease;
  }
.review-dialog__close svg { width: 20px; height: 20px; display: block; }
.review-dialog__body {
    flex: 1 1 auto; min-height: 0; overflow-y: auto;
  }
.review-dialog__body:focus, .review-dialog__body:focus-visible { outline: none; box-shadow: none; }

.review-step { display: grid; gap: var(--gap-block); }
.review-step__text {
    font-size: var(--text-body); line-height: var(--lh-body); font-weight: var(--fw-body);
  }
.review-step__note {
    font-size: var(--text-caption); line-height: var(--lh-caption);
    font-weight: var(--fw-caption); color: var(--color-text-secondary);
  }
.review-dialog__body a { color: var(--color-action); transition: color .15s ease; }

/* Подпись и поле — строки одного куска, роль 8px. Стояло 4px: это расстояние
   между парными элементами, и подпись прилипала к рамке. */
.review-field { display: grid; gap: var(--gap-inner); border: 0; padding: 0; }
.review-field__label {
    font-size: var(--text-caption); line-height: var(--lh-caption);
    font-weight: var(--fw-h2); color: var(--color-text-secondary);
  }
/* Поля на белом несут контур: без него поле не отличить от фона — тот случай,
   когда 3:1 обязателен. */
.review-field__input {
    width: 100%; min-height: 48px; padding: 0 var(--gap-block);
    border: 1px solid var(--color-separator); border-radius: 8px;
    background: var(--color-white); color: var(--color-text);
    font-family: inherit;
    font-size: var(--text-body); line-height: var(--lh-body); font-weight: var(--fw-body);
    /* Отклик у поля — потемнение контура: заливки у него нет, менять больше
       нечего. */
    transition: border-color .15s ease;
  }
/* Поле тянется по вертикали, но не дальше 320px: без потолка его можно было
   растянуть на несколько экранов, кнопка отправки уезжала из виду, и окно
   превращалось в пустой белый столб.
   320px — примерно двенадцать строк; вопрос или абзац отзыва длиннее этого
   человек все равно правит не в поле, а в голове. Дальше поле прокручивается
   внутри себя. */
/* Поле НЕ тянется: размер задан заранее и его хватает. Растягивание давало
   человеку способ сломать окно — поле уезжало на несколько экранов, кнопка
   пропадала из виду, — а взамен не давало ничего: текст длиннее видимой части
   прокручивается внутри поля. */
.review-field__input--area {
    padding: var(--gap-inner) var(--gap-block);
    resize: none;
  }
/* Счетчик внутри поля, у правого нижнего угла. Поле получает снизу место под
   него, иначе последняя строка текста подлезает под цифры.
   pointer-events: none — чтобы нажатие по счетчику ставило курсор в поле, а не
   промахивалось мимо. */
/* Обертка ОБНИМАЕТ поле: у textarea снизу остается зазор под базовую линию,
   обертка была на 4px выше, и счетчик, отмеренный от ее низа, ложился прямо
   на рамку поля — линия под цифрами пропадала. display: flex убирает зазор. */
.review-field__box { position: relative; display: flex; }
.review-field__box .review-field__input--area { flex: 1 1 auto; padding-bottom: var(--gap-section); }
.review-field__counter {
    /* Отступ в 2px оставляет рамку поля видимой: подложка начинается за ней. */
    position: absolute; right: 2px; bottom: 2px;
    /* Подложка белая и до самого края рамки: текст в поле прокручивается, и
       без нее строки проезжали ПОД цифрами — читалось как каша.
       Набивка по бокам отделяет цифры от букв слева. */
    padding: 2px var(--gap-block) var(--gap-inner) var(--gap-inner);
    border-radius: 0 0 8px 0;
    background: var(--color-white);
    pointer-events: none;
    font-size: var(--text-caption); line-height: var(--lh-caption);
    font-weight: var(--fw-caption); color: var(--color-text-muted);
  }
/* На подходе к пределу счетчик темнеет: человек должен заметить границу до
   того, как поле перестанет принимать буквы. */
.review-field__counter[data-near="true"] { color: var(--color-brand-strong); }
/* Незаполненное поле помечается рамкой и надписью — но только ПОСЛЕ ухода из
   поля: ругаться на недописанное, пока человек печатает, нельзя.
   Надпись набрана ролью Caption красным: #C41A1A дает 6.4:1 на белом. */
.review-field__error {
    font-size: var(--text-caption); line-height: var(--lh-caption);
    font-weight: var(--fw-caption); color: var(--color-brand-strong);
  }
.review-field__input[aria-invalid="true"] { border-color: var(--color-brand-strong); }
/* Выключенная кнопка: видно, что она есть, но нажать нечего. Цель и размер не
   меняются — иначе форма прыгала бы при вводе. */
.review-dialog__submit[disabled] {
    background: var(--color-border); color: var(--color-text-muted); cursor: default;
  }
.review-field__input::placeholder { color: var(--color-text-muted); }
.review-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gap-block); }

/* Оценка звездами. Кнопки, а не радиокнопки со стилями: так проще держать
   подсветку «до наведенной» и не спорить с браузером.
   Ряд по центру и крупнее прочего — это главное, что просят у человека, и
   первое, на что он смотрит, открыв форму.
   Незажженная звезда светло-серая, тем же цветом, что пустые звезды в сводке
   рейтинга: у них одна роль «оценки нет». */
/* Ряд ОБНИМАЕТ звезды и центрируется целиком, а не растягивается на всю
   ширину окна. Пока он был шириной 512px при звездах в 252, по бокам
   оставалось по 130px пустоты — и подсветка держалась, пока курсор не уйдет
   за эту пустоту. Выглядело так, будто эффект отпускает с запозданием. */
.review-rate {
    display: flex; gap: var(--gap-inner);
    width: max-content; margin-inline: auto;
  }
.review-rate__star {
    width: 44px; height: 44px; padding: 0; border: 0; cursor: pointer;
    background: none; color: var(--color-placeholder);
    transition: color .12s ease;
  }
.review-rate__star svg { width: 44px; height: 44px; display: block; }
/* Выбранная оценка и все звезды до нее. Класс ставит скрипт: чистым CSS
   «все предыдущие» не выбрать, а обратный порядок в разметке сломал бы
   чтение с клавиатуры. */
.review-rate__star[aria-pressed="true"] { color: var(--color-rating); }
/* Наведение сразу показывает будущую оценку ЖЕЛТЫМ — тем же цветом, каким
   она и будет поставлена. Человек видит результат до нажатия, а не намек на
   него.
   Пока курсор на ряду, желтым горят только звезды до наведенной: прежний
   выбор гасится, иначе на пятерке поверх четверки видно две разные оценки
   сразу. */
.review-rate--hover .review-rate__star { color: var(--color-placeholder); }
.review-rate--hover .review-rate__star.is-hot { color: var(--color-rating); }

.review-choice { display: grid; gap: var(--gap-inner); }
/* Строка выбора — цель целиком, а не только кружок: 20px кружка мало, а
   min-height 24px доводит строку до минимума по размеру цели. */
.review-choice__item, .review-agree {
    display: flex; align-items: center; gap: var(--gap-inner);
    min-height: 24px;
    font-size: var(--text-body); line-height: var(--lh-body); font-weight: var(--fw-body);
    cursor: pointer;
    transition: color .15s ease;
  }
.review-choice__item input, .review-agree input { width: 20px; height: 20px; flex-shrink: 0; accent-color: var(--color-cta); }

/* Карточка товара в шапке формы. Нужна потому, что та же форма открывается
   из личного кабинета, где рядом нет ни снимка, ни названия: человек должен
   видеть, о каком товаре пишет. */
/* Линии между кусками формы нет: куски и так разделены промежутком, а лишняя
   черта дробит короткую форму на отсеки. */
.review-product { display: flex; align-items: center; gap: var(--gap-block); }
.review-product__pic {
    width: 72px; height: 72px; flex-shrink: 0;
    border-radius: 8px; object-fit: contain;
    background: var(--color-gray-light);
  }
.review-product__name {
    font-size: var(--text-ui); line-height: var(--lh-ui); font-weight: var(--fw-h2);
  }

/* Снимки к отзыву: сетка пять на два — ровно десять мест, столько же, сколько
   разрешено приложить. Плашка выбора занимает следующую свободную клетку и
   равна снимку по размеру: широкая полоса под нее съедала треть окна ради
   одного действия.
   Промежутки ролью 8px — это плитки одного ряда, а не разные куски формы. */
.review-photos {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: var(--gap-inner);
    list-style: none;
  }
.review-photos__item { position: relative; aspect-ratio: 1; }
.review-photos__item--add { display: block; }
.review-photos__pic {
    display: block; width: 100%; height: 100%;
    border-radius: 8px; object-fit: cover;
    background: var(--color-gray-light);
  }
/* Пометка на ролике: кадр из видео выглядит как обычный снимок, и без подписи
   человек не отличит одно от другого. */
.review-photos__kind {
    position: absolute; left: var(--gap-tight); bottom: var(--gap-tight);
    padding: 0 var(--gap-tight);
    border-radius: 4px;
    background: rgba(0, 0, 0, .55); color: var(--color-white);
    font-size: var(--text-caption); line-height: var(--lh-caption); font-weight: var(--fw-caption);
  }
/* Плашка выбора. Пунктир — исключение из запрета на подчеркивание: это не
   текст, а граница области, куда тащат файлы. */
.review-drop {
    display: flex; align-items: center; justify-content: center;
    width: 100%; height: 100%;
    border: 1px dashed var(--color-separator); border-radius: 8px;
    background: var(--color-gray-light);
    cursor: pointer; color: var(--color-text-secondary);
    transition: border-color .15s ease, background-color .15s ease;
  }
.review-drop__icon { display: flex; }
/* Знак крупнее обычных 24: клетка 96px, и знак в четверть ее высоты в ней
   теряется. Это единственный знак в пустой плитке, соседей по строке у него
   нет — сравнивать не с чем. */
.review-drop svg { width: 32px; height: 32px; }
/* Крестик на плитке: убрать снимок можно сразу, не открывая выбор заново. */
.review-photos__drop {
    position: absolute; top: var(--gap-tight); right: var(--gap-tight);
    display: flex; align-items: center; justify-content: center;
    width: 24px; height: 24px;
    padding: 0; border: 0; border-radius: 50%; cursor: pointer;
    background: rgba(0, 0, 0, .55); color: var(--color-white);
    transition: background-color .15s ease;
  }
.review-photos__drop svg { width: 14px; height: 14px; display: block; }

/* Красная, как основные кнопки магазина: вход и отправка отзыва — такие же
   главные действия своего окна, как «Добавить в корзину» на странице. Окно
   перекрывает страницу, и спорить кнопке не с кем.
   Белым по --color-cta 4.69:1 — выше нормы 4.5. */
.review-dialog__submit {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 48px; padding: 0 var(--gap-section);
    border: 0; border-radius: 8px; cursor: pointer;
    background: var(--color-cta); color: var(--color-white);
    font-family: inherit;
    font-size: var(--text-ui); line-height: var(--lh-ui); font-weight: var(--fw-h2);
    transition: background-color .15s ease;
  }
/* Второстепенное действие — контуром: красная заливка принадлежит покупке и
   отправке отзыва, и второй красной кнопки в окне быть не должно. */
.review-dialog__submit--ghost {
    background: none; color: var(--color-text);
    border: 1px solid var(--color-separator);
  }

/* Разделитель «или через сервис»: линия по обе стороны от надписи. Рисуется
   границей соседних ячеек сетки, а не псевдоэлементами с фоном — так она
   тянется ровно до текста при любой его длине. */
.auth-or {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--gap-block);
  font-size: var(--text-caption);
  line-height: var(--lh-caption);
  font-weight: var(--fw-caption);
  color: var(--color-text-secondary);
}
.auth-or::before, .auth-or::after {
  content: '';
  height: 1px;
  background: var(--color-divider);
}

/* Между кнопками сервисов 16px, а не 8. По роли 8 — «строки одного куска», и
   формально это один кусок. Но каждая кнопка здесь сплошная заливка высотой
   48px, и восемь пикселей между тремя цветными блоками читаются волоском:
   кнопки слипались в одну полосу.
   16px дает форме единый шаг: все расстояния в ней теперь 16, кроме подписи и
   поля — те 8, потому что это действительно одна строка. */
.auth-services { display: grid; gap: var(--gap-block); }
.auth-service {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--gap-inner);
  min-height: 48px;
  padding: 0 var(--gap-block);
  border: 0;
  border-radius: 8px;
  cursor: pointer;
  color: var(--color-white);
  font-family: inherit;
  font-size: var(--text-ui);
  line-height: var(--lh-ui);
  font-weight: var(--fw-h2);
  transition: opacity .15s ease;
}
.auth-service svg { width: 24px; height: 24px; flex-shrink: 0; display: block; }
/* Белым на синем VK 4.13:1 — ниже 4.5 для обычного текста. Надпись набрана
   весом H2 при кегле 14, а это «крупный текст», для которого норма 3:1.
   Цвет фирменный и перекраске не подлежит: кнопку узнают по нему. */
.auth-service--vkid { background: var(--color-vkid); }
.auth-service--yandex { background: var(--color-yandex); }
.auth-service--sber { background: var(--color-sber); }

@media (max-width: 640px) {
  .review-dialog {
    width: 100vw; max-width: none; height: 100vh; max-height: none;
    border-radius: 0; padding: var(--pad-box);
  }
  .review-grid { grid-template-columns: 1fr; }
}

/* ── Окно условий возврата ────────────────────────────────────────────────
   Устроено как выбор города: тот же нативный <dialog>, та же подложка, тот же
   крестик. Отличие одно — внутри длинный текст, поэтому прокручивается тело
   окна, а шапка с заголовком остается на месте. */
.return-dialog::backdrop { background: rgba(0, 0, 0, .5); }
.return-dialog {
  width: min(calc(592px + 2 * var(--pad-box-xl)), calc(100vw - var(--gap-section)));
  max-height: min(720px, calc(100vh - var(--gap-section)));
  margin: auto;
  /* Набивка окна — --pad-box-xl (32px, решение 17.09.2026). Ширина считается
     от прежней рабочей области плюс две набивки: содержимое внутри окна не
     перестраивается, растет только поле по краю. */
  padding: var(--pad-box-xl);
  border: 0;
  border-radius: 8px;
  background: var(--color-white);
  color: var(--color-text);
  overflow: hidden;
}
.return-dialog[open] { display: flex; flex-direction: column; gap: var(--gap-block); }
.return-dialog__head {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--gap-block); flex-shrink: 0;
  }
.return-dialog__title {
    font-size: var(--text-h2); line-height: var(--lh-h2); font-weight: var(--fw-h2);
  }
.return-dialog__close {
    display: flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; flex-shrink: 0;
    padding: 0; border: 0; border-radius: 8px; cursor: pointer;
    background: var(--color-gray-light); color: var(--color-text);
    transition: background-color .15s ease;
  }
.return-dialog__close svg { width: 20px; height: 20px; }

/* Текст окна набран ролью Body — это читаемый текст, а не подписи.
   Мера строки не ограничивается отдельно: ее держит ширина самого окна. */
.return-dialog__body {
    flex: 1 1 auto; min-height: 0; overflow-y: auto;
    font-size: var(--text-body); line-height: var(--lh-body); font-weight: var(--fw-body);
  }
/* Тело ПРИНИМАЕТ фокус, но указателя фокуса не получает. tabindex="-1"
   означает, что ни мышью, ни табом сюда не попасть: фокус ставится скриптом
   один раз при открытии, чтобы он не достался крестику и вокруг того не
   вспыхнуло кольцо. Обводить рамкой весь текст окна незачем. */
.return-dialog__body:focus,
.return-dialog__body:focus-visible { outline: none; box-shadow: none; }
.return-dialog__body > * + * { margin-top: var(--gap-block); }
.return-dialog__body a { color: var(--color-action); }
/* Подзаголовок внутри окна — кегль Interface с весом H2, как подзаголовки
   групп характеристик и заголовок плашки доставки. */
.return-dialog__subtitle {
    margin-top: var(--gap-component);
    font-size: var(--text-ui); line-height: var(--lh-ui); font-weight: var(--fw-h2);
  }
/* Шаги нумерованные: порядок здесь значащий, его нельзя терять. */
.return-dialog__steps { padding-left: var(--gap-section); }
.return-dialog__steps > li + li { margin-top: var(--gap-inner); }
.return-dialog__steps ul {
    margin-top: var(--gap-tight); padding-left: var(--gap-section); list-style: disc;
  }
.return-dialog__steps ul li + li { margin-top: var(--gap-tight); }
/* Способы возврата — список ссылок без маркеров: маркер рядом со ссылкой
   читается как часть текста. */
.return-dialog__ways { list-style: none; }
.return-dialog__ways li + li { margin-top: var(--gap-inner); }

@media (max-width: 640px) {
  /* На телефоне окно во весь экран: текст длинный, и окно в окне отнимает у
     него высоту ради рамки. */
  .return-dialog {
    width: 100vw; max-width: none; height: 100vh; max-height: none;
    border-radius: 0; padding: var(--pad-box);
  }
}

/* ── Окно выбора города ───────────────────────────────────────────────────
   Нативный <dialog>, как окно аналогов: сам запирает фокус, закрывается по
   Esc и возвращает фокус на кнопку, которая его открыла. */
.city-dialog::backdrop { background: rgba(0, 0, 0, .5); }
.city-dialog {
  width: min(calc(372px + 2 * var(--pad-box-xl)), calc(100vw - var(--gap-section)));
  max-height: min(560px, calc(100vh - var(--gap-section)));
  margin: auto;
  /* Набивка окна — --pad-box-xl (32px, решение 17.09.2026). Ширина считается
     от прежней рабочей области плюс две набивки: содержимое внутри окна не
     перестраивается, растет только поле по краю. */
  padding: var(--pad-box-xl);
  border: 0;
  border-radius: 8px;
  background: var(--color-white);
  color: var(--color-text);
  overflow: hidden;
}
.city-dialog[open] { display: flex; flex-direction: column; gap: var(--gap-block); }
.city-dialog__head { display: flex; align-items: center; justify-content: space-between; gap: var(--gap-block); }
.city-dialog__title {
    font-size: var(--text-h2); line-height: var(--lh-h2); font-weight: var(--fw-h2);
  }
.city-dialog__close {
    display: flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; flex-shrink: 0;
    padding: 0; border: 0; border-radius: 8px; cursor: pointer;
    background: var(--color-gray-light); color: var(--color-text);
    transition: background-color .15s ease;
  }
.city-dialog__close svg { width: 20px; height: 20px; }
/* Поле поиска несет контур само: здесь оно на белом, и без границы его не
   отличить от фона — тот случай, когда 3:1 обязателен. */
.city-dialog__search {
    width: 100%; min-height: 48px; padding: 0 var(--gap-block);
    border: 1px solid var(--color-separator); border-radius: 8px;
    background: var(--color-white); color: var(--color-text);
    font-family: inherit;
    font-size: var(--text-ui); line-height: var(--lh-ui); font-weight: var(--fw-body);
  }
.city-dialog__search::placeholder { color: var(--color-text-muted); }
/* Список прокручивается, а окно — нет: заголовок и поиск остаются на месте. */
.city-dialog__list {
    list-style: none; flex: 1 1 auto; min-height: 0; overflow-y: auto;
  }
.city-dialog__item {
    display: flex; align-items: center; width: 100%; min-height: 44px;
    padding: 0 var(--gap-block); border: 0; border-radius: 8px; cursor: pointer;
    background: none; color: var(--color-text); text-align: left;
    font-family: inherit;
    font-size: var(--text-ui); line-height: var(--lh-ui); font-weight: var(--fw-body);
    transition: background-color .15s ease;
  }
.city-dialog__item[aria-current="true"] { font-weight: var(--fw-h2); }
.city-dialog__empty {
    padding: var(--gap-block); color: var(--color-text-secondary);
    font-size: var(--text-ui); line-height: var(--lh-ui);
  }

@media (max-width: 640px) {
  /* На телефоне окно во весь экран: список городов длинный, и окно в окне
     отнимает у него высоту ради рамки. */
  /* Набивка на телефоне прежняя, 24px: мобильная версия — отдельная задача. */
  .city-dialog { width: 100vw; max-width: none; height: 100vh; max-height: none; border-radius: 0; padding: var(--pad-box-lg); }
}

/* Поведение края задается двумя числами, а сами градиенты ниже их только
     подставляют — чтобы менять край в одном месте, а не в трех правилах:
       --nav-clear — ширина ЧИСТОЙ зоны у края, где ссылок нет совсем;
       --nav-ramp  — длина перехода перед ней; 0 значит резкий срез.
     На десктопе чистая зона 40px: стрелка занимает у края 28px, остальные
     12px — воздух между обрезанным текстом и шевроном, иначе срез впритык
     к стрелке читается как баг верстки, а не как решение. */
.quick-nav-wrap.is-fade-right:not(.is-fade-left) .quick-nav {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - var(--nav-clear) - var(--nav-ramp)), transparent calc(100% - var(--nav-clear)));
    mask-image: linear-gradient(to right, #000 calc(100% - var(--nav-clear) - var(--nav-ramp)), transparent calc(100% - var(--nav-clear)));
  }
.quick-nav-wrap.is-fade-left:not(.is-fade-right) .quick-nav {
    -webkit-mask-image: linear-gradient(to right, transparent var(--nav-clear), #000 calc(var(--nav-clear) + var(--nav-ramp)));
    mask-image: linear-gradient(to right, transparent var(--nav-clear), #000 calc(var(--nav-clear) + var(--nav-ramp)));
  }
.quick-nav-wrap.is-fade-left.is-fade-right .quick-nav {
    -webkit-mask-image: linear-gradient(to right, transparent var(--nav-clear), #000 calc(var(--nav-clear) + var(--nav-ramp)), #000 calc(100% - var(--nav-clear) - var(--nav-ramp)), transparent calc(100% - var(--nav-clear)));
    mask-image: linear-gradient(to right, transparent var(--nav-clear), #000 calc(var(--nav-clear) + var(--nav-ramp)), #000 calc(100% - var(--nav-clear) - var(--nav-ramp)), transparent calc(100% - var(--nav-clear)));
  }
.btn-catalog {
    position:relative;
    display:inline-flex;
    align-items:center;
    height:48px;
    padding:var(--gap-inner) var(--gap-block);
    gap:var(--gap-inner);
    background:var(--color-white);
    border:0;
    border-radius:8px;
    font-size:var(--text-ui);
    line-height:var(--lh-ui);
    font-weight:var(--fw-ui);
    color:var(--color-text);
    cursor:pointer;
    outline-offset:2px;
    font-family:inherit;
    flex-shrink:0;
    width:136px;
    justify-content:flex-start;
    white-space:nowrap;
    transition: opacity .2s ease;
  }
.btn-catalog:focus-visible { outline: none; }
.btn-catalog__burger { position:absolute; left:16px; top:50%; transform:translateY(-50%); width:24px; height:24px; flex-shrink:0; }
.btn-catalog__burger span {
    position:absolute; left:0; width:100%; height:3px; border-radius:2px; background:var(--color-text);
    transition: transform .2s cubic-bezier(.4,0,.2,1), width .2s cubic-bezier(.4,0,.2,1) .2s, top .2s cubic-bezier(.4,0,.2,1) .2s, left .15s ease .2s, opacity .15s ease .15s, background-color .2s ease;
  }
.btn-catalog__burger span:nth-child(1) { top:4px; width:81%; }
.btn-catalog__burger span:nth-child(2) { top:11px; width:100%; }
.btn-catalog__burger span:nth-child(3) { top:18px; width:62%; }
.btn-catalog.active .btn-catalog__burger span {
    transition: width .2s cubic-bezier(.4,0,.2,1), top .2s cubic-bezier(.4,0,.2,1), left .15s ease, opacity .15s ease .05s, transform .2s cubic-bezier(.4,0,.2,1) .2s, background-color .2s ease;
  }
.btn-catalog.active .btn-catalog__burger span:nth-child(1) { top:11px; width:100%; transform:rotate(45deg); }
.btn-catalog.active .btn-catalog__burger span:nth-child(2) { opacity:0; width:0; left:50%; }
.btn-catalog.active .btn-catalog__burger span:nth-child(3) { top:11px; width:100%; transform:rotate(-45deg); }
.btn-catalog__label { white-space:nowrap; margin-left:var(--gap-section); }
.catalog-panel {
    position:fixed; left:0; top:0; width:100%;
    background:var(--color-white);
    opacity:0; visibility:hidden;
    transition: opacity .2s ease, visibility 0s linear .2s;
    z-index:50;
  }
.catalog-panel.active {
    opacity:1; visibility:visible;
    transition: opacity .2s ease;
  }
.catalog-panel .container {
    display:flex; flex-wrap:wrap; align-items:flex-start; align-content:flex-start; gap:var(--gap-component);
    height:70vh; margin:0 auto; overflow-y:auto; overflow-x:hidden;
    padding:0 var(--container-pad); max-width:1440px;
    scrollbar-width:none;
  }
.catalog-panel .container::-webkit-scrollbar { display:none; width:0; height:0; }
.catalog-scrollbar {
    position:fixed; width:8px; background:var(--color-gray-light); border-radius:4px;
    z-index:51; display:none;
  }
.catalog-scrollbar__thumb {
    position:absolute; left:0; width:8px; background:var(--color-scrollbar-track); border-radius:4px;
    cursor:grab;
  }
.catalog-scrollbar__thumb:active { cursor:grabbing; }
.catalog-menu__list {
    flex:0 1 320px; max-width:360px; padding:var(--gap-block) 0; position:sticky; top:0; align-self:flex-start;
    max-height:100%; overflow-y:auto; scrollbar-width:none;
  }
.catalog-menu__list::-webkit-scrollbar { display:none; width:0; height:0; }
.catalog-menu__back { display:none; }
.catalog-menu__item {
    display:flex; align-items:center; gap:var(--gap-inner); padding:var(--gap-inner) var(--gap-block); border-radius:8px; min-height:48px;
    cursor:pointer; color:var(--color-text); font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-h2);
    transition: background-color .15s ease, color .15s ease;
  }
.catalog-menu__item svg { flex-shrink:0; width:24px; height:24px; display:block; color:var(--color-icon); transition: color .15s ease; }
.catalog-menu__item.is-active { background:var(--color-gray-light); color:var(--color-brand); }
.catalog-menu__item.is-active svg { color:var(--color-brand); }
.catalog-menu__panels { flex:5 1 480px; min-width:0; }
/* Верхний отступ = собственный отступ панели (16px, из сетки) + оптическая
     компенсация (48 − 22) / 2 = 13px.
     Второе слагаемое — не решение об отступе, а следствие геометрии: пункт
     левого списка это бокс высотой 48px (тач-цель) с вертикально центрированным
     текстом, поэтому его строка начинается на 13px ниже верха бокса. У заголовка
     колонки та же типографика (16px/22px), но своей высоты 48px больше нет, и без
     компенсации первая строка панели встает на 13px выше первого пункта списка.
     Раньше это выравнивание держал min-height:48px у заголовка — он же портил
     ритм внутри колонки, поэтому обязанности разделены: ритм задает margin
     заголовка, выравнивание — этот padding. Записано формулой, а не числом 29,
     чтобы при смене высоты пункта или line-height пересчиталось само.
     На ≤768 обнуляется (см. мобильный блок): там панель разворачивается на всю
     ширину, левого списка рядом нет и выравнивать не с чем. */
.catalog-menu__panel { display:none; padding-top:calc(16px + (48px - 24px) / 2);   /* 28px: 16 из сетки + компенсация под бокс заголовка в 24px */ }
.catalog-menu__panel.is-active { display:block; }
/* Колонки раскладывает браузер, а не JS. Раньше группы распределялись по
     четырем <div class="catalog-menu__col"> заранее, по ОЦЕНКЕ высоты каждой
     группы (заголовок + число пунктов × константа). Оценка неизбежно врала:
     длинные названия переносятся на две строки, заголовки тоже, и реальная
     высота расходилась с расчетной. Отсюда и брались пустые белые зоны —
     одна колонка обрывалась заметно выше остальных, а высоту меню задавала
     самая длинная.
     Многоколоночная раскладка считает по НАСТОЯЩИМ высотам после переноса
     строк и выравнивает колонки сама (column-fill:balance по умолчанию).
     Порядок групп при этом сохраняется: заполняется сверху вниз, слева
     направо. Побочный выигрыш — из JS уходит вся арифметика с константами,
     которую приходилось пересчитывать после каждой правки типографики.
     Запись `columns: 220px 4` = не больше четырех колонок и не уже 220px
     каждая, поэтому на промежуточных ширинах число колонок падает само. */
.catalog-menu__groups {
    columns: 220px 4; column-gap: var(--gap-section); padding-right:var(--space-md);
  }
/* Группу нельзя разрывать между колонками: заголовок обязан остаться со
     своими пунктами. Без этого браузер перенес бы хвост списка в следующую
     колонку без названия. */
.catalog-menu__group {
    /* Невидимая набивка, которую добавил min-height:25px ради размера цели
       по WCAG. У пункта строка 17px в боксе 25px — по 4px сверху и снизу от
       текста; у заголовка строка 22px в боксе 25px — по 1,5px. Между самими
       пунктами эта набивка и работает отступом (4+4 = ровно те 8px, что были
       раньше). А вот на стыке «заголовок ↔ пункт» она СКЛАДЫВАЕТСЯ с заданным
       отступом: 1,5 + 16 + 4 давало 21,5px вместо 16, и просвет под
       заголовком выглядел вдвое с лишним больше межстрочного вместо ровно
       вдвое. Ниже она вычитается обратно — на обоих таких стыках он один и
       тот же, поэтому выражение общее. */
    /* Шкала 8 / 16 / 24 — по сетке проекта, каждый уровень вложенности
       отделен вдвое сильнее предыдущего.
       Работать ей позволяет межстрочный интервал в 20px (см. ниже). Раньше
       он был 17px — ровно высота знакоместа Inter, то есть просвета между
       строками не было вовсе, и перенесенное название лепилось само к себе
       с зазором в 6px. При таком наборе отделить пункты друг от друга можно
       было только раздвигая их все сильнее: на 8px перенос читался как два
       пункта, и приходилось уходить на 16px, а шаг строки раздувался до
       33px. Свободная строка снимает проблему в корне — перенос выглядит
       обычным текстом, и отступ возвращается на 8px.
       Набивка задана прямо, а не выведена из 25px: высота цели теперь 28px
       (20 + 4 + 4), с запасом над минимумом WCAG в 24, и это число отвечает
       за ритм, а не за попадание пальцем. */
    --pad-link: 4px;                       /* над и под текстом ссылки → отступ 8px */
    /* Набивка заголовка добирает его бокс до 24px — минимума WCAG для цели.
       На десктопе интервал Body уже 24px, добирать нечего и набивка равна
       нулю; на мобильных он 20px, и добавляется по 2px. max() нужен, чтобы
       на десктопе не получилось отрицательное значение. Бокс заголовка
       поэтому всегда ровно 24px, независимо от ширины окна. */
    --pad-head: max(0px, calc((24px - var(--lh-ui)) / 2));

    margin-bottom:calc(24px - var(--pad-link) - var(--pad-head));
    -webkit-column-break-inside:avoid; break-inside:avoid;
  }
.catalog-menu__group:last-child { margin-bottom:0; }
/* Без min-height. Раньше здесь стояло min-height:48px — правило тач-цели:
     на ≤768 заголовок группы становится тапабельной строкой аккордеона, и там
     48px обязательны. Но объявлено оно было в базовом правиле и работало на
     десктопе, где заголовок — просто текст. Строка текста высотой 22px внутри
     бокса в 48px давала (48−22)/2 = 13px пустоты сверху и снизу: снизу они
     складывались с margin-bottom:var(--gap-block) в отступ 29px до первого пункта, сверху —
     с margin-bottom:var(--gap-component) соседней группы в 37px между группами. Оба значения
     мимо шкалы 4-8-16-24, причем как побочный эффект чужого правила.
     Мобильный блок (@media max-width:768px) объявляет свои 48px отдельно,
     поэтому тач-цель аккордеона не затронута. Ритм колонки стал 8 / 16 / 24 —
     три соседние ступени сетки. */
.catalog-menu__group h4 { display:flex; align-items:center; font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-h2); color:var(--color-text); margin-bottom:calc(16px - var(--pad-head) - var(--pad-link)); }
/* Высоту заголовка задает сама ссылка — иначе целью осталась бы строка
     текста в 22px, а не бокс в 25px. Набивка здесь тоже явная, по той же
     причине, что и у пунктов: у двухстрочного заголовка вроде «Система
     очистки стекол и фар» центрировать нечего, и компенсация --pad-head
     ниже перестала бы соответствовать действительности. */
.catalog-menu__group h4 a {
    display:flex; align-items:center; align-self:stretch;
    padding:var(--pad-head) 0; color:inherit; text-decoration:none;
  }
/* Группа без пунктов — заголовок, за которым сразу идет следующий заголовок.
     Таких в каталоге 117 из 161. Отступ под заголовком здесь не нужен вовсе:
     отделять он должен заголовок от СВОЕГО списка, а списка нет. Иначе он
     складывается с межгрупповым, и между двумя названиями получается 32px —
     больше, чем между полноценными группами.
     Вычитание тоже другое: сверху и снизу от промежутка теперь не ссылка и
     заголовок, а два заголовка, значит и набивка вычитается их. */
.catalog-menu__group.is-empty h4 { margin-bottom:0; }
.catalog-menu__group.is-empty { margin-bottom:calc(24px - var(--pad-head) - var(--pad-head)); }
.catalog-menu__group ul { list-style:none; }
.catalog-menu__group li { margin-bottom:0; }
.catalog-menu__group li:last-child { margin-bottom:0; }
/* То же решение, что в подвале: цель 25px, а margin-bottom у li обнулен —
     8px воздуха переехали внутрь ссылки. Расстояние между названиями и общая
     высота группы не изменились, поэтому оценка высоты колонок в JS
     (25px на пункт) остается верной и пересчета не требует. */
/* padding, а не только min-height с центрированием. Набивка в 4px сверху и
     снизу — это и есть межпунктовый отступ (4+4 = 8px), но при центрировании
     она существовала лишь пока пункт помещался в одну строку: у перенесенного
     содержимое перерастало 25px, центрировать становилось нечего, и набивка
     обнулялась. Просветы получались разные — 8px между обычными пунктами и 4px
     рядом с перенесенным. Явный padding не зависит от числа строк.
     min-height оставлен как гарантия размера цели по WCAG на случай, если
     поменяется кегль. */
.catalog-menu__group ul a {
    display:flex; align-items:center; min-height:25px; padding:var(--pad-link) 0;
    font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-ui); color:var(--color-text-secondary); text-decoration:none;
    transition: color .2s ease;
  }
.catalog-menu__group li.is-extra { display:none; }
.catalog-menu__group ul.is-expanded li.is-extra { display:list-item; }
.catalog-menu__more button { display:flex; align-items:center; min-height:25px;
    font: inherit; font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-ui); color:var(--color-action);
    background:none; border:0; padding:0; margin:0; cursor:pointer;
    transition: color .15s ease;
  }
.mobile-bottom-nav { display:none; }

  @media (max-width: 1024px){
  .catalog-panel .container { padding: 32px var(--container-pad); }
  .header-geo { gap: var(--gap-inner); }
  .header-left { gap: var(--gap-block); margin-right: var(--gap-block); flex-shrink: 0; }
  .btn-catalog { width: 44px; height: 44px; padding: 0; gap: 0; justify-content: center; flex-shrink: 0; }
  .btn-catalog__label { display: none; }
  .btn-catalog__burger { left: 10px; }
  .search-form { flex: 1 1 auto; min-width: 0; margin-right: var(--gap-block); }
  .account-menu {
      display: flex; flex-shrink: 0; width: auto; gap: var(--gap-block);
      margin-left: 0;
    }
  .account-menu .label { display: none; }
  .account-menu .link { width: auto; min-width: 0; }
  /* Стрелки убираем: на тач-экране ленту листают свайпом, а не целятся
       в кружок 24px. Вместе со стрелкой исчезает и смысл чистой зоны — она
       существовала как место под шеврон. Резать текст насухо там, где ничего
       не стоит, нельзя: получится обрыв без объяснения, похожий на сломанную
       верстку. Поэтому на тач-ширинах край не срезается, а плавно гаснет —
       это привычный признак того, что ленту можно листать дальше. Правила
       маски те же, меняются только два числа. */
  .quick-nav__arrow { display: none; }
  .quick-nav-wrap { --nav-clear: 0px; --nav-ramp: 32px; }
  }
/* ------------------------------------------------------------------
     ПОРЯДОК MEDIA QUERY В ЭТОЙ СЕКЦИИ: строго по УБЫВАНИЮ ширины
     (1024 → 768 → 640 → 420). Для max-width это не стиль, а
     обязательное условие: при одинаковой специфичности выигрывает то
     правило, что ниже по файлу. Блок 768 раньше стоял ВЫШЕ блока 1024
     и на ширине 700px проигрывал ему — из-за чего в файле и завелись
     `padding: ... !important`, которых теперь нет. Новые блоки
     добавлять только в этом порядке.
     ------------------------------------------------------------------ */

  @media (max-width: 768px){
  .site-header-real { padding-bottom: var(--gap-inner); }
  .catalog-menu__panel { padding-top: 0; }
  .catalog-menu__list {
      position: static; max-width: none; width: 100%; flex-basis: 100%;
      max-height: none; overflow-y: visible; padding-top: var(--gap-inner);
    }
  .catalog-panel .container {
      padding-top: var(--gap-inner); -webkit-overflow-scrolling: touch;
    }
  .catalog-scrollbar { display: none !important; }
  .catalog-menu__panels { display: none; width: 100%; }
  .catalog-panel .container.is-drilled .catalog-menu__list { display: none; }
  .catalog-panel .container.is-drilled .catalog-menu__panels { display: block; flex-basis: 100%; }
  .catalog-panel .container.is-drilled .catalog-menu__back { display: flex; }
  /* Одна колонка. Правил для .catalog-menu__col здесь больше нет: оберток
       колонок не существует, а прятать «лишние» при раскрытии группы не надо —
       остальные группы и так скрыты правилом .is-group-open ниже. */
  .catalog-menu__groups { column-count: 1; }
  .catalog-menu__group, .catalog-menu__group.is-empty { margin-bottom: 0; }
  .catalog-menu__group h4 {
      display: flex; align-items: center; justify-content: space-between; gap: var(--gap-inner);
      min-height: 48px; padding: 0; margin-bottom: 0; border-bottom: 1px solid var(--color-divider-strong);
      cursor: pointer; line-height:var(--lh-ui);
    }
  .catalog-menu__group h4::after {
      content: ''; width: 8px; height: 8px; flex-shrink: 0;
      border-right: 2px solid var(--color-brand); border-bottom: 2px solid var(--color-brand);
      transform: rotate(-45deg);
    }
  .catalog-menu__group.is-empty h4::after { display: none; }
  .catalog-menu__group.is-empty h4 { cursor: default; }
  .catalog-menu__group ul { display: none; padding-top: var(--gap-inner); }
  .catalog-menu__panel.is-group-open .catalog-menu__group { display: none; }
  .catalog-menu__panel.is-group-open .catalog-menu__group.is-open { display: block; }
  .catalog-menu__panel.is-group-open .catalog-menu__group.is-open h4 { border-bottom: 0; cursor: default; }
  .catalog-menu__panel.is-group-open .catalog-menu__group.is-open h4::after { display: none; }
  .catalog-menu__panel.is-group-open .catalog-menu__group.is-open ul { display: block; }
  .catalog-menu__group.is-open li { margin-bottom: 0; border-bottom: 1px solid var(--color-divider); }
  .catalog-menu__group.is-open li:last-child { border-bottom: 0; }
  .catalog-menu__group.is-open li.catalog-menu__more { border-bottom: 0; }
  .catalog-menu__group.is-open a {
      display: flex; align-items: center; min-height: 48px;
      font-size:var(--text-ui); line-height:var(--lh-ui); color:var(--color-text);
    }
  .catalog-menu__item { padding-left: var(--gap-component); padding-right: var(--gap-component); }
  .catalog-menu__more { display: none; }
  .catalog-menu__group.is-open li.is-extra { display: block; }
  .catalog-menu__back {
      align-items: center; gap: var(--gap-inner); width: 100%; padding: var(--gap-inner) 0; margin-bottom: var(--gap-inner); min-height: 44px;
      background: none; border: 0; border-bottom: 1px solid var(--color-divider-strong); color: var(--color-brand);
      font: inherit; font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-h2); cursor: pointer;
    }
  .catalog-menu__back svg { width: 20px; height: 20px; }
  }

  @media (max-width: 640px){
  * { -webkit-tap-highlight-color: transparent; }
  /* Строго дочерний селектор (>), а не потомок. .catalog-panel лежит
       ВНУТРИ <header class="site-header-real">, и ее собственный
       .container тоже подходил под `.site-header-real .container` —
       то есть панель каталога молча получала мобильную раскладку шапки
       (display:flex поверх своей, align-items:center вместо flex-start,
       row-gap:var(--gap-tight) вместо gap:var(--gap-component), чужой padding). Лечилось это парой
       `padding: ... !important` на .catalog-panel .container — их тут
       больше нет, они были симптомом именно этого промаха. */
  .site-header-real > .container { display: flex; flex-wrap: wrap; align-items: center; padding: 8px var(--container-pad); row-gap: var(--gap-tight); }
  .header-top { display: contents; }
  .header-main-row { display: contents; }
  .header-left { display: contents; }
  .logo svg { height: 18px; }
  .header-geo__pickup, .header-geo__sep { display: none; }
  /* Резерв min-width:230px нужен только на десктопе: он держит место
       под название города, чтобы точка-разделитель и «N пунктов выдачи»
       не прыгали, когда город/шрифт доедут. Здесь и разделитель, и
       пункты выдачи скрыты — прыгать нечему, а резерв остается: на
       ≤420px, где само название города тоже скрыто, гео-кнопка
       превращалась в пустой блок 230px с иконкой у левого края,
       прижатый к правому краю экрана. */
  .header-geo__city { min-width: 0; }
  .logo { order: 1; margin-right: 0; }
  .header-geo { order: 2; margin-left: auto; }
  /* Мобильная шапка ЗАМОРОЖЕНА решением заказчика от 17.09.2026: в нее
       ничего не добавляется, мобильная версия сайта — отдельная задача.
       Ссылка «Для бизнеса» живет в шапке только от 641px. На телефоне та же
       ссылка доступна из подвала, раздел «Покупателям». */
  .header-b2b { display: none; }
  /* Тот же промах, что и выше, но злее: этот псевдоэлемент —
       принудительный перенос строки во флексе. В контейнере панели
       каталога он добавлял ЛИШНИЙ элемент на всю ширину и разрывал ее
       раскладку на ровном месте. */
  .site-header-real > .container::after { content: ''; order: 3; flex-basis: 100%; height: 0; }
  .btn-catalog { order: 4; width: 44px; height: 44px; }
  .btn-catalog__burger { left: 10px; }
  .search-form .input-wrap { height: 44px; }
  .account-menu { display: none; }
  .header-bottom-row { display: none; }
  /* Основа 0, а не auto. С auto поле сначала просит место под свою
       естественную ширину (около 256px), и на экранах уже 360px вместе с
       кнопкой каталога и отступом не помещалось в строку: флекс переносил
       поиск под кнопку. С основой 0 поле забирает ровно остаток строки при
       любой ширине. Дефект был в исходной сборке, найден 17.09.2026 по
       скриншоту заказчика на 320px. */
  .search-form {
      order: 5; flex: 1 1 0%; width: auto; margin-right: 0; margin-left: var(--gap-block);
    }
  .site-header-real { padding-bottom: var(--gap-tight); }
  /* Резерв под фиксированную панель = ее собственная высота + один шаг
       сетки на воздух. Оба слагаемых — из переменных, чтобы резерв не
       разъезжался с реальной высотой панели при следующей правке
       (было 80px против панели в 60px). */
  body { padding-bottom: calc(var(--mobile-nav-height) + var(--space-md) + env(safe-area-inset-bottom, 0px)); }
  /* height здесь ОБЯЗАТЕЛЬНО через calc с env(): глобально включен
       box-sizing:border-box, поэтому padding-bottom под safe-area
       вычитался ИЗ 60px, а не добавлялся к ним. На iPhone с «челкой»
       (safe-area 34px) под контент оставалось 26px при иконке с
       подписью в 40px — иконки наезжали на подпись и на границу
       панели. Теперь 60px всегда достаются контенту, а safe-area
       прибавляется сверху. */
  .mobile-bottom-nav {
      display: flex; justify-content: space-around; align-items: center;
      position: fixed; left: 0; right: 0; bottom: 0;
      height: calc(var(--mobile-nav-height) + env(safe-area-inset-bottom, 0px));
      padding: 0 8px env(safe-area-inset-bottom, 0px);
      background: var(--color-white); border-top: 1px solid var(--color-border-lighter); z-index: 60;
    }
  .mobile-bottom-nav .link {
      display: flex; flex-direction: column; align-items: center; justify-content: center;
      gap: var(--gap-tight); height: 100%; flex: 1;
      color: var(--color-text); text-decoration: none;
    }
  .mobile-bottom-nav .icon { position: relative; width: 24px; height: 24px; }
  .mobile-bottom-nav .icon svg { width: 24px; height: 24px; display: block; }
  .mobile-bottom-nav .label { white-space:nowrap; font-size:var(--text-caption); line-height:var(--lh-caption); font-weight:var(--fw-caption); }
  .mobile-bottom-nav .nav-badge {
      position: absolute; top: -5px; left: 100%; transform: translateX(-50%);
    min-width:16px; height:16px; border-radius:8px; padding:0 var(--gap-tight);
    background:var(--color-badge-bg); color:var(--color-badge-text);
    font-size:10px; line-height:1; font-weight:700;
      display: flex; align-items: center; justify-content: center;
    }
  }

  /* Скрытие названия города на узких экранах — правило шапки, а не
     подвала. Блок стоял в конце подвальной секции и сбивал порядок
     max-width по файлу (проверка 7). Перенесен к остальным
     брейкпоинтам шапки; селекторы двух секций не пересекаются,
     видимое поведение не меняется. */
  @media (max-width: 420px){
  .header-geo__city span { display: none; }
  }
/* Скруглены только верхние углы — нижние упираются в край окна, и
     скругление там открыло бы белые уголки под подвалом. Зеркально
     шапке, у которой по той же причине скруглены только нижние. */
.site-footer { background:var(--color-dark); color:var(--color-white); min-height:336px; border-radius:var(--radius-block) var(--radius-block) 0 0; }
.footer-top {
    display:grid; grid-template-columns:2fr 1fr 1fr 1fr; gap:var(--gap-section); padding-top:var(--gap-section); padding-bottom:var(--gap-section);
  }
/* min-height убран по той же причине: 208px подбирались под прежние кегли,
     содержимое стало короче примерно на 20-35px, и разница висела пустотой
     под соцсетями — на ≤1024, где блок растянут на всю ширину, она видна
     как лишний зазор перед колонками ссылок. */
.footer-brand { max-width:440px; }
.footer-logo { display:inline-flex; }
.footer-logo svg { height:25px; width:auto; display:block; }
/* Utility-класс на будущее: применять к ценам, артикулам, таблицам
     характеристик, столбцам с числами в корзине — все цифры получают
     одинаковую ширину (как в Excel), не "скачут" при сравнении. */
.tabular-nums, .font-numeric-tables { font-feature-settings:"tnum"; }
/* Уважение к системной настройке «уменьшить движение». Кто включил ее в
     ОС — при вестибулярных нарушениях, мигрени или просто по предпочтению —
     получает интерфейс без анимации: переходы схлопываются почти в ноль,
     плавная прокрутка ленты быстрых ссылок и панели каталога становится
     мгновенной.
     !important здесь оправдан и является общепринятой практикой для этого
     блока: правило должно перебить в том числе inline-стили и любые более
     специфичные объявления, иначе часть анимаций переживет отключение.
     Длительность 0.01ms, а не 0 — на нуле некоторые браузеры не выстреливают
     событие transitionend, и код, который его ждет, зависает. */

  @media (prefers-reduced-motion: reduce){
  *, *::before, *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
      scroll-behavior: auto !important;
    }
  }
/* Кольцо фокуса на ВСЕХ интерактивных элементах.
     Раньше свое правило было только у кнопки «Каталог», все остальное
     получало то, что нарисует браузер, — а вид у него разный: голубое
     свечение в Safari, синяя рамка в старых Chromium, черно-белое кольцо
     в новых, свой вариант в Firefox. Предсказать, как это ляжет на красную
     шапку, нельзя.
     Три слоя дают кольцо, читаемое на любом фоне: box-shadow рисует темный
     ореол от края элемента до 6px, поверх него outline кладет белую полосу
     с 2 по 4px. Получается темный–белый–темный. Порядок именно такой,
     потому что outline рисуется поверх тени.
     :focus-visible, а не :focus — браузер сам отличает переход клавиатурой
     от клика мышью, и по клику кольцо не появится. */
:focus-visible {
    outline: 2px solid var(--focus-ring-inner);
    outline-offset: 2px;
    box-shadow: 0 0 0 6px var(--focus-ring-outer);
  }
/* Текстовым полям — свой вид фокуса, без общего кольца.

   Причина не в оформлении, а в поведении браузера: :focus-visible срабатывает
   у полей ввода ВСЕГДА, в том числе по клику мышью, — человек собирается
   печатать, и указатель ему нужен. У кнопок и ссылок такого нет, там кольцо
   появляется только при переходе с клавиатуры.

   Поэтому у полей вместо двойного кольца — потемневшая рамка в два пикселя.
   Толщина НЕ добирается: обводка остается 1px по всему периметру, меняется
   только цвет. Прежде поверх рамки клалась тень в 1px, и вместе они давали
   два пикселя — но тень ложится по внешнему контуру со скруглением, и на
   прямых участках сверху и снизу выглядела заметно жирнее, чем по бокам.
   Указателя хватает и цветом: #949494 против #1A1A1A — 5.74:1, разница видна
   и с клавиатуры, и мышью.

   Указатель остается видимым: рамка меняется с #949494 (3.03:1) на #1A1A1A
   (17.4:1), это заметно и с клавиатуры, и мышью. */
input:focus-visible,
textarea:focus-visible {
    outline: none;
    /* Общее кольцо фокуса гасится ЯВНО. Я убрал отсюда тень в 1px и решил,
       что поле останется с одной рамкой, — но тогда до него снова дотянулось
       общее правило с ореолом в 6px, и обводка стала еще толще прежнего. */
    box-shadow: none;
    border-color: var(--color-dark-action);
  }

/* Поле поиска в шапке — исключение по устройству, а не по вкусу. Рамку там
   несет ОБЕРТКА .input-wrap: внутри нее, кроме самого поля, лежит кнопка с
   лупой, и граница обязана охватывать обоих. У самого input границы нет
   вовсе (border: 0), поэтому общее правило выше красило несуществующую рамку,
   а из всего указателя оставалась тень в 1px. Она обводила input — элемент
   без скругления, вписанный внутрь скругленной обертки, — и получался темный
   прямоугольник внутри светлого овала. Ровно то, что было видно.
   Переносим указатель на обертку: :focus-within срабатывает, когда фокус
   внутри нее, то есть в поле. Вид тот же, что у любого другого поля, —
   рамка темнеет с #949494 до #1A1A1A, толщина добирается тенью, чтобы поле
   не выросло и строка не дернулась. */
.search-form input:focus-visible { box-shadow: none; }

/* Указатель фокуса у поля поиска — БЕЗ рамки. Рамка не трогается ни в одном
   состоянии: в покое, при наведении и при фокусе она остается --color-separator.

   Вместо нее темнеют знак лупы и подсказка: #929292 (--color-text-muted) →
   #6B7280 (--color-text-secondary). Плавность у подсказки была объявлена в
   стилях давно и до сих пор ничего не делала — цвет ей никто не менял.
   Теперь меняет.

   Чего этот прием НЕ закрывает, и это надо знать. Подсказка исчезает, как
   только человек начинает печатать, и половина указателя пропадает вместе с
   ней. Остается лупа. WCAG 2.4.7 таким образом выполнен наполовину: указатель
   есть, но слабее принятого, и в пустом поле он заметнее, чем в заполненном.
   Решение принято сознательно, при известной цене. */
.search-form .input-wrap:focus-within { box-shadow: none; }
.search-form .input-wrap:focus-within .search-btn { color:var(--color-text-secondary); }
.search-form .input-wrap:focus-within input::placeholder { color:var(--color-text-secondary); }

/* Скругление кольца НЕ задается: outline и так повторяет форму элемента.
   Раньше здесь стояло border-radius: 4px, и оно переопределяло собственное
   скругление элемента — поле ввода со скруглением 8px в фокусе становилось
   4px, рамка и кольцо расходились по форме и выглядели двойным
   прямоугольником.
   Элементам без своего скругления кольцо рисуется прямым — это верно, оно
   повторяет их форму. */
/* Видимая только для скринридеров подпись. Нужна там, где по дизайну
     подписи нет, а поле без имени оставлять нельзя (placeholder именем
     поля не считается). clip-path вместо display:none — скрытое через
     display содержимое скринридеры тоже не читают. */
.visually-hidden {
    position:absolute; width:1px; height:1px; margin:-1px; padding:0;
    overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0;
  }
/* type="search" в вебките рисует свой крестик очистки поверх нашей
     кнопки-лупы — убираем, вид поля не должен зависеть от типа. */
.search-form input::-webkit-search-decoration,
  .search-form input::-webkit-search-cancel-button,
  .search-form input::-webkit-search-results-button { -webkit-appearance:none; appearance:none; }
/* min-height, а НЕ height: на десктопе текст укладывается ровно в 64px
     и резерв держит высоту блока стабильной (не дергается при загрузке
     шрифта), но на узких экранах юридический адрес разворачивается в 5
     строк — с фиксированной height половина реквизитов физически
     обрезалась через overflow:hidden. overflow тоже убран: при min-height
     он ничего не удерживает, только маскирует такие обрезки. */
/* БЕЗ резерва высоты. Здесь стояло min-height, сперва 64px, потом расчет
     на три строки — и оба варианта неверны в принципе: число строк зависит
     от ширины окна. Этот же текст занимает две строки при 800px, три при
     1440px и четыре-пять на телефоне, а резерв — одно число, и на всех
     ширинах, кроме одной, он оставляет пустоту. Замер на 800px: 60px
     просвета до почты вместо 8.
     Резерв тут и не нужен: при font-display:block текст на время загрузки
     шрифта невидим, но строчные боксы место уже занимают (метрики берутся
     из запасного шрифта), так что скачка, от которого резерв защищал,
     практически нет. */
.footer-desc { font-size:var(--text-caption); line-height:var(--lh-caption); font-weight:var(--fw-caption); color:var(--color-text-muted); margin-top:var(--space-md); font-feature-settings:"tnum"; }
/* Почта и реквизиты — элементы одного блока, поэтому между ними один шаг
     сетки (8px), а не 16px как между блоками. Объявленное значение меньше на
     собственную набивку почты: та добавляет 4px сверху, и без вычитания
     оптический просвет вышел бы 12px вместо 8. */
.footer-email {
    --pad-y: 4px;
    display:inline-flex; align-items:center; font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-ui); min-height:25px; padding:var(--pad-y) 0; color:var(--color-text-muted);
    text-decoration:none; margin-top:calc(var(--space-sm) - var(--pad-y));
  }
.footer-social { display:flex; gap:var(--space-sm); margin-top:var(--space-lg); }
.footer-social__link {
    display:flex; align-items:center; justify-content:center; width:40px; height:40px;
    border-radius:50%; background:var(--color-dark-secondary); color:var(--color-white);
    text-decoration:none; transition: background-color .2s ease;
  }
.footer-social__link svg { display:block; }
/* h2, а не h4: иерархия заголовков шла h1 → h4 с пропуском двух уровней.
     Размер задан стилями, поэтому визуально ничего не меняется. */
.footer-col h2 { font-size:var(--text-ui); line-height:var(--lh-ui); min-height:20px; font-weight:var(--fw-h2); color:var(--color-white); margin-bottom:var(--gap-block); margin-top:var(--gap-inner); }
/* gap:0, а не var(--gap-inner). Ссылка выросла с 17px до 25px ради размера цели, и
     разница ровно var(--gap-inner) — те самые, что раньше были воздухом между строками.
     Теперь этот воздух внутри цели, а не между целями: расстояние между
     текстами осталось прежним, но мертвых промежутков между ссылками нет. */
/* На десктопе summary не должен выглядеть и вести себя как кнопка:
     служебный треугольник убран, курсор обычный. Раскрытием управляет JS
     через атрибут open, а клик по summary там же перехватывается — иначе
     пользователь мог бы свернуть колонку на десктопе, где сворачивание не
     предусмотрено. */
.footer-acc > summary { list-style:none; display:block; cursor:default; }
.footer-acc__chevron { display:none; }
.footer-acc > summary::-webkit-details-marker { display:none; }
.footer-col ul { list-style:none; display:flex; flex-direction:column; gap:0; }
.footer-col a { display:flex; align-items:center; font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-ui); min-height:25px; padding:var(--gap-tight) 0; color:var(--color-text-muted); text-decoration:none; transition:color .2s ease; }
.footer-contacts { display:flex; flex-direction:column; gap:var(--gap-inner); }
.footer-contacts a {
    font-size:var(--text-ui); line-height:var(--lh-ui); font-weight:var(--fw-ui); color:var(--color-text-muted); text-decoration:none;
  }
.footer-bottom__inner {
    display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between;
    gap:var(--gap-block); padding-top:var(--gap-component); padding-bottom:var(--gap-component); position:relative;
  }
.footer-bottom__inner::before {
    content:''; position:absolute; top:0; left:var(--container-pad); right:var(--container-pad); height:1px;
    background-color:var(--color-dark-secondary);
  }
/* --color-text-muted, а НЕ --color-text-secondary. Вторичный цвет описан
     в системе для артикулов и OEM на СВЕТЛОМ фоне; на темном подвале он дает
     3.45:1 при норме 4.5. Весь остальной подвал использует muted (5.35:1),
     копирайт по недосмотру остался на secondary. */
.footer-copy { font-size:var(--text-caption); line-height:var(--lh-caption); font-weight:var(--fw-caption); min-height:16px; color:var(--color-text-muted); }
.footer-legal-links { display:flex; gap:var(--gap-component); }
.footer-legal-links a { display:inline-flex; align-items:center; font-size:var(--text-caption); line-height:var(--lh-caption); font-weight:var(--fw-caption); min-height:25px; padding:var(--gap-tight) 0; color:var(--color-text-muted); text-decoration:none; transition:color .2s ease; }

  @media (hover: hover) and (pointer: fine){
  .footer-col a:hover { color:var(--color-white); }
  .footer-email:hover { color:var(--color-white); }
  .footer-social__link:hover { background:var(--color-dark-hover); }
  .footer-legal-links a:hover { color:var(--color-white); }
  }

  @media (max-width: 1024px){
  .footer-top { padding-top:var(--gap-section); padding-bottom:var(--gap-component); gap:var(--gap-component); grid-template-columns:repeat(3, 1fr); }
  .footer-brand { grid-column:1 / -1; max-width:none; }
  }

  @media (max-width: 640px){
  .footer-top { grid-template-columns:1fr; gap:0; }
  .footer-brand { margin-bottom:var(--space-xl); }
  .footer-col { border-top:1px solid var(--color-dark-hover); }
  /* Набивка summary решает две задачи разом. По вертикали она доводит
       строку заголовка (20px) до тач-цели в 44px. И она же задает просвет до
       первой ссылки: нижняя набивка плюс собственные 4px ссылки дают 16px
       оптически — тот же отступ «заголовок → пункты», что и в мегаменю.
       Отсюда и записана формулой, а не числом 12. */
  .footer-acc > summary {
      display:flex; align-items:center; justify-content:space-between; gap:var(--gap-inner);
      padding:calc(16px - 4px) 0; cursor:pointer;
    }
  .footer-col h2 { margin-top:0; margin-bottom:0; }
  /* Шеврон устроен как стрелки ленты в шапке: иконка 16x16 по центру
       области 24x24. Область нужна не для вида, а как поле вокруг острие —
       без нее шеврон прижимался бы к краю и к тексту заголовка.
       Иконка из спрайта смотрит вправо: 90° — свернуто, -90° — раскрыто. */
  .footer-acc__chevron {
      display:flex; align-items:center; justify-content:center;
      width:24px; height:24px; flex-shrink:0; color:var(--color-white);
      transform:rotate(90deg); transition:transform .2s ease;
    }
  .footer-acc__chevron svg { width:16px; height:16px; display:block; }
  .footer-acc[open] .footer-acc__chevron { transform:rotate(-90deg); }
  .footer-acc[open] > ul,
    .footer-acc[open] > a { margin-bottom:var(--space-sm); }
  .footer-bottom__inner {
      flex-direction:column; align-items:flex-start;
    }
  /* Правовые ссылки — в столбик. В строку они не помещались и переносились
       каждая на две строки: получалось шесть строк текста, в которых три
       ссылки не отделялись друг от друга и не читались как отдельные пункты.
       gap обнулен намеренно: у ссылок есть собственная набивка по 4px ради
       размера цели, и она уже дает между ними 8px оптически — тот же шаг,
       что у ссылок в колонках подвала. Со своим gap просвет удвоился бы.
       align-self растягивает цель на всю ширину: попадать пальцем в короткую
       строку вроде «Условия продажи» иначе неудобно. */
  .footer-legal-links { flex-direction:column; gap:0; align-self:stretch; }
  .footer-legal-links a { align-self:stretch; }
  }
/* Hover-эффекты — только для устройств с реальной мышью/трекпадом.
     На тач-экранах :hover не нужен и часто «залипает» после тапа —
     media (hover:hover) not (pointer:coarse) исключает мобильные
     устройства из вычисления этих правил вообще. */

  @media (hover: hover) and (pointer: fine){
  .breadcrumbs a:hover { color:var(--color-brand); }
  .btn-catalog:hover { opacity:.97; }
  .header-geo__city:hover { opacity:.9; }
  .header-geo__pickup:hover { opacity:.9; }
  .header-b2b:hover { opacity:.9; }
  .search-form .search-btn:hover { opacity:.7; }
  .city-dialog__close:hover { background: var(--color-border); }
  .return-dialog__close:hover { background: var(--color-border); }
  .review-dialog__close:hover { color: var(--color-text); }
  .review-rate__star:hover { color: var(--color-rating); }
  .review-drop:hover { border-color: var(--color-text-on-plate); background: var(--color-border); }
  .review-photos__drop:hover { background: rgba(0, 0, 0, .75); }
  .auth-service:hover:not([disabled]) { opacity: .85; }
  /* Кнопка отправки не отвечала на мышь вовсе: плавность была объявлена, а
     менять оказалось нечему. */
  /* Выключенная кнопка на наведение НЕ отвечает: нажать ее нельзя, а отклик
     обещает обратное — человек ведет к ней мышь и упирается в пустоту. */
  .review-dialog__submit:hover:not([disabled]) { background: var(--color-cta-hover); }
  .review-dialog__submit--ghost:hover:not([disabled]) { background: none; border-color: var(--color-text); }
  .review-field__input:hover { border-color: var(--color-text-on-plate); }
  .review-choice__item:hover, .review-agree:hover { color: var(--color-text-on-plate); }
  .review-dialog__body a:hover { color: var(--color-action-hover); }
  .return-dialog__body a:hover { color: var(--color-action-hover); }
  .city-dialog__item:hover { background: var(--color-gray-light); }
    .nav-popover__menu a:hover { background: var(--color-gray-light); }
  .suggest__tag:hover { background: var(--color-border); }
  .suggest__item:hover { background: var(--color-gray-light); }
  .account-menu .link:hover .icon svg,
    .account-menu .link:hover .label { opacity:.9; }
  .quick-nav a:hover { opacity:.9; }
  /* Круг появляется ТОЛЬКО при наведении: в покое кружок прозрачный, как и
     задумано, а обратная связь остается явной. Прошлый вариант (opacity:0.7
     на прозрачном кружке) приглушал один шеврон и был почти незаметен —
     затемнять там больше нечего, фон у кружка теперь отсутствует. */
  .quick-nav__arrow:hover .quick-nav__arrow-disc { background:var(--color-overlay-hover); }
  .catalog-menu__group h4 a:hover { color:var(--color-brand-hover); }
  .catalog-menu__group ul a:hover { color:var(--color-brand); }
  .catalog-menu__more button:hover { color:var(--color-action-hover); }
  .catalog-menu__item:hover { background:var(--color-gray-light); color:var(--color-brand); }
  .catalog-menu__item:hover svg { color:var(--color-brand); }
  }
/* ============================================================
     ЗАГОТОВКА ПОД SELF-HOSTED ШРИФТ (на будущее, для боевого домена)
     ============================================================
     Сейчас шрифт грузится с fonts.googleapis.com — это чужой домен,
     а значит лишний DNS+TCP+TLS хендшейк, который мы не контролируем.
     У крупных сайтов шрифты почти всегда лежат на своем же сервере —
     тогда шрифт грузится тем же соединением, что и сама страница,
     без лишней сетевой задержки. Именно в этой задержке и была
     причина дерганий, которые мы чинили.

     ВАЖНАЯ ОГОВОРКА ИМЕННО ПРО INTER: сами авторы шрифта прямо пишут
     в официальной документации (rsms.me/inter) — «не используйте Inter
     через Google Fonts, если есть другой выбор» (там устаревшая версия,
     без курсива). То есть текущее подключение ниже — временный мост,
     а не финальное решение. Self-hosting тут не просто «оптимизация
     скорости», а способ получить актуальную версию шрифта вообще.

     Когда будете разворачивать сайт на реальном домене:
     1. Скачайте актуальные файлы Inter с официального источника
        rsms.me/inter (не с Google Fonts) — либо статические начертания
        400/500/600/700 в .woff2, либо ОДИН variable-файл на весь
        диапазон начертаний сразу (Inter — variable font, это может
        заменить 4 отдельных файла одним, меньше запросов к серверу).
     2. Положите файл(ы) в /fonts/ на своем сервере.
     3. В <head> ДО этого style добавьте preload под каждый файл:
          link rel="preload" as="font" type="font/woff2" crossorigin
          href="/fonts/inter-400.woff2" (и так же для остальных весов,
          либо один preload на variable-файл)
     4. В САМОЕ НАЧАЛО этого style добавьте @font-face — по одному на
        каждое статическое начертание, либо один вариант для variable:
          @font-face { font-family:'Inter'; font-weight:400;
          font-display:block; src:url('/fonts/inter-400.woff2')
          format('woff2'); } — и так же для 500/600/700, меняя
          вес и путь к файлу.
     5. Удалите текущий <link rel="stylesheet" href="fonts.googleapis...">
        ниже — он больше не будет нужен.
     ============================================================ */
