/* ===== Токены ===== */
:root {
  --brand: #1f5c8b;
  --brand-dark: #123c5c;
  --accent: #ff5900;
  --accent-dark: #cc4700;
  --ink: #1b2530;
  --ink-soft: #55626e;
  --line: #e1e6ea;
  --bg: #f6f8fa;
  --card-bg: #ffffff;
  --success: #1e8e5a;
  --error: #c0392b;
  --radius: 10px;
  --shadow: 0 2px 10px rgba(20, 30, 45, 0.06);
  --shadow-hover: 0 8px 24px rgba(20, 30, 45, 0.12);
  --container-w: 1360px;
  --font-main: 'Manrope', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 16px;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* Страховка от горизонтального скролла страницы (найдено пользователем на
   350px) — основные причины устранены точечно (min-width: 0 у
   .catalog-layout/.cards-grid/.types-grid и т.п., см. блок перед
   "Responsive" ниже), но у CSS Grid при делении дробной ширины на колонки
   (1fr) остаётся пара лишних пикселей "по спецификации" (сумма
   getBoundingClientRect всех колонок сходится с шириной контейнера, а вот
   scrollWidth документа — иногда на 2-4px больше, это особенность
   субпиксельной раскладки grid, а не видимый глазу элемент, вылезающий за
   край). overflow-x: hidden на html — обычная практика для таких
   остаточных долей пикселя, НЕ ломает собственный внутренний скролл
   .compare-table-wrap (overflow-x: auto у него — независимый,
   "вложенный" scroll-контейнер, наружу не выходит и это правило его не
   трогает). */
html, body { overflow-x: hidden; }
body {
  font-family: var(--font-main);
  color: var(--ink);
  background: var(--bg);
  line-height: 1.5;
}
button, input, select, textarea { font-family: inherit; }
h1, h2, h3, h4 { font-weight: 800; }
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4 { margin: 0 0 .5em; line-height: 1.25; }
p { margin: 0 0 1em; }
ul { margin: 0; padding: 0; list-style: none; }
.container { max-width: var(--container-w); margin: 0 auto; padding: 0 20px; }

/* ===== Кнопки ===== */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 6px; border-radius: 8px; font-weight: 600; font-size: .95rem;
  padding: 12px 22px; cursor: pointer; border: 2px solid transparent;
  transition: all .15s ease; text-align: center;
}
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-dark); }
.btn-outline { background: transparent; border-color: var(--brand); color: var(--brand); }
.btn-outline:hover { background: var(--brand); color: #fff; }
.btn-text { background: transparent; color: var(--ink-soft); border: none; }
.btn-text:hover { color: var(--brand); }
.btn-large { padding: 15px 28px; font-size: 1.05rem; }
.btn-small { padding: 8px 16px; font-size: .85rem; }
.btn-block { width: 100%; }

/* ===== Header ===== */
.site-header { background: #fff; border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 50; }
.header-inner { display: flex; align-items: center; gap: 24px; height: 72px; }
.logo { display: flex; align-items: center; gap: 10px; font-weight: 800; font-size: 1.1rem; color: var(--brand-dark); letter-spacing: .01em; text-transform: uppercase; }
.logo-icon { color: var(--brand); display: inline-flex; }
.logo-icon img { display: block; }
.logo-text-accent { color: var(--accent); }
.main-nav { display: flex; gap: 24px; margin-right: auto; margin-left: 12px; }
.main-nav a { font-weight: 600; color: var(--ink-soft); padding: 6px 0; border-bottom: 2px solid transparent; }
.main-nav a:hover, .main-nav a.active { color: var(--brand); border-color: var(--accent); }
/* "Позвонить"/"Оставить заявку" (templates/header.php, внутри #mainNav) —
   по просьбе пользователя видны только в открытом мобильном меню (см.
   .main-nav.open .mobile-menu-actions в @max-width:640px ниже); на
   десктопе .main-nav — обычный горизонтальный ряд ссылок, где этому блоку
   не место (телефон и кнопка "Каталог" там и так есть в .header-contacts) —
   поэтому по умолчанию скрыт. */
.mobile-menu-actions { display: none; }
.header-contacts { display: flex; align-items: center; gap: 16px; margin-left: auto; }
.header-phone { font-weight: 700; color: var(--ink); white-space: nowrap; }

/* ===== Переключатель города ===== */
.city-switcher { position: relative; }
.city-switcher-btn {
  display: flex; align-items: center; gap: 6px; background: #eef2f5; border: none;
  border-radius: 20px; padding: 8px 14px; font-weight: 600; font-size: .88rem; color: var(--ink);
  cursor: pointer; white-space: nowrap;
}
.city-switcher-btn:hover { background: #e2e8ed; }
.city-switcher-btn svg:first-child { color: var(--accent); }
.city-switcher-panel {
  position: absolute; top: calc(100% + 10px); right: 0; width: 280px; max-height: 360px;
  background: #fff; border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--shadow-hover);
  padding: 12px; z-index: 60; display: flex; flex-direction: column; gap: 10px;
}
.city-switcher-panel[hidden] { display: none; }
.city-search {
  padding: 9px 12px; border: 1px solid var(--line); border-radius: 6px; font-family: inherit; font-size: .9rem; width: 100%;
}
.city-list { overflow-y: auto; display: flex; flex-direction: column; }
.city-list-item { padding: 8px 10px; border-radius: 6px; font-size: .9rem; color: var(--ink); }
.city-list-item:hover { background: #f2f5f7; }
.city-list-item.is-current { background: #eaf2f8; color: var(--brand); font-weight: 700; }
.city-list-item[hidden] { display: none; }
.city-list-item-all { font-weight: 700; border-bottom: 1px solid var(--line); border-radius: 0; margin-bottom: 4px; padding-bottom: 10px; }
.nav-toggle { display: none; flex-direction: column; gap: 5px; background: none; border: none; cursor: pointer; padding: 8px; }
.nav-toggle span { width: 22px; height: 2px; background: var(--ink); }

/* ===== Hero ===== */
.hero { background: linear-gradient(135deg, #eef4f9 0%, #f6f8fa 60%); padding: 56px 0; }
.hero-inner { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: 40px; align-items: center; }
.hero h1 { font-size: 2.2rem; color: var(--brand-dark); }
.hero-lead { color: var(--ink-soft); font-size: 1.05rem; max-width: 46ch; }
.hero-actions { display: flex; gap: 14px; margin: 22px 0; flex-wrap: wrap; }
.hero-badges { display: flex; gap: 18px; flex-wrap: wrap; color: var(--ink-soft); font-size: .9rem; }
.hero-art img { width: 100%; height: auto; }

/* ===== Sections ===== */
.section { padding: 52px 0; }
.section-title { font-size: 1.6rem; color: var(--brand-dark); }
.section-header-row { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 20px; }
.section-link { color: var(--brand); font-weight: 600; }
.section-link:hover { color: var(--accent); }

/* ===== Types grid ===== */
.types-section { background: #fff; }
.types-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; margin-top: 20px; }
.type-card {
  background: var(--card-bg); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 18px; text-align: center; transition: box-shadow .15s, transform .15s;
}
.type-card:hover { box-shadow: var(--shadow-hover); transform: translateY(-2px); }
.type-card img { width: 100%; height: 70px; object-fit: contain; margin-bottom: 10px; }
.type-name { display: block; font-weight: 700; margin-bottom: 4px; }
.type-count { display: block; font-size: .82rem; color: var(--ink-soft); }

/* ===== Cards grid (catalog) ===== */
.cards-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; margin-top: 8px; }
.card {
  background: var(--card-bg); border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; display: flex; flex-direction: column; transition: box-shadow .15s, transform .15s;
}
.card:hover { box-shadow: var(--shadow-hover); transform: translateY(-3px); }
.card-image-wrap { position: relative; }
.card-image { position: relative; display: block; aspect-ratio: 4/3; background: #eef2f5; overflow: hidden; }
/* Кнопка "Редактировать" для залогиненного админа (см. adminLoggedIn() в
   app/functions.php) — намеренно ВНЕ .card-image (там <a>, вложенные <a>
   невалидны), но позиционируется поверх того же .card-image-wrap. */
.card-edit-link {
  position: absolute; right: 8px; bottom: 8px; z-index: 2;
  background: rgba(20, 30, 40, .78); color: #fff; font-size: .72rem; font-weight: 700;
  padding: 4px 9px; border-radius: 14px; text-decoration: none; white-space: nowrap;
}
.card-edit-link:hover { background: var(--brand); }
.card-image img { width: 100%; height: 100%; object-fit: cover; }
.badge { position: absolute; top: 10px; padding: 4px 10px; border-radius: 20px; font-size: .72rem; font-weight: 700; color: #fff; }
.badge-featured { left: 10px; background: var(--accent); }
.badge-sale { right: 10px; background: var(--error); }
.badge-sold { left: 10px; top: 10px; background: var(--ink-soft); }
/* "Нет в наличии"/"Резерв (оплачен)" — две независимые недельные подборки
   (см. ContainerRepo::weeklyOutOfStockIds()/weeklyReservedIds()), теперь
   могут быть активны на одном контейнере одновременно. .badge-stack —
   общий столбик в левом верхнем углу картинки: складывает бейджи друг под
   другом вместо того чтобы они перекрывали друг друга в одной точке
   (left:10px/top:10px, как раньше, когда был активен только один за раз). */
.badge-stack { position: absolute; top: 10px; left: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.badge-stack .badge { position: static; }
.badge-outofstock { background: var(--error); }
.badge-reserved { background: var(--success); }
.card-body { padding: 16px; display: flex; flex-direction: column; gap: 10px; flex: 1; }
.card-title { font-size: 1rem; }
.card-title a:hover { color: var(--brand); }
.card-specs { display: flex; flex-direction: column; gap: 3px; color: var(--ink-soft); font-size: .85rem; }
.card-footer { margin-top: auto; display: flex; align-items: center; justify-content: space-between; gap: 10px; padding-top: 8px; border-top: 1px solid var(--line); }
.card-price { display: flex; flex-direction: column; }
.price-old { text-decoration: line-through; color: var(--ink-soft); font-size: .82rem; }
.price-current { font-weight: 800; font-size: 1.1rem; color: var(--brand-dark); }
/* "Нет в наличии"/"Резерв (оплачен)" (см. ContainerRepo::weeklyOutOfStockIds()/
   weeklyReservedIds()) — по просьбе пользователя цена теперь ЗАЧЁРКНУТА
   (одного притушенного серого цвета оказалось недостаточно заметно), плюс
   серая подпись-статус под ней вместо обычного CTA. */
.card-price-muted .price-current, .card-price-muted .price-old { color: var(--ink-soft); text-decoration: line-through; }
.card-price-note { color: var(--ink-soft); font-size: .78rem; font-weight: 600; margin-top: 2px; }

/* ===== Общий стек хэндлов плавающих боковых панелей =====
   (templates/footer.php) — хэндлы (кнопки) "Товара дня"/"Контейнера
   месяца" и "Избранного" стоят ВПЛОТНУЮ друг к другу (gap: 0) в одном
   компактном блоке, прижатом к правому краю экрана и отцентрированном по
   вертикали (top: 50% + translateY(-50%)). Тела панелей (.side-picks-body/
   .side-favorites-body) сюда не входят — каждое само по себе прижато к
   правому краю (right: 0, тот же приём). По умолчанию кнопки и тело
   открытой панели занимают одно и то же место (правый край экрана) — видны
   только кнопки, тело за краем (transform: translateX).
   По просьбе пользователя кнопки больше НЕ разъезжаются по отдельности
   (раньше уезжала только та, чья панель открыта, а вторая оставалась у
   края) — теперь весь блок .side-panels сдвигается ЦЕЛИКОМ, одной группой,
   и всегда остаётся у левого края открытой панели. Ширину сдвига (она
   разная у разных панелей и разная на мобильном — см. media-запрос ниже)
   вычисляет JS по фактической ширине открытого тела (offsetWidth, не
   захардкожено) и кладёт в CSS-переменную --panels-shift на самом
   .side-panels; класс .is-shifted включает сдвиг (public/assets/js/main.js,
   updateSidePanelsShift()). Когда открытых панелей нет — класс снят, блок
   сам возвращается к краю (right: 0).
   Чтобы добавить сюда ещё один хэндл в будущем, достаточно вывести его
   кнопку в этот же блок (см. докблок в footer.php) и зарегистрировать его
   тело через registerSidePanel() в main.js — сдвиг группы посчитается сам,
   ничего в CSS дополнительно заводить не нужно. */
.side-panels {
  position: fixed; top: 50%; right: 0; transform: translateY(-50%); z-index: 46;
  display: flex; flex-direction: column; align-items: stretch;
  transition: right .3s ease;
}
.side-panels.is-shifted { right: var(--panels-shift, 0px); }
.side-panels > button:first-child { border-radius: 8px 0 0 0; }
.side-panels > button:last-child { border-radius: 0 0 0 8px; }

/* ===== "Товар дня" / "Контейнер месяца" — плавающая боковая панель =====
   (templates/day_month_picks.php, подключается из templates/footer.php —
   видна на КАЖДОЙ публичной странице). .side-picks-toggle — кнопка-хэндл
   (значок 🔥, раньше была обычная стрелка — по просьбе пользователя),
   стоит в общем стеке .side-panels; сама кнопка больше никуда не едет —
   при открытии сдвигается (вместе со второй кнопкой) весь .side-panels,
   см. докблок выше. .is-open на кнопке — только подсветка фона (какая
   именно панель сейчас открыта), на позицию больше не влияет.
   .side-picks-body — само тело панели, независимый fixed-элемент, всегда
   прижато к правому краю (right: 0). Свёрнуто (.is-collapsed, состояние по
   умолчанию) — translateX(120%) уводит тело целиком за правый край экрана;
   открыто — translateX(0), тело встаёт вровень с краем (там, где до этого
   была кнопка).
   .is-pending на самой КНОПКЕ (не на теле) — первые 30 секунд на сайте
   кнопка скрыта (display:none, см. докблок в day_month_picks.php и таймер
   в main.js); как только 30 секунд проходят, JS не только снимает
   is-pending с кнопки, но и сам раскрывает тело панели (по просьбе
   пользователя — панель должна сама выехать с предложениями, а не просто
   "появиться" кнопкой, которую ещё надо нажать). */
.side-picks-toggle {
  width: 34px; height: 64px; flex-shrink: 0; border: none;
  background: var(--brand); color: #fff; font-size: 1.2rem;
  line-height: 1; cursor: pointer; box-shadow: var(--shadow-hover);
  transition: background .15s ease;
  display: flex; align-items: center; justify-content: center;
}
.side-picks-toggle:hover { background: var(--brand-dark); }
.side-picks-toggle.is-pending { display: none; }
.side-picks-toggle.is-open { background: var(--brand-dark); }
.side-picks-body {
  position: fixed; top: 50%; right: 0; z-index: 45;
  transform: translateY(-50%) translateX(0); transition: transform .3s ease;
  width: 190px; max-height: calc(100vh - 40px); overflow-y: auto;
  background: var(--card-bg); border: 1px solid var(--line); border-right: none;
  border-radius: var(--radius) 0 0 var(--radius); box-shadow: var(--shadow-hover);
  padding: 12px; display: flex; flex-direction: column; gap: 12px;
}
.side-picks-body.is-collapsed { transform: translateY(-50%) translateX(120%); }
.side-pick-card {
  position: relative; display: block; border: 1px solid var(--line); border-radius: 8px;
  overflow: hidden; background: #fff; transition: box-shadow .15s, transform .15s;
}
.side-pick-card:hover { box-shadow: var(--shadow-hover); transform: translateY(-2px); }
.side-pick-label {
  position: absolute; top: 6px; left: 6px; z-index: 2;
  font-size: .68rem; font-weight: 800; color: #fff; padding: 3px 9px; border-radius: 20px; white-space: nowrap;
}
.side-pick-day .side-pick-label { background: var(--accent); }
.side-pick-month .side-pick-label { background: var(--brand); }
.side-pick-card img { display: block; width: 100%; aspect-ratio: 4/3; object-fit: cover; background: #eef2f5; }
.side-pick-title {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  padding: 8px 10px 0; font-size: .82rem; font-weight: 600; color: var(--ink);
}
.side-pick-price { display: block; padding: 4px 10px 10px; font-weight: 800; color: var(--brand-dark); }
.side-picks-cta { font-size: .85rem; padding: 10px 12px; }

/* ===== "Добавить в избранное" — сердечко на карточке товара =====
   (templates/catalog_card.php) — на КАЖДОЙ карточке по всему сайту.
   Противоположный угол от .card-edit-link (тот — правый нижний, этот —
   левый нижний), по той же причине вне <a class="card-image"> (см.
   комментарий в самом catalog_card.php). .is-active — товар уже в
   избранном (JS переключает и класс, и сам символ ♡/♥, см. main.js). */
.fav-toggle {
  position: absolute; left: 8px; bottom: 8px; z-index: 2;
  width: 30px; height: 30px; border: none; border-radius: 50%;
  background: rgba(255, 255, 255, .92); color: var(--ink-soft); font-size: 1.05rem; line-height: 1;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  box-shadow: var(--shadow); transition: color .15s ease, transform .15s ease;
}
.fav-toggle:hover { transform: scale(1.08); }
.fav-toggle.is-active { color: var(--error); }

/* То же сердечко, но как обычная подписанная кнопка — на странице самого
   контейнера (app/pages/container.php, .detail-actions), там уже есть
   место под полноразмерную кнопку, иконка поверх картинки не нужна. */
.fav-toggle-detail-icon { margin-right: 2px; }
.fav-toggle-detail.is-active { background: var(--error); border-color: var(--error); color: #fff; }

/* ===== "Избранное" — плавающая боковая панель =====
   (templates/favorites_panel.php, подключается из templates/footer.php).
   .side-favorites-toggle — кнопка-хэндл (сердечко), стоит в общем стеке
   .side-panels вплотную к хэндлу "Товара дня"; сама кнопка больше никуда
   не едет — при открытии сдвигается (вместе со второй кнопкой) весь
   .side-panels целиком, см. докблок у .side-panels выше — тот же приём,
   что и у .side-picks-toggle. .is-open на кнопке — только подсветка фона.
   .side-favorites-body — само тело панели, независимый fixed-элемент,
   всегда прижато к правому краю (right: 0). Свёрнуто (.is-collapsed, по
   умолчанию) — translateX(120%) уводит тело за правый край экрана; открыто
   — translateX(0), тело встаёт вровень с краем. Открывается только по
   клику на хэндл — панель для этого отдельного "появления" по таймеру не
   имеет (в отличие от "Товара дня"), хэндл виден сразу.
   Шире промо-панели (280px против 190px, по просьбе пользователя "чтобы
   всё поместилось") — здесь список из потенциально многих товаров,
   отрисованный горизонтальными строками (картинка + текст + крестик
   "убрать"), а не карточками. */
.side-favorites-toggle {
  /* position: relative — обязательно: .side-favorites-count ниже висит
     на этой кнопке через position:absolute, а без своего positioned
     предка она "улетала" к ближайшему таковому — общему .side-panels
     (см. его position:fixed) — и садилась на угол ПЕРВОЙ кнопки в общем
     стеке (.side-picks-toggle, "Топ дня/месяца"), а не на "Избранное". */
  position: relative;
  width: 34px; height: 64px; flex-shrink: 0; border: none;
  background: var(--accent); color: #fff; font-size: 1.3rem;
  line-height: 1; cursor: pointer; box-shadow: var(--shadow-hover);
  transition: background .15s ease;
  display: flex; align-items: center; justify-content: center;
}
.side-favorites-toggle:hover { background: var(--accent-dark); }
.side-favorites-toggle.is-open { background: var(--accent-dark); }
.side-favorites-count {
  position: absolute; top: -6px; right: -6px; min-width: 18px; height: 18px; padding: 0 4px;
  border-radius: 999px; background: var(--brand-dark); color: #fff; font-size: .68rem; font-weight: 800;
  display: flex; align-items: center; justify-content: center; line-height: 1; box-shadow: var(--shadow);
}
/* Баг, найденный при разборе горизонтального скролла на 350px (см. правки
   ниже про .catalog-layout/.cards-grid): `.side-favorites-count { display:
   flex }` выше — селектор по КЛАССУ, та же специфичность (0,1,0), что и
   стандартное браузерное правило `[hidden] { display: none }` (селектор
   по АТРИБУТУ) — и, идя позже в каскаде (это наша таблица стилей, не
   браузерная), побеждает. Из-за этого счётчик "0" в кнопке "Избранное"
   был виден ВСЕГДА, даже когда JS явно ставит el.hidden = true, пока
   ничего не добавлено в избранное (см. main.js). Та же причина и то же
   решение, что уже было у .review-item[hidden] в
   templates/home_reviews_section.php — просто явно объявляем display:none
   для атрибута с более высоким приоритетом (без !important, обычной
   специфичности [класс][атрибут] > [класс] достаточно). */
.side-favorites-count[hidden] { display: none; }
.side-favorites-body {
  position: fixed; top: 50%; right: 0; z-index: 45;
  transform: translateY(-50%) translateX(0); transition: transform .3s ease;
  width: 280px; max-height: calc(100vh - 40px); overflow-y: auto;
  background: var(--card-bg); border: 1px solid var(--line); border-right: none;
  border-radius: var(--radius) 0 0 var(--radius); box-shadow: var(--shadow-hover); padding: 14px;
}
.side-favorites-body.is-collapsed { transform: translateY(-50%) translateX(120%); }
.side-favorites-head { margin-bottom: 8px; }
.side-favorites-head h4 { margin: 0; font-size: .98rem; }
.side-favorites-empty { color: var(--ink-soft); font-size: .84rem; margin: 0; padding: 6px 0; }
.side-favorites-cta { margin-top: 10px; font-size: .85rem; padding: 10px 12px; }

/* ===== Модалка "Заказать из избранного" (templates/favorites_panel.php) ===== */
.favorites-order-items {
  display: flex; flex-direction: column; gap: 8px; max-height: 240px; overflow-y: auto;
  margin-bottom: 16px; padding-right: 2px;
}
.favorites-order-item {
  display: flex; align-items: center; gap: 10px; padding: 7px 8px; border: 1px solid var(--line);
  border-radius: var(--radius); cursor: pointer;
}
.favorites-order-item input[type="checkbox"] { flex-shrink: 0; width: 16px; height: 16px; accent-color: var(--brand); }
.favorites-order-item img { width: 40px; height: 40px; object-fit: cover; border-radius: 3px; flex-shrink: 0; background: var(--bg); }
.favorites-order-item-text { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.favorites-order-item-title {
  font-size: .82rem; font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap;
}
.favorites-order-item-price { font-size: .8rem; font-weight: 800; color: var(--ink-soft); }
.favorites-order-item.is-unchecked { opacity: .5; }
.favorites-order-hint { color: var(--ink-soft); font-size: .82rem; margin: 0 0 14px; }
.fav-item { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--line); }
.fav-item:last-child { border-bottom: none; }
.fav-item-link { display: flex; align-items: center; gap: 10px; flex: 1 1 auto; min-width: 0; text-decoration: none; }
.fav-item-link img { width: 48px; height: 48px; border-radius: 6px; object-fit: cover; background: #eef2f5; flex-shrink: 0; }
.fav-item-text { display: flex; flex-direction: column; min-width: 0; gap: 2px; }
.fav-item-title {
  font-size: .84rem; font-weight: 600; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fav-item-price { font-size: .84rem; font-weight: 800; color: var(--brand-dark); }
.fav-item-remove {
  flex-shrink: 0; width: 26px; height: 26px; border: none; background: transparent;
  color: var(--ink-soft); font-size: 1.15rem; line-height: 1; cursor: pointer; border-radius: 50%;
}
.fav-item-remove:hover { background: var(--bg); color: var(--error); }

/* ===== Модальное окно "Получить предложение" (templates/day_month_picks.php) =====
   Открывается кнопкой внизу боковой панели (.side-picks-cta) — JS в
   public/assets/js/main.js снимает/ставит атрибут [hidden] на .site-modal-overlay.
   [hidden] явно продублирован своим правилом ниже — иначе его перебил бы
   соседний display:flex у того же селектора (авторский CSS всегда сильнее
   базового [hidden]{display:none} браузера, несмотря на near-равную
   специфичность, из-за порядка подключения таблиц стилей). */
.site-modal-overlay {
  position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center;
  padding: 20px; background: rgba(15, 23, 32, .55);
}
.site-modal-overlay[hidden] { display: none; }
.site-modal {
  position: relative; width: 100%; max-width: 380px; max-height: 90vh; overflow-y: auto;
  background: #fff; border-radius: var(--radius); box-shadow: var(--shadow-hover); padding: 26px 22px 22px;
}
.site-modal h3 { margin: 0 0 16px; font-size: 1.15rem; padding-right: 26px; }
.site-modal-close {
  position: absolute; top: 14px; right: 14px; width: 30px; height: 30px; border: none; border-radius: 50%;
  background: var(--bg); color: var(--ink-soft); font-size: 1.3rem; line-height: 1; cursor: pointer;
}
.site-modal-close:hover { background: var(--line); color: var(--ink); }

/* ===== Steps ===== */
.how-section { background: #fff; }
.steps-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; margin-top: 20px; }
.step { padding: 20px; }
.step-num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%; background: var(--accent); color: #fff;
  font-weight: 800; margin-bottom: 10px;
}
.step h3 { font-size: 1.05rem; }
.step p { color: var(--ink-soft); font-size: .9rem; margin: 0; }

/* ===== Доставка и отгрузка (templates/delivery_terminal.php) ===== */
.delivery-section { background: var(--bg); }
.delivery-lead { color: var(--ink-soft); font-size: .95rem; margin: 0 0 16px; }
.delivery-terminals { list-style: none; margin: 0 0 20px; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.delivery-terminal-item {
  display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px; border: 1px solid var(--line);
  border-radius: var(--radius); background: #fff; font-size: .92rem; color: var(--ink);
}
.delivery-terminal-icon { flex-shrink: 0; font-size: 1.05rem; line-height: 1.3; }
.delivery-note { color: var(--ink-soft); font-size: .88rem; margin: 0 0 8px; max-width: 720px; }
.delivery-note:last-child { margin-bottom: 0; }
.delivery-note a { color: var(--brand); font-weight: 600; }

/* ===== Наши преимущества ===== */
.advantages-section { background: #fff; }
.advantages-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-top: 20px; }
.advantage {
  display: flex; gap: 14px; align-items: flex-start;
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius); padding: 20px;
}
.advantage-icon { font-size: 1.6rem; line-height: 1; flex-shrink: 0; }
.advantage-title { font-size: 1rem; margin-bottom: 4px; }
.advantage-desc { color: var(--ink-soft); font-size: .88rem; margin: 0; }

/* ===== География городов (главная) ===== */
.geo-section { background: #fff; }
.geo-lead { color: var(--ink-soft); font-size: .95rem; max-width: 640px; margin: 0 0 24px; }
.city-tags { display: flex; flex-wrap: wrap; gap: 10px; }
.city-tag {
  display: inline-block; padding: 9px 16px; border-radius: 20px; font-size: .88rem; font-weight: 600;
  background: var(--bg); border: 1px solid var(--line); color: var(--ink); transition: all .15s ease;
}
.city-tag:hover { border-color: var(--brand); color: var(--brand); }
.city-tag.is-current { background: var(--accent); border-color: var(--accent); color: #fff; }

/* ===== Сравнительная таблица характеристик (главная) =====
   Секции сверху/снизу (how-section, advantages-section) — белые, поэтому
   для заметности у этого блока отдельный тонированный фон (не сливается). */
.compare-section {
  background: linear-gradient(135deg, #eaf1f8 0%, #dbe7f1 100%);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.compare-lead { color: var(--ink-soft); font-size: .95rem; max-width: 680px; margin: 0 0 24px; }
.compare-table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); background: #fff; box-shadow: var(--shadow); }
.compare-table { width: 100%; min-width: 900px; border-collapse: collapse; }
.compare-table th, .compare-table td { padding: 12px 14px; text-align: left; font-size: .88rem; white-space: nowrap; }
.compare-table thead th {
  background: var(--bg); color: var(--ink-soft); font-weight: 700; font-size: .78rem;
  text-transform: uppercase; letter-spacing: .02em; border-bottom: 1px solid var(--line); white-space: normal;
}
.compare-table tbody tr { border-bottom: 1px solid var(--line); transition: background .12s ease; }
.compare-table tbody tr:last-child { border-bottom: none; }
.compare-table tbody tr:hover { background: #f6f9fb; }
.compare-table td { color: var(--ink-soft); }
.compare-type-cell a { display: block; color: var(--ink); font-weight: 700; }
.compare-type-cell a:hover { color: var(--brand); }
.compare-size { font-weight: 500; color: var(--ink-soft); font-size: .84rem; }
.compare-stock a { color: var(--brand); font-weight: 700; }
.compare-stock a:hover { color: var(--accent); }

/* ===== FAQ по городу (app/pages/home.php, FAQPage JSON-LD рядом) ===== */
.faq-section { background: #fff; }
.faq-list { display: flex; flex-direction: column; gap: 10px; }
.faq-item { background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius); padding: 4px 20px; }
.faq-question {
  cursor: pointer; list-style: none; padding: 14px 28px 14px 0; font-weight: 600; color: var(--ink);
  position: relative;
}
.faq-question::-webkit-details-marker { display: none; }
.faq-question::after {
  content: '+'; position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  font-size: 1.3rem; font-weight: 400; color: var(--brand); line-height: 1;
}
.faq-item[open] .faq-question::after { content: '−'; }
.faq-answer { color: var(--ink-soft); font-size: .93rem; padding: 0 0 16px; }

/* ===== CTA ===== */
.cta-section { background: var(--brand-dark); color: #fff; border-radius: 0; }

/* ===== Хаб-главная (/, без привязки к городу) ===== */
.hub-cities-section { background: #fff; scroll-margin-top: 90px; }
.hub-cities-lead { color: var(--ink-soft); font-size: .95rem; max-width: 640px; margin: 0 0 24px; }
.hub-cities-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 12px; }
.hub-city-card {
  display: flex; align-items: center; justify-content: center; text-align: center;
  padding: 14px 10px; border: 1px solid var(--line); border-radius: 8px;
  font-weight: 600; font-size: .92rem; color: var(--ink); background: var(--bg);
  transition: all .15s ease;
}
.hub-city-card:hover { border-color: var(--accent); color: var(--accent); background: #fff; box-shadow: var(--shadow); }
.hub-city-card.is-featured { border-color: var(--brand); background: #eaf2f8; color: var(--brand-dark); }
.cta-inner { display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.cta-inner h2 { color: #fff; }
.cta-inner p { color: #cfe0ee; margin: 0; }

/* ===== СЕО-текст на главной ===== */
.seo-section { padding-top: 44px; }
.seo-text { max-width: 900px; }
.seo-text p { color: var(--ink-soft); font-size: .95rem; }
.seo-text ul { color: var(--ink-soft); font-size: .95rem; padding-left: 22px; margin: 0 0 16px; }
.seo-text li { margin-bottom: 6px; }
.seo-text a { color: var(--brand); font-weight: 600; text-decoration: underline; }
.seo-text a:hover { color: var(--accent); }

/* ===== Catalog page ===== */
/* Каталог — с сентября 2026 блок на городской главной (id="catalog"), а не
   отдельная страница (см. templates/catalog_section.php) — scroll-margin-top
   нужен, чтобы sticky-шапка не перекрывала заголовок при переходе по якорю
   #catalog (тот же приём, что и для #calc, см. .calc-home-section ниже). */
.catalog-section { scroll-margin-top: 90px; }
.catalog-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 24px; flex-wrap: wrap; gap: 8px; }
.catalog-count { color: var(--ink-soft); }
.catalog-layout { display: grid; grid-template-columns: 260px 1fr; gap: 28px; align-items: start; }
.filters { background: var(--card-bg); border: 1px solid var(--line); border-radius: var(--radius); padding: 20px; position: sticky; top: 90px; }
.filter-group { margin-bottom: 16px; display: flex; flex-direction: column; gap: 6px; }
.filter-group label { font-weight: 600; font-size: .88rem; }
.filter-group input, .filter-group select {
  padding: 9px 10px; border: 1px solid var(--line); border-radius: 6px; font-size: .92rem; width: 100%;
  font-family: inherit; background: #fff;
}
.range-inputs { display: flex; gap: 8px; }
.catalog-toolbar { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 16px; margin-bottom: 16px; }
.sort-form { display: flex; align-items: center; gap: 8px; font-size: .9rem; color: var(--ink-soft); }
.sort-form select { padding: 7px 10px; border-radius: 6px; border: 1px solid var(--line); }

/* Переключатель вида каталога (плитка/список) — справа в .catalog-toolbar,
   после селекторов "Показывать"/"Сортировка". Выбор сохраняется в cookie
   catalog_view на клиенте (см. public/assets/js/main.js) и читается сервером
   при следующей загрузке страницы (см. $catalogView в
   catalog_section.php/catalog_section_hub.php), чтобы сразу открылся нужный
   вид без "мигания" плиткой. Оформлен ярче обычных select'ов рядом (заливка
   в цвет бренда на активной кнопке) — чтобы бросался в глаза как отдельный
   переключатель, а не терялся среди фильтров. */
.view-toggle { display: flex; gap: 3px; background: #fff; border: 1.5px solid var(--brand); border-radius: 8px; padding: 3px; }
.view-toggle-btn {
  display: flex; align-items: center; justify-content: center;
  width: 32px; height: 30px; border: none; border-radius: 6px; background: transparent;
  color: var(--brand); font-size: 1rem; line-height: 1; cursor: pointer; transition: all .15s ease;
}
.view-toggle-btn:hover { background: #eaf2f8; }
.view-toggle-btn.is-active { background: var(--brand); color: #fff; }

/* Вид "Список" — узкие строки с небольшой квадратной картинкой вместо
   плитки. Класс .view-list ставится на .catalog-results (а не только на
   .cards-grid), чтобы работать и при пустом результате поиска (когда вместо
   .cards-grid выводится .empty-state) — переключателю не важно, есть ли
   сейчас карточки в DOM. */
.catalog-results.view-list .cards-grid { grid-template-columns: 1fr; gap: 10px; }
.catalog-results.view-list .card { flex-direction: row; align-items: center; gap: 14px; padding: 10px 14px; }
.catalog-results.view-list .card:hover { transform: none; }
.catalog-results.view-list .card-image-wrap { flex: 0 0 76px; width: 76px; height: 76px; border-radius: 8px; overflow: hidden; }
.catalog-results.view-list .card-image { width: 100%; height: 100%; }
/* Бейджи статуса и кнопка "Редактировать" тесно не помещаются на маленькой
   квадратной картинке строки — статус и так виден рядом с ценой
   (.card-price-note), а "Редактировать" остаётся доступной в плитке. */
.catalog-results.view-list .card-image-wrap .badge, .catalog-results.view-list .card-edit-link { display: none; }
.catalog-results.view-list .card-body { flex: 1 1 auto; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px 20px; padding: 0; }
.catalog-results.view-list .card-title { flex: 1 1 200px; margin: 0; }
.catalog-results.view-list .card-specs { flex-direction: row; flex-wrap: wrap; gap: 4px 14px; flex: 1 1 220px; }
.catalog-results.view-list .card-footer { margin-top: 0; padding-top: 0; border-top: none; flex: 0 0 auto; }
.empty-state { padding: 60px 20px; text-align: center; color: var(--ink-soft); background: #fff; border-radius: var(--radius); border: 1px solid var(--line); }
.pagination { display: flex; align-items: center; justify-content: center; gap: 18px; margin-top: 32px; }
.page-link { font-weight: 700; color: var(--brand); }
.page-link:hover { color: var(--accent); }
.page-current { color: var(--ink-soft); font-size: .9rem; }

/* ===== Container detail ===== */
.breadcrumbs { color: var(--ink-soft); font-size: .85rem; margin-bottom: 20px; }
.breadcrumbs a:hover { color: var(--brand); }
/* Кнопка "Редактировать" на странице контейнера для залогиненного админа
   (см. adminLoggedIn() в app/functions.php) — та же строка, что и хлебные
   крошки, справа. */
.page-head-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.page-head-row .breadcrumbs { margin-bottom: 20px; }
.admin-edit-link {
  display: inline-flex; align-items: center; gap: 4px; font-size: .82rem; font-weight: 700;
  color: var(--brand); background: #eef2f5; padding: 4px 12px; border-radius: 20px;
  text-decoration: none; white-space: nowrap; margin-bottom: 20px;
}
.admin-edit-link:hover { background: var(--brand); color: #fff; }
.container-detail-layout { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: 36px; margin-bottom: 40px; }
.gallery-main { position: relative; border-radius: var(--radius); overflow: hidden; background: #eef2f5; aspect-ratio: 4/3; }
.gallery-main img { width: 100%; height: 100%; object-fit: cover; }
.gallery-thumbs { display: flex; gap: 10px; margin-top: 10px; flex-wrap: wrap; }
.thumb { width: 70px; height: 52px; padding: 0; border: 2px solid transparent; border-radius: 6px; overflow: hidden; cursor: pointer; background: none; }
.thumb img { width: 100%; height: 100%; object-fit: cover; }
.thumb:hover { border-color: var(--accent); }
.detail-info h1 { font-size: 1.7rem; color: var(--brand-dark); }
.detail-tags { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 16px; }
.detail-tags li { background: #eef2f5; color: var(--ink-soft); font-size: .8rem; font-weight: 600; padding: 5px 12px; border-radius: 20px; }
.detail-price { display: flex; align-items: baseline; gap: 12px; margin-bottom: 18px; }
.detail-price .price-current { font-size: 1.9rem; }
/* "Нет в наличии"/"Резерв (оплачен)" (см. ContainerRepo::weeklyOutOfStockIds()/
   weeklyReservedIds()) — теперь могут быть активны одновременно на одном
   контейнере (см. её докблок). Цена — ЗАЧЁРКНУТА (по просьбе пользователя:
   один притушенный серый цвет был недостаточно заметен) и короткая подпись
   сразу под ней (обе, через " · ", если статусов два сразу — см.
   app/pages/container.php); более подробный статус — ниже, в detail-meta
   (см. .detail-availability-highlight-*, разные цвета на разные статусы:
   красный — "ждём", зелёный — "уже оплачено"). */
.detail-price-muted { margin-bottom: 4px; }
.detail-price-muted .price-current, .detail-price-muted .price-old { color: var(--ink-soft); text-decoration: line-through; }
.detail-price-note { color: var(--ink-soft); font-weight: 700; font-size: .9rem; margin: 0 0 18px; }
.detail-availability-highlight { font-weight: 700; }
.detail-availability-highlight-outofstock { color: var(--error); }
.detail-availability-highlight-reserved { color: var(--success); }
.detail-meta { display: flex; flex-direction: column; gap: 6px; margin-bottom: 22px; color: var(--ink-soft); }
.detail-meta strong { color: var(--ink); }
/* Компактный блок "Похожие в наличии" сразу под статусом "Нет в наличии"
   (по чётности недели, см. ContainerRepo::weeklyOutOfStockIds()) — не
   путать с .related-section, это большой блок с полными карточками внизу
   страницы, для обычных (не "нет в наличии") товаров. */
.detail-similar-instock { background: #f6f8fa; border-radius: var(--radius); padding: 14px 16px; margin-bottom: 22px; }
.detail-similar-instock-title { font-weight: 700; font-size: .85rem; margin: 0 0 10px; }
.detail-similar-instock-list { display: flex; flex-direction: column; gap: 8px; }
.detail-similar-instock-list li a {
  display: flex; align-items: center; gap: 10px; color: var(--ink);
}
.detail-similar-instock-list li a:hover { color: var(--brand); }
.detail-similar-instock-list img { width: 44px; height: 34px; object-fit: cover; border-radius: 4px; flex-shrink: 0; }
.detail-similar-instock-title-text { flex: 1; font-size: .85rem; }
.detail-similar-instock-price { font-weight: 700; font-size: .85rem; white-space: nowrap; }
.detail-actions { display: flex; gap: 12px; flex-wrap: wrap; }

.container-secondary-layout { display: grid; grid-template-columns: 1.4fr 1fr; gap: 32px; align-items: start; }
.detail-block { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 22px; margin-bottom: 20px; }
/* Внутренняя ссылка на городскую главную (templates/city_backlink.php) —
   тот же .detail-block, но потоньше и с акцентной полосой слева, чтобы
   читалось как отдельная смысловая врезка, а не ещё один блок характеристик. */
.detail-block-citylink { padding: 14px 22px; border-left: 3px solid var(--brand); }
.detail-block-citylink p { margin: 0; font-size: .95rem; }
.detail-block-citylink a { color: var(--brand); font-weight: 600; }
.detail-block-citylink a:hover { color: var(--brand-dark); }
.specs-table { width: 100%; border-collapse: collapse; }
.specs-table td { padding: 10px 4px; border-bottom: 1px solid var(--line); font-size: .92rem; }
.specs-table td:first-child { color: var(--ink-soft); width: 55%; }
.specs-table td:last-child { font-weight: 700; text-align: right; }

.related-section { padding-top: 0; }

/* ===== Order form ===== */
/* Honeypot-поле форм заявки (см. templates/order_form.php) — скрыто от
   реальных посетителей, но остаётся в разметке и DOM для ботов, которые
   заполняют поля формы вслепую (в т.ч. игнорируя visibility/opacity, но
   display:none отсеивает подавляющее большинство). */
.user-class { display: none; }

.order-form-wrap { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 22px; position: sticky; top: 90px; }
.order-form-wrap h3 { font-size: 1.15rem; }
.form-row { margin-bottom: 14px; }
.form-row label { display: flex; flex-direction: column; gap: 6px; font-weight: 600; font-size: .88rem; }
.form-row input, .form-row textarea {
  padding: 10px; border: 1px solid var(--line); border-radius: 6px; font-family: inherit; font-size: .95rem; resize: vertical;
}
.form-note { font-size: .78rem; color: var(--ink-soft); margin: 10px 0 0; }
.form-row-checkbox label { flex-direction: row; align-items: flex-start; font-weight: 400; gap: 8px; }
.form-row-checkbox input[type="checkbox"] { width: 17px; height: 17px; flex-shrink: 0; margin: 2px 0 0; accent-color: var(--accent); }
.form-row-checkbox span { font-size: .82rem; color: var(--ink-soft); line-height: 1.4; }
.form-row-checkbox a { color: var(--brand); }
.alert { padding: 14px 16px; border-radius: 8px; font-size: .92rem; }
.alert-success { background: #e5f6ee; color: var(--success); }
.alert-error { background: #fdecea; color: var(--error); margin-bottom: 12px; }

/* ===== Отзывы (карточка товара) =====
   Видимый блок — templates/reviews_section.php, форма — templates/review_form.php,
   форма открывается в модалке (.site-modal-overlay/.site-modal — та же обвязка,
   что и у "Получить предложение" в day_month_picks.php, см. чуть выше) — обёртка
   templates/review_modal.php, кнопка-триггер — .reviews-leave-btn ниже. Тот же
   .order-form-wrap-подобный стиль формы (см. "Order form" выше), плюс список
   отзывов и чистый CSS-рейтинг звёздами на радиокнопках (без JS, см. докблок
   .review-rating-stars ниже). */
.reviews-section { margin-top: 28px; }
.reviews-summary { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.reviews-summary-score { font-family: var(--font-display); font-size: 1.6rem; font-weight: 700; color: var(--ink); }
.reviews-summary-stars, .review-item-stars { color: #d9a441; letter-spacing: 1px; }
.reviews-summary-count { font-size: .88rem; color: var(--ink-soft); }
.reviews-empty { color: var(--ink-soft); font-size: .92rem; }

.reviews-list { display: flex; flex-direction: column; gap: 16px; margin: 0 0 20px; padding: 0; list-style: none; }
.review-item { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 16px 18px; }
.review-item-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 6px; }
.review-item-author { font-weight: 700; color: var(--ink); }
.review-item-date { font-size: .8rem; color: var(--ink-soft); margin-left: auto; }
.review-item-city { font-size: .8rem; color: var(--ink-soft); margin: 0 0 6px; }
.review-item-text { font-size: .92rem; color: var(--ink); line-height: 1.5; margin: 0; }

.reviews-leave-btn { margin-top: 4px; }
.review-form-wrap { margin-top: 0; max-width: 480px; }
.review-form-note { font-size: .78rem; color: var(--ink-soft); margin: 10px 0 0; }
.review-rating-legend { display: block; font-weight: 600; font-size: .88rem; margin-bottom: 6px; }

/* Чистый CSS-рейтинг звёздами: радиокнопки идут в разметке в обратном
   порядке (5..1, см. templates/review_form.php), здесь визуально
   переворачиваются (row-reverse) — тогда ":checked ~ label" подсвечивает
   отмеченную звезду и все ей предшествующие в разметке (после переворота —
   визуально все звёзды с БОЛЬШИМ или равным баллом), а ":hover ~ label"
   даёт живой предпросмотр при наведении, без единой строчки JS. */
.review-rating-stars { display: flex; flex-direction: row-reverse; justify-content: flex-end; gap: 2px; font-size: 1.6rem; }
.review-rating-stars input { position: absolute; opacity: 0; width: 0; height: 0; }
.review-rating-stars label { color: var(--line); cursor: pointer; transition: color .1s; }
.review-rating-stars input:checked ~ label,
.review-rating-stars label:hover,
.review-rating-stars label:hover ~ label { color: #d9a441; }

/* ===== Отзывы на главной (templates/home_reviews_section.php) =====
   Витрина последних отзывов со всего сайта (не одного товара, как в блоке
   выше на карточке) — карточки сеткой, а не узкой колонкой. Переиспользует
   .review-item/.review-item-head/.review-item-author/.review-item-stars/
   .review-item-text/.review-item-product-link из блока выше — .reviews-
   list-home только меняет раскладку списка и мелкие детали (объединённая
   строка "дата · город" вместо отдельного абзаца). */
.reviews-home-section { background: var(--bg); }
.reviews-list-home { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; margin: 0 0 20px; padding: 0; list-style: none; }
.reviews-list-home .review-item { display: flex; flex-direction: column; gap: 4px; }
.reviews-list-home .review-item-head { justify-content: space-between; }
.review-item-meta { font-size: .8rem; color: var(--ink-soft); }
.reviews-list-home .review-item-text { flex-grow: 1; }
.review-item-product-link { display: inline-block; margin-top: 4px; font-size: .85rem; font-weight: 700; color: var(--brand); }
.review-item-product-link:hover { color: var(--brand-dark); }
/* "Показать ещё" (по просьбе пользователя, см. докблок home_reviews_section.php
   и main.js) — .review-item выше объявлен как display:flex тем же селектором
   по классу, что у него больший вес, чем у стандартного браузерного правила
   [hidden]{display:none}: без явного переопределения ниже скрытые атрибутом
   `hidden` карточки отзывов всё равно показывались бы (flex "перебивает"
   hidden). Кнопка — по центру, с отступом от списка сверху. */
.reviews-list-home .review-item[hidden] { display: none; }
.reviews-show-more-btn { display: block; margin: 0 auto; }

/* ===== Contacts page ===== */
.contacts-layout { display: grid; grid-template-columns: 1fr 1fr; gap: 36px; margin-top: 24px; }
.contacts-info { display: flex; flex-direction: column; gap: 22px; }
.contact-item h3 { font-size: .85rem; text-transform: uppercase; letter-spacing: .03em; color: var(--ink-soft); margin-bottom: 4px; }
.contact-value { font-size: 1.1rem; font-weight: 600; }
a.contact-value:hover { color: var(--brand); }
/* Терминалы отгрузки на странице Контакты (app/pages/contacts.php) — тот же
   список, что и в templates/delivery_terminal.php, но компактнее под
   сайдбар контактов. */
.contact-terminals { list-style: none; margin: 0 0 8px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.contact-terminals li { font-size: 1rem; font-weight: 600; }
.contact-terminal-note { font-size: .85rem; font-weight: 400; color: var(--ink-soft); margin: 0; }

/* ===== Footer ===== */
.site-footer { background: var(--brand-dark); color: #cfe0ee; margin-top: 40px; }
.footer-inner { display: grid; grid-template-columns: 1.2fr 1fr 1fr; gap: 32px; padding: 44px 20px 24px; }
.footer-logo { color: #fff; margin-bottom: 10px; }
.footer-tagline { color: #a9c3d8; font-size: .9rem; }
.footer-col h4 { color: #fff; font-size: .9rem; text-transform: uppercase; letter-spacing: .04em; margin-bottom: 12px; }
.footer-col { display: flex; flex-direction: column; gap: 8px; }
.footer-col a:hover { color: #fff; }
.footer-bottom { display: flex; justify-content: space-between; gap: 12px; padding: 16px 20px 24px; border-top: 1px solid rgba(255,255,255,.12); font-size: .8rem; color: #93aec2; flex-wrap: wrap; }

/* ===== Плашка согласия на cookie (templates/cookie_consent.php) ===== */
.cookie-consent { position: fixed; left: 0; right: 0; bottom: 0; z-index: 70; background: var(--brand-dark); box-shadow: 0 -4px 16px rgba(20, 30, 45, 0.18); }
.cookie-consent-inner {
  max-width: var(--container-w); margin: 0 auto; padding: 14px 20px; display: flex; align-items: center;
  justify-content: space-between; gap: 20px; flex-wrap: wrap;
}
.cookie-consent-inner p { margin: 0; color: #cfe0ee; font-size: .85rem; line-height: 1.4; }
.cookie-consent-inner a { color: #fff; text-decoration: underline; }
.cookie-consent-inner .btn { flex-shrink: 0; }
.footer-disclaimer { max-width: 620px; }

/* ===== Admin (общие элементы, используются в /admin) ===== */
.admin-body { background: #f1f4f7; min-height: 100vh; }
.admin-header { background: var(--brand-dark); color: #fff; padding: 14px 0; }
.admin-header .container { display: flex; align-items: center; justify-content: space-between; }
.admin-header a { color: #cfe0ee; }
.admin-header a:hover { color: #fff; }
.admin-nav { display: flex; gap: 18px; align-items: center; }
.admin-wrap { max-width: 1100px; margin: 30px auto; padding: 0 20px; }
.admin-card { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 24px; margin-bottom: 20px; }
.admin-table { width: 100%; border-collapse: collapse; }
.admin-table th, .admin-table td { text-align: left; padding: 10px; border-bottom: 1px solid var(--line); font-size: .9rem; vertical-align: middle; }
.admin-table th { color: var(--ink-soft); font-weight: 700; font-size: .8rem; text-transform: uppercase; }
.admin-table img { width: 56px; height: 42px; object-fit: cover; border-radius: 4px; }
.admin-actions { display: flex; gap: 8px; }
.status-pill { display: inline-block; padding: 3px 10px; border-radius: 20px; font-size: .75rem; font-weight: 700; }
.status-new { background: #fdecea; color: var(--error); }
.status-processed { background: #e5f6ee; color: var(--success); }
.status-rejected { background: #eef0f2; color: var(--ink-soft); }
/* Статусы отзывов (/admin/reviews.php) — 'rejected' переиспользует стиль выше. */
.status-pending { background: #fdecea; color: var(--error); }
.status-approved { background: #e5f6ee; color: var(--success); }
/* Уровни журнала ошибок — /admin/logs.php, см. app/Log.php */
.log-error { background: #fdecea; color: var(--error); }
.log-warning { background: #fff1e6; color: var(--accent); }
.log-info { background: #e6eef5; color: var(--brand); }
.log-debug { background: #eef0f2; color: var(--ink-soft); }
.admin-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.admin-form-grid .full { grid-column: 1 / -1; }
.admin-form-grid label { display: flex; flex-direction: column; gap: 6px; font-weight: 600; font-size: .85rem; }
.admin-form-grid input, .admin-form-grid select, .admin-form-grid textarea {
  padding: 9px 10px; border: 1px solid var(--line); border-radius: 6px; font-family: inherit; font-size: .92rem;
}
/* Чекбоксы "Города показа" (admin/container_edit.php) — условия показа
   контейнера в городе, список динамический (CityRepo::all()), поэтому
   просто плотная адаптивная сетка, а не фиксированное число колонок. */
.admin-city-checkboxes {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 6px 12px;
  max-height: 260px; overflow-y: auto; padding: 12px; border: 1px solid var(--line); border-radius: 6px; margin-bottom: 20px;
}
.admin-city-checkboxes label { display: flex; flex-direction: row; align-items: center; gap: 6px; font-weight: 400; font-size: .88rem; }
.admin-city-checkboxes input { width: auto; }

.admin-login-box { max-width: 380px; margin: 90px auto; background: #fff; padding: 32px; border-radius: var(--radius); border: 1px solid var(--line); }
.admin-toolbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px; flex-wrap: wrap; gap: 12px; }
.stat-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 24px; }
.stat-box { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 18px; text-align: center; }
.stat-box .num { font-size: 1.8rem; font-weight: 800; color: var(--brand-dark); display: block; }
.stat-box .label { color: var(--ink-soft); font-size: .85rem; }

/* ===== Калькулятор подбора контейнера (промо-баннер) ===== */
.calc-promo {
  background: linear-gradient(135deg, var(--brand) 0%, var(--brand-dark) 100%);
  border-radius: var(--radius); color: #fff; padding: 30px 32px;
  display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap;
}
.calc-promo-text h2 { color: #fff; font-size: 1.35rem; margin-bottom: 6px; }
.calc-promo-text p { color: #cfe0ee; margin: 0; max-width: 52ch; }
.calc-promo .btn-primary { flex-shrink: 0; }
/* Блок-обёртка баннера там, где вокруг него нет других отступов (страница контейнера) */
.calc-promo-block { margin: 40px 0; }
/* Узкий вариант — для сайдбара каталога (под фильтрами, ширина колонки ~260px) */
.calc-promo--compact {
  flex-direction: column; align-items: flex-start; text-align: left;
  padding: 18px; gap: 12px; margin-top: 20px;
}
.calc-promo--compact .calc-promo-text h2 { font-size: 1rem; }
.calc-promo--compact .calc-promo-text p { font-size: .82rem; max-width: none; }
.calc-promo--compact .btn { width: 100%; }
.calc-section { padding-top: 40px; }
.calc-head { max-width: 60ch; margin-bottom: 28px; }
.calc-head h1 { color: var(--brand-dark); }
.calc-lead { color: var(--ink-soft); }
.calc-restart { display: inline-block; color: var(--brand); font-weight: 600; margin-bottom: 18px; }
.calc-restart:hover { color: var(--accent); }

.calc-quiz { max-width: 720px; background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 28px; box-shadow: var(--shadow); }
.calc-progress { display: flex; align-items: center; gap: 14px; margin-bottom: 22px; }
.calc-progress-step { font-size: .82rem; font-weight: 700; color: var(--ink-soft); white-space: nowrap; }
.calc-progress-bar { flex: 1; height: 6px; border-radius: 4px; background: var(--line); overflow: hidden; }
.calc-progress-bar span { display: block; height: 100%; background: var(--accent); border-radius: 4px; transition: width .2s ease; width: 25%; }

.calc-step-title { font-size: 1.25rem; color: var(--brand-dark); margin-bottom: 6px; }
.calc-step-hint { color: var(--ink-soft); font-size: .9rem; margin-bottom: 18px; }

.calc-options { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; margin-bottom: 6px; }
.calc-option {
  display: flex; align-items: flex-start; gap: 12px; text-align: left;
  background: #fff; border: 2px solid var(--line); border-radius: var(--radius);
  padding: 14px 16px; cursor: pointer; font-family: inherit; transition: border-color .15s, box-shadow .15s;
}
.calc-option:hover { border-color: var(--brand); }
.calc-option.is-selected { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(255, 89, 0, .12); }
.calc-option-icon { font-size: 1.5rem; line-height: 1; flex-shrink: 0; }
.calc-option-body { display: flex; flex-direction: column; gap: 3px; }
.calc-option-title { font-weight: 700; color: var(--ink); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.calc-option-desc { font-size: .85rem; color: var(--ink-soft); }
.calc-badge { font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .02em; color: var(--success); background: #e5f6ee; padding: 2px 8px; border-radius: 20px; }

.calc-actions { display: flex; align-items: center; justify-content: flex-end; gap: 10px; margin-top: 18px; }
.calc-actions-back-only { justify-content: flex-start; margin-top: 22px; }
.calc-back { padding-left: 0; }
.calc-budget-row { margin-bottom: 6px; }
.calc-budget-input {
  width: 100%; max-width: 280px; padding: 12px 14px; border: 1px solid var(--line); border-radius: 8px;
  font-family: inherit; font-size: 1rem;
}

.calc-result h1 { color: var(--brand-dark); }
.calc-reason { color: var(--ink-soft); max-width: 68ch; margin-bottom: 24px; }
.calc-more { margin-top: 20px; }
.calc-order { max-width: 480px; margin-top: 36px; }

/* Квиз-блок на главной — полноширинная выделенная секция (иначе визуально
   сливается с обычной белой/фоновой секцией "Популярные предложения" над ней) */
.calc-home-section {
  background: linear-gradient(135deg, #eaf1f8 0%, #dbe7f1 100%);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 64px 0;
  scroll-margin-top: 90px; /* чтобы sticky-шапка не перекрывала заголовок при переходе по якорю #calc */
}
.calc-home-section .calc-head { max-width: 640px; margin: 0 auto 28px; text-align: center; }
.calc-home-section .calc-quiz { max-width: none; }

/* ===== Защита от горизонтального скролла на очень узких экранах =====
   Пользователь заметил горизонтальный скролл на разрешении 350px
   (сайт-каталог с сайдбаром фильтров, ниже 640px — этого не было у
   reefer-containers, там каталог сверстан на flex-column, а не на grid,
   см. .catalog-layout ниже — грид больше подвержен этому классу багов).
   Причина везде одна и та же: у грид-трека `1fr` (как и у флекс-айтема с
   flex-shrink) браузер по умолчанию не даёт ему сжаться уже собственного
   min-content ("automatic minimum size" в спеке Grid/Flexbox), потому что
   у CSS-свойства min-width при display:grid/flex-item ЗНАЧЕНИЕ ПО
   УМОЛЧАНИЮ — не 0, а auto (= "не уже, чем требует контент"). Обычно
   этого не видно — контента с запасом хватает всем, — но на очень узких
   экранах (иномарки вроде 320-360px) содержимое каталога (сайдбар
   .filters + сама плитка .cards-grid + панель .catalog-toolbar с
   выпадающим списком сортировки, плюс блок "Типы контейнеров" —
   .types-grid) в сумме требовало больше места, чем есть у .container, и
   грид/флекс-контейнеры вместо того, чтобы сжаться, раздвигали сами себя
   (а с ними и body) — отсюда и скролл. min-width: 0 на всех
   грид/флекс-айтемах ниже разрешает им сжиматься нормально: тексту внутри
   и так есть куда переноситься, фильтры и так уже адаптивны (см. media
   @max-width:980px/640px ниже) — сжатие только убирает лишний "распор".
   <select> (нативный form-control) — частный случай: min-width: 0 у
   родителей на него не действует, браузер всё равно меряет его по
   содержимому <option> — нужно min-width: 0 на САМОМ select. */
.catalog-layout, .filters, .filters-form, .catalog-results,
.cards-grid, .card, .card-body, .card-footer, .card-price, .card-title,
.types-grid, .type-card,
.catalog-toolbar, .sort-form, .view-toggle {
  min-width: 0;
}
.sort-form select {
  min-width: 0;
}

/* ===== Responsive ===== */
@media (max-width: 980px) {
  .hero-inner { grid-template-columns: 1fr; }
  .hero-art { order: -1; max-width: 320px; margin: 0 auto; }
  .types-grid { grid-template-columns: repeat(3, 1fr); }
  .cards-grid { grid-template-columns: repeat(2, 1fr); }
  .steps-grid { grid-template-columns: repeat(2, 1fr); }
  .advantages-grid { grid-template-columns: repeat(2, 1fr); }
  .hub-cities-grid { grid-template-columns: repeat(4, 1fr); }
  .catalog-layout { grid-template-columns: 1fr; }
  .filters { position: static; }
  .container-detail-layout { grid-template-columns: 1fr; }
  .container-secondary-layout { grid-template-columns: 1fr; }
  .contacts-layout { grid-template-columns: 1fr; }
  .footer-inner { grid-template-columns: 1fr 1fr; }
  .stat-row { grid-template-columns: repeat(2, 1fr); }
  .calc-options { grid-template-columns: 1fr; }
}

@media (max-width: 640px) {
  .main-nav, .header-contacts .header-phone, .header-contacts > .btn-primary { display: none; }
  .logo { font-size: 1rem; min-width: 0; }
  .logo-icon, .logo-icon img { flex-shrink: 0; width: 26px; height: 26px; }
  .logo-text { white-space: normal; line-height: 1.15; min-width: 0; }
  .header-contacts { gap: 8px; }
  .city-switcher-btn span { max-width: 80px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .city-switcher-panel { width: 220px; right: -10px; }
  .nav-toggle { display: flex; flex-shrink: 0; }
  .main-nav.open { display: flex; position: absolute; top: 72px; left: 0; right: 0; background: #fff; flex-direction: column; padding: 16px 20px; border-bottom: 1px solid var(--line); gap: 12px; }
  /* Показываем блок "Позвонить"/"Оставить заявку" только когда мобильное
     меню реально открыто (.main-nav.open) — отдельной строкой под
     ссылками, с разделителем сверху. */
  .main-nav.open .mobile-menu-actions { display: flex; gap: 10px; margin-top: 4px; padding-top: 12px; border-top: 1px solid var(--line); }
  .mobile-menu-action { flex: 1; white-space: nowrap; }
  .hero h1 { font-size: 1.6rem; }
  .types-grid { grid-template-columns: repeat(2, 1fr); }
  .cards-grid { grid-template-columns: 1fr; }
  /* На мобильном центрирование по вертикали не нужно (мало места) — и
     хэндлы, и тела панелей просто прижаты к низу экрана (та же высота
     bottom: 90px у обоих, чтобы тело открывалось вровень со своим хэндлом);
     сбрасываем translateY(-50%) из базовых правил — иначе bottom-
     позиционирование съедет вверх. */
  .side-panels { top: auto; bottom: 90px; transform: none; }
  .side-picks-body, .side-favorites-body { top: auto; bottom: 90px; transform: translateX(120%); }
  .side-picks-body:not(.is-collapsed), .side-favorites-body:not(.is-collapsed) { transform: translateX(0); }
  .side-picks-body { width: 130px; max-height: 50vh; gap: 8px; padding: 8px; }
  .side-pick-title { font-size: .76rem; padding-top: 6px; }
  .side-pick-price { font-size: .82rem; padding: 2px 8px 8px; }
  .side-favorites-body { width: 220px; max-height: 50vh; padding: 10px; }
  /* Сдвиг блока .side-panels на мобильном отдельно не задаём — JS сам
     берёт фактическую ширину открытого тела (оно здесь уже 130px/220px,
     см. выше) через offsetWidth, см. докблок .side-panels в базовых
     правилах выше. */
  .steps-grid { grid-template-columns: 1fr; }
  .advantages-grid { grid-template-columns: 1fr; }
  .hub-cities-grid { grid-template-columns: repeat(2, 1fr); }
  .catalog-results.view-list .card-image-wrap { flex: 0 0 56px; width: 56px; height: 56px; }
  .footer-inner { grid-template-columns: 1fr; }
  .footer-bottom { flex-direction: column; }
  .admin-form-grid { grid-template-columns: 1fr; }
  .stat-row { grid-template-columns: 1fr 1fr; }
  .calc-promo { flex-direction: column; text-align: center; }
  .calc-promo-text p { max-width: none; }
  .calc-promo--compact { text-align: left; }
  .calc-quiz { padding: 20px; }
}

/* Пользователь заметил, что на узких экранах (шел скриншот на телефоне) лого
   "КОНТЕЙНЕР-ТОРГ" перекрывается переключателем города. Причина: в блоке
   @max-width:640px выше .logo/.logo-text намеренно сжимаются (min-width: 0),
   чтобы название переносилось на 2 строки по слову — но у самого длинного
   "слова" ("КОНТЕЙНЕР-", т.к. в SITE_NAME_PART1 дефис — часть названия, а не
   разделитель для переноса; настоящих пробелов внутри текста нет вообще, см.
   header.php/config.php) есть свой неснижаемый минимум ширины — а
   .header-contacts (город) при этом остаётся зафиксирован по своему
   min-content (никакого min-width:0 у него нет) и вообще не сжимается. В
   сумме на экранах ýже ~375px это НЕ помещается в ширину (логотип, город и
   кнопка-гамбургер), и раз min-width:0 у лого не даёт вёрстке честно
   переполниться (со скроллом, который был бы виден), а .header-contacts не
   уступает ни пикселя — лишнее просто наезжает текстом поверх соседа. Чинить
   тем же самым способом, что и общий горизонтальный скролл на 350px
   (safety-net overflow-x:hidden) здесь нельзя — оно бы просто утащило
   кнопку-гамбургер за край экрана, а не показало всё аккуратно.
   Настоящее решение — снять нагрузку с города: ниже 400px переключатель
   города превращается в маленькую иконку без текста (просто булавка +
   стрелочка, без названия города — сам город и так виден на странице, а
   после клика открывается панель со списком/поиском). Освободившегося места
   с лихвой хватает, чтобы вернуть лого его настоящий минимум (min-width:
   auto вместо 0 — слово "КОНТЕЙНЕР-" тогда не сжимается ниже своей ширины и
   не наезжает на город). Заодно чуть уменьшен gap в .header-inner (24px ->
   12px) и паддинг самой кнопки-переключателя — просто чтобы было немного
   комфортнее по краям, не впритык. Проверено подряд на всём диапазоне
   280-640px (с шагом 5px) — ни оверлапа, ни горизонтального скролла. */
@media (max-width: 400px) {
  .header-inner { gap: 12px; }
  .logo, .logo-text { min-width: auto; }
  .city-switcher-btn span { display: none; }
  .city-switcher-btn { padding: 8px 10px; }
}

/* Квиз на главной теперь во всю ширину контейнера — на широких экранах
   вариантам ответов просторно, есть смысл разложить их в 3 колонки вместо 2
   (на ≤980px карточки и так уже в 1 колонку, см. основной медиа-запрос выше). */
@media (min-width: 981px) {
  .calc-home-section .calc-options { grid-template-columns: repeat(3, 1fr); }
}
