:root {
  /* ─── Цвет: бренд ─── */
  --navy: #14213D;
  --navy-light: #1f3160;
  --amber: #FFB020;
  --amber-dark: #d99414;
  --bg: #f7f8fa;
  --card-bg: #fff;
  --text: #1a1d29;
  --muted: #6b7280;
  --border: #e2e5eb;

  /* ─── Цвет: статусы (тон + мягкая заливка/рамка для плашек и алертов) ───
     Общая система вместо разбросанных по файлам hex-литералов: danger для
     ошибок/недоступности, success для готово/оплачено, warning для
     "на границе" (осталось мало, счёт выставлен), info — нейтральные
     информационные врезки (гео-подсказки, "договор с точкой" и т.п.). */
  --danger: #c0392b;
  --danger-bg: #fdeceb;
  --danger-border: #f6c9c4;
  --success: #1e8e5a;
  --success-bg: #e5f6ee;
  --success-border: #bfe9d3;
  --warning: #92610a;
  --warning-bg: #fff3d9;
  --warning-border: #ffe2a3;
  --info: #2a4d8f;
  --info-bg: #eef4ff;
  --info-border: #cfe0ff;

  /* ─── Форма ─── */
  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 14px;
  --shadow-sm: 0 1px 3px rgba(20, 33, 61, 0.08);
  --shadow-md: 0 6px 18px rgba(20, 33, 61, 0.14);

  /* ─── Типографика: шкала размеров и межстрочный интервал ───
     База — системный шрифт ОС (см. font-family на body), без внешних
     подключений. Шкала используется по всему сайту вместо разрозненных
     rem-значений в отдельных компонентах. */
  --fs-xs: 0.75rem;
  --fs-sm: 0.85rem;
  --fs-base: 0.95rem;
  --fs-md: 1.05rem;
  --fs-lg: 1.2rem;
  --fs-xl: 1.5rem;
  --lh-tight: 1.3;
  --lh-base: 1.5;
  --lh-relaxed: 1.65;
  /* Длина строки для длинных текстовых блоков (правовые документы,
     развёрнутые описания) — за пределами этой ширины глаз теряет строку. */
  --measure: 68ch;

  /* Видимое кольцо фокуса — единое для всего сайта (клавиатурная навигация
     обязана быть видна везде: и на светлом фоне, и на тёмной шапке). */
  --focus-ring: 0 0 0 3px rgba(217, 148, 20, 0.35);
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  background: var(--bg);
  color: var(--text);
}

/* ─── Состояние фокуса: единое и обязательно видимое ───────────────────
   :focus-visible — кольцо появляется при клавиатурной навигации и не
   мешает при клике мышью. Псевдоклассный fallback на голый :focus не
   добавляем: все актуальные браузеры поддерживают :focus-visible, а лишний
   контур на клик выглядел бы шумно. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--amber-dark);
  outline-offset: 2px;
  border-radius: 2px;
}
/* На тёмной шапке amber-dark теряется на navy — берём чистый amber и
   больше отступ, чтобы кольцо не сливалось со значком/текстом. */
header.site-header :focus-visible {
  outline-color: var(--amber);
  outline-offset: 3px;
}

a { color: var(--navy); text-decoration-thickness: from-font; }
a:hover { color: var(--amber-dark); }

header.site-header {
  background: var(--navy);
  color: #fff;
  padding: 0 1.5rem;
}

.header-inner {
  max-width: 1100px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 60px;
}

.brand {
  color: #fff;
  text-decoration: none;
  font-weight: 700;
  font-size: 1.15rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.brand-mark {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 3px solid var(--amber);
  position: relative;
  flex: none;
}
.brand-mark::before, .brand-mark::after {
  content: "";
  position: absolute;
  background: var(--amber);
}
.brand-mark::before { left: 50%; top: -2px; bottom: -2px; width: 3px; transform: translateX(-50%); }
.brand-mark::after { top: 50%; left: -2px; right: -2px; height: 3px; transform: translateY(-50%); }

nav.site-nav {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  font-size: 0.92rem;
}
/* :not(.btn) — иначе кнопка "Регистрация" (.btn.btn-primary.btn-amber в
   шапке для гостя) теряла фон/паддинг/рамку от этого сброса: правило ниже
   специфичнее .btn-primary (nav.site-nav + элемент против одного класса),
   и побеждало в каскаде — кнопка становилась текстом того же цвета, что и
   фон шапки, то есть визуально исчезала. */
nav.site-nav a:not(.btn), nav.site-nav button:not(.btn) {
  color: #cbd5e1;
  text-decoration: none;
  background: none;
  border: none;
  font: inherit;
  cursor: pointer;
  padding: 0;
}
nav.site-nav a:not(.btn):hover, nav.site-nav button:not(.btn):hover { color: #fff; }
nav.site-nav .btn-amber { color: var(--navy); }

main {
  max-width: 1100px;
  margin: 0 auto;
  padding: 1.75rem 1.5rem 4rem;
}

h1, h2, h3, h4 { line-height: var(--lh-tight); font-weight: 700; color: var(--text); }
h1 { font-size: var(--fs-xl); margin: 0 0 1rem; }
h2 { font-size: var(--fs-lg); margin: 0 0 0.75rem; }
h3 { font-size: var(--fs-md); margin: 1.1rem 0 0.5rem; }
h4 { font-size: var(--fs-base); margin: 0.9rem 0 0.4rem; }
p { line-height: var(--lh-base); }

.card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.1rem 1.25rem;
  margin-bottom: 1rem;
}

.grid-form {
  display: grid;
  gap: 0.9rem;
  max-width: 480px;
}

label { display: block; font-size: var(--fs-sm); font-weight: 600; color: var(--text); margin-bottom: 0.35rem; }
/* Подпись у чекбокса/группы полей выглядит иначе, чем подпись обычного
   поля — не нужен лишний вес, это не заголовок поля. */
.checkbox-row label, .checkbox-group label { font-weight: 400; color: var(--text); }

input, select, textarea {
  width: 100%;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-base);
  font-family: inherit;
  line-height: var(--lh-base);
  background: var(--card-bg);
  color: var(--text);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
input::placeholder, textarea::placeholder { color: #9aa1b1; }
input:hover, select:hover, textarea:hover { border-color: #c7cdda; }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--amber-dark);
  box-shadow: var(--focus-ring);
}
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: none; /* используем box-shadow-кольцо выше вместо outline у полей ввода */
}
input:disabled, select:disabled, textarea:disabled {
  background: var(--bg);
  color: var(--muted);
  cursor: not-allowed;
  opacity: 0.85;
}
input[readonly] { background: var(--bg); }
/* Поле с ошибкой (класс ставит JS-валидация, если она есть на странице) —
   готовый крючок, чтобы не собирать состояние заново. */
input.is-invalid, select.is-invalid, textarea.is-invalid {
  border-color: var(--danger);
}
input.is-invalid:focus, select.is-invalid:focus, textarea.is-invalid:focus {
  box-shadow: 0 0 0 3px rgba(192, 57, 43, 0.18);
}

/* Чекбоксы/радио — сбрасываем «полевой» вид, который им иначе достаётся от
   правила `input {...}` выше (растягивало квадратик на 100% ширины формы).
   Специфичность type-селектора выше обычного `input`, поэтому порядок
   правил тут не важен. */
input[type="checkbox"], input[type="radio"] {
  width: 1.05rem;
  height: 1.05rem;
  flex: none;
  padding: 0;
  border: 1px solid var(--border);
  accent-color: var(--amber-dark);
  cursor: pointer;
  vertical-align: middle;
}
input[type="radio"] { border-radius: 50%; }

.checkbox-row { display: flex; align-items: center; gap: 0.5rem; }
.checkbox-row input { width: 1.05rem; }
.checkbox-row label { margin-bottom: 0; cursor: pointer; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.6rem 1.15rem;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  font: inherit;
  font-size: var(--fs-base);
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
  text-decoration: none;
  text-align: center;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease, transform 0.05s ease;
}
.btn-primary { background: var(--amber); color: var(--navy); }
.btn-primary:hover { background: var(--amber-dark); }
.btn-primary:active { background: var(--amber-dark); transform: translateY(1px); }
.btn-outline { background: transparent; border-color: var(--navy); color: var(--navy); }
.btn-outline:hover { background: var(--navy); color: #fff; }
.btn-outline:active { transform: translateY(1px); }
.btn-danger { background: #fff; border-color: var(--danger); color: var(--danger); }
.btn-danger:hover { background: var(--danger-bg); }
.btn-sm { padding: 0.35rem 0.75rem; font-size: var(--fs-sm); }
.btn:disabled,
.btn:disabled:hover {
  background: var(--bg);
  border-color: var(--border);
  color: var(--muted);
  opacity: 1;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}
/* Кнопка в состоянии отправки/загрузки — вешается классом на существующую
   кнопку (без изменения разметки): текст остаётся читаемым, крутилка не
   требует доп. элемента в DOM — рисуется на псевдоэлементе. */
.btn.is-loading {
  color: transparent !important;
  pointer-events: none;
  position: relative;
}
.btn.is-loading::after {
  content: "";
  position: absolute;
  width: 1em;
  height: 1em;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-right-color: transparent;
  color: var(--navy);
  animation: btn-spin 0.6s linear infinite;
}
.btn-outline.is-loading::after, .btn-danger.is-loading::after { color: var(--navy); }
@keyframes btn-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .btn.is-loading::after { animation-duration: 1.4s; }
}
.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  flex: none;
}
.btn-icon svg { width: 16px; height: 16px; }
.row-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }

/* Превью адреса на карте (блок 28) — некликабельная картинка, только
   визуальное подтверждение "туда ли указали". */
.address-row { display: flex; gap: 0.75rem; align-items: flex-end; flex-wrap: wrap; }
/* position: relative обязателен: .address-suggestions позиционируется
   absolute c top:100% и без него отсчитывается от всей страницы, из-за чего
   выпадающий список подсказок уезжал за нижнюю границу экрана. */
.address-input-wrap { position: relative; flex: 1 1 200px; min-width: 200px; }
.map-preview {
  width: 160px;
  height: 110px;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--border, #e2e5eb);
  background: #f3f4f6;
  flex: none;
}
.map-preview img { width: 100%; height: 100%; object-fit: cover; display: block; }
.map-preview-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.72rem;
  text-align: center;
  padding: 0.4rem;
}

/* Карта нескольких точек в результатах поиска (только для авторизованных —
   см. public/js/catalog.js: updateResultsMap). Всплывающая карточка точки
   по клику на метку — см. .map-point-popup ниже. */
#results-map {
  width: 100%;
  height: 320px;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--border, #e2e5eb);
  margin-bottom: 1rem;
}

/* Метка пользователя и метка адреса поиска на карте результатов (блок 27
   BACKLOG.md) — визуально отличны от стандартных синих маркеров MapLibre у
   точек продавцов (см. updateResultsMap в public/js/catalog.js: элемент
   маркера подменяется на этот div, а не CSS поверх стандартного). Обычный
   круг с иконкой человечка — своя метка (map-marker-own), флажок — метка
   выбранного адреса поиска, когда он отличается от своего местоположения
   (map-marker-anchor, п.2 задачи). */
.map-marker {
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 2px solid #fff;
  box-shadow: var(--shadow-sm);
  color: #fff;
  cursor: pointer;
}
.map-marker svg { width: 18px; height: 18px; }
.map-marker-own { background: var(--info); }
.map-marker-anchor { background: var(--amber-dark); border-radius: 8px 8px 8px 2px; }

.results-map-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  align-items: center;
  font-size: 0.78rem;
  color: var(--muted);
  margin: -0.5rem 0 1rem;
}
.results-map-legend[hidden] { display: none; }
.results-map-legend-item { display: inline-flex; align-items: center; gap: 0.35rem; }
.results-map-legend-dot {
  width: 12px; height: 12px; border-radius: 50%; flex: none; display: inline-block;
}
.results-map-legend-dot-own { background: var(--info); }
.results-map-legend-dot-anchor { background: var(--amber-dark); border-radius: 3px 3px 3px 0; }
.results-map-legend-dot-point { background: #3887be; } /* дефолтный синий маркер MapLibre */

/* Всплывающая карточка точки при клике на метку карты (задача владельца
   14.09.2026, public/js/catalog.js: buildPointPopupHtml) — карта видна
   только вошедшему, поэтому карточка всегда содержит название/адрес/график
   и кнопку маршрута, без телефона. */
.map-point-popup { font-size: 0.85rem; line-height: 1.45; min-width: 170px; }
.map-point-popup-title { font-weight: 600; margin-bottom: 0.15rem; }
.map-point-popup-type { color: var(--muted); }
.map-point-popup-address, .map-point-popup-hours {
  margin-top: 0.2rem;
}
/* Кнопка «Проложить маршрут» переиспользована из public/js/point-contacts.js
   (.point-contacts-route) — здесь только чуть меньше отступ, чем в общем
   блоке контактов, карточка на карте компактнее. */
.map-point-popup .point-contacts-route { margin-top: 0.4rem; }

/* Чекбокс «Показать ближайшие первыми» отключается (без гео-центра считать
   расстояние не от чего — территория поиска «РФ», см. catalog.js). */
.checkbox-row-nearest:has(input:disabled) { opacity: 0.55; cursor: not-allowed; }
.checkbox-row-nearest:has(input:disabled) label,
.checkbox-row-nearest:has(input:disabled) span { cursor: not-allowed; }

/* Расстояние до точки в карточке результата (блок 27 BACKLOG.md, п.4). */
.result-distance { white-space: nowrap; }

/* Адрес точки в карточке результата — только вошедшему, рядом с
   расстоянием (решение владельца 14.09.2026, см. public/js/catalog.js:
   renderResults). Приглушённым цветом — вспомогательная деталь строки,
   не такая заметная, как цена или название. */
.result-address { color: var(--muted); }

/* Автоподсказка адреса (DaData) в форме точки. */
.address-suggestions {
  position: absolute;
  z-index: 20;
  left: 0;
  right: 0;
  top: 100%;
  margin-top: 2px;
  background: var(--card-bg, #fff);
  border: 1px solid var(--border, #e2e5eb);
  border-radius: 8px;
  box-shadow: 0 6px 16px rgba(0,0,0,0.08);
  max-height: 220px;
  overflow-y: auto;
}
.address-suggestion-item {
  padding: 0.5rem 0.7rem;
  font-size: 0.88rem;
  cursor: pointer;
}
.address-suggestion-item:hover,
.address-suggestion-item:focus {
  background: var(--bg-hover, #f3f4f6);
}

.search-form { display: flex; flex-direction: column; gap: 0.9rem; }
.search-form-title { margin: 0; font-size: 1.05rem; color: var(--navy); }

.search-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.75rem;
  align-items: start;
}

.search-form-divider { border: none; border-top: 1px solid var(--border); margin: 0; }

.search-form-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  width: fit-content;
  color: var(--navy);
  font-weight: 600;
  font-size: 0.88rem;
  text-decoration: none;
  cursor: pointer;
}
.search-form-toggle:hover { text-decoration: underline; }
.search-form-toggle-chevron { transition: transform 0.15s ease; }
.search-form-toggle[aria-expanded="true"] .search-form-toggle-chevron { transform: rotate(180deg); }

.search-form-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.75rem;
}
.search-sort-row { display: flex; align-items: center; gap: 0.6rem; }
.search-sort-label { font-size: 0.85rem; color: var(--muted); font-weight: 600; }
.search-form-actions { display: flex; gap: 0.5rem; align-items: center; }

.result-list { display: grid; gap: 0.75rem; margin-top: 1.25rem; }

.result-row {
  display: flex;
  gap: 1rem;
  align-items: center;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.9rem 1.1rem;
  text-decoration: none;
  color: inherit;
}
.result-row:hover { border-color: var(--amber); }
.result-photo {
  width: 56px; height: 56px; border-radius: 8px; background: var(--bg);
  display: flex; align-items: center; justify-content: center; flex: none;
  color: var(--muted); font-size: 0.7rem; overflow: hidden;
}
.result-photo img { width: 100%; height: 100%; object-fit: cover; }
/* Иллюстрация категории вместо фото (public/js/catalog.js, public/js/
   product.js) — задача владельца 2026-09-12, design/brand/category-icons.md.
   В плитке результатов под саму иллюстрацию нужно место для обязательной
   подписи (см. ниже) — фиксированная квадратная .result-photo для этого
   случая раздвигается в колонку чуть шире, а картинка внутри уменьшается,
   чтобы подпись уместилась без переноса строки результата. */
.result-photo-illustration {
  width: 68px; height: auto; flex-direction: column; gap: 0.15rem;
  padding: 0.3rem 0.2rem; background: transparent;
}
.result-photo-illustration img.category-illustration { width: 40px; height: 40px; object-fit: contain; }
.result-main { flex: 1; min-width: 0; }
.result-title { font-weight: 600; }
.result-meta { color: var(--muted); font-size: 0.85rem; margin-top: 0.15rem; }
.result-price { font-weight: 700; color: var(--navy); font-size: 1.05rem; white-space: nowrap; }

/* Подпись под иллюстрацией категории (не под настоящим фото товара) —
   обязательна по закону о защите прав потребителей: без неё покупатель
   может принять схему за фото конкретной детали (задача владельца
   2026-09-12, design/brand/category-icons.md). Полный текст — в карточке
   товара (public/js/product.js), короткий вариант — в плитке результатов
   поиска (public/js/catalog.js), где места мало. */
.category-illustration-caption { font-size: 0.78em; color: var(--muted); margin-top: 0.25rem; max-width: 240px; }
.category-illustration-caption-compact { font-size: 0.6rem; line-height: 1.15; text-align: center; margin-top: 0; }

/* Миниатюра в таблице "Прайс работ" карточки товара (public/js/product.js,
   loadPointServices) — задача владельца 2026-09-12: своё фото услуги или,
   при его отсутствии, иллюстрация категории услуги (той же природы, что
   .category-illustration выше, но без отдельной строки-подписи — в таблице
   на неё нет места без рассогласования высоты строк, подпись даётся через
   title-подсказку на самой миниатюре). */
.service-name-cell { display: flex; gap: 0.55rem; align-items: flex-start; }
.service-thumb {
  width: 40px; height: 40px; flex: none; object-fit: cover; border-radius: 6px;
}
/* Иллюстрация категории (в отличие от настоящего фото услуги) — уже готовая
   квадратная SVG-плитка со своей подложкой (см. design/brand/category-icons.md),
   cover обрезал бы её край — здесь нужен contain. */
.service-thumb.category-illustration { object-fit: contain; }

/* ─── Миниатюра 40×40 в списках + всплывающее окно просмотра (public/js/
   lightbox.js) — задача владельца 2026-09-12: корзина, «Мои запросы»,
   «Мои заказы»/карточка заказа, кабинет продавца. Кнопка, а не голый <img>
   — миниатюра должна быть доступна с клавиатуры (Tab + Enter/Space), сам
   <img> фокус не получает. */
.thumb-trigger {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; flex: none; padding: 0; border: none;
  background: var(--bg); border-radius: var(--radius-sm); cursor: zoom-in;
  overflow: hidden;
}
.thumb-trigger:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }
.thumb-40 { width: 100%; height: 100%; object-fit: cover; }
/* Иллюстрация категории — готовая SVG-плитка со своей подложкой, cover
   обрезал бы её край (та же причина, что у .service-thumb выше). */
.thumb-40.thumb-illustration { object-fit: contain; padding: 3px; }

/* Затемнённый фон + диалог просмотра — создаётся один раз лениво (см.
   lightbox.js: buildOverlay) и переиспользуется для любой миниатюры на
   странице. is-open переключается через classList, а не через [hidden]:
   overlay нужен display:flex для центрирования, и завязывать это на
   специфичность атрибутного селектора не нужно — проще держать display:none
   базовым состоянием класса. */
.lightbox-overlay {
  display: none; position: fixed; inset: 0; z-index: 1000;
  background: rgba(20, 33, 61, 0.72);
  align-items: center; justify-content: center; padding: 1.5rem;
}
.lightbox-overlay.is-open { display: flex; }
.lightbox-dialog {
  position: relative; background: var(--card-bg); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md); padding: 2.5rem 1.25rem 1.25rem;
  max-width: min(90vw, 640px); max-height: 90vh;
  display: flex; flex-direction: column; align-items: center; gap: 0.6rem;
}
.lightbox-dialog:focus { outline: none; }
.lightbox-image { max-width: 100%; max-height: 70vh; object-fit: contain; border-radius: var(--radius-sm); }
.lightbox-caption { font-size: 0.85em; text-align: center; max-width: 32rem; }
.lightbox-close {
  position: absolute; top: 0.5rem; right: 0.5rem; width: 2rem; height: 2rem;
  border: 1px solid var(--border); background: var(--card-bg); border-radius: 999px;
  font-size: 1.3rem; line-height: 1; color: var(--text); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.lightbox-close:hover { border-color: var(--amber); }
.lightbox-close:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

.badge {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  background: var(--bg);
  color: var(--muted);
  border: 1px solid var(--border);
}
.badge-pending { color: var(--warning); background: var(--warning-bg); border-color: var(--warning-border); }
.badge-seller_confirmed { color: var(--success); background: var(--success-bg); border-color: var(--success-border); }
.badge-declined, .badge-expired { color: var(--danger); background: var(--danger-bg); border-color: var(--danger-border); }
.badge-completed { color: var(--info); background: var(--info-bg); border-color: var(--info-border); }

/* Нештатная (тюнинговая) деталь — этап 8 плана каталога. Предупреждение
   должно быть ЗАМЕТНЫМ (решение владельца 14.09.2026), поэтому у него
   предупреждающий цвет, а не серый цвет обычного бейджа. */
.badge-warning { color: var(--warning); background: var(--warning-bg); border-color: var(--warning-border); }
.result-aftermarket-note {
  margin: 0.15rem 0 0.2rem;
  font-size: 0.78rem;
  color: var(--warning);
}
.aftermarket-warning {
  margin: 0.6rem 0;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--warning-border);
  border-radius: 8px;
  background: var(--warning-bg);
  color: var(--warning);
  font-size: 0.86rem;
}
.aftermarket-warning strong { display: block; margin-bottom: 0.2rem; }

/* Характеристики товара в форме продавца — этап 6 плана каталога.
   Обязательные стоят отдельной группой выше необязательных: продавец
   должен видеть, что от него требуется, не разбирая звёздочки в списке. */
.product-attrs:empty { display: none; }
.product-attr-title { margin: 0 0 0.5rem; font-size: 0.95rem; color: var(--navy); }
.product-attr-group {
  margin-bottom: 0.9rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
}
.product-attr-group-title { margin: 0 0 0.25rem; font-size: 0.85rem; color: var(--text); }
.product-attr-field + .product-attr-field { margin-top: 0.6rem; }

/* Фильтры по характеристикам категории — этап 6 плана каталога. Состав
   панели задаёт справочник, поэтому сетка авторазмерная: полей может быть
   одно (диаметр диска) и может быть шесть (масла). */
.search-category-filters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 0.75rem;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
}
.category-filter-values {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem 0.9rem;
}

/* График работы (фильтр «Учесть график работы» + кабинет продавца) */
.badge-open-hours { color: var(--success); background: var(--success-bg); border-color: var(--success-border); }
.badge-closed-now { color: var(--danger); background: var(--danger-bg); border-color: var(--danger-border); }
.result-row-unavailable { opacity: 0.6; }
.schedule-badge { margin-left: 0.3rem; }

.table { width: 100%; max-width: 100%; border-collapse: collapse; }
.table th, .table td { text-align: left; padding: 0.6rem 0.65rem; border-bottom: 1px solid var(--border); font-size: var(--fs-base); vertical-align: middle; }
.table th { color: var(--muted); font-weight: 600; font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.02em; }
.table tbody tr:hover { background: var(--bg); }

/* .error/.success — то же самое, что .error-box/.success-box. Двадцать пять
   мест в трёх файлах писали сообщения человеку этими короткими именами, для
   которых правил не было вовсе: отказ показывался обычным серым текстом,
   неотличимым от подписи рядом, и человек его попросту не замечал. Дешевле
   и надёжнее объявить имена рабочими здесь, чем править каждое место и
   ловить следующее такое же завтра. */
.error-box, .success-box, .error, .success {
  padding: 0.65rem 0.85rem;
  border-radius: var(--radius-sm);
  margin: 0.75rem 0;
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  border: 1px solid;
}
.error-box, .error { background: var(--danger-bg); border-color: var(--danger-border); color: var(--danger); }
.success-box, .success { background: var(--success-bg); border-color: var(--success-border); color: var(--success); }

.impersonation-bar { background: var(--amber); color: var(--navy); padding: 0.5rem 1rem; text-align: center; font-size: var(--fs-sm); display: flex; gap: 0.75rem; align-items: center; justify-content: center; flex-wrap: wrap; }
.impersonation-bar .btn { border-color: var(--navy); color: var(--navy); }
.impersonation-bar .btn.btn-outline:hover { background: var(--navy); color: #fff; }

/* ─── Пагинация ───────────────────────────────────────────────────────────
   Панель видна всегда, даже когда список умещается на одну страницу — тогда
   в ней остаётся только селектор размера страницы и "Всего N" (см.
   pagination.js). Оборачиваем в лёгкую карточку с фоном, чтобы в этом
   "коротком" состоянии панель не выглядела повисшей в воздухе строкой
   текста без общего с остальным сайтом визуального веса. */
/* Контекст для @container ниже — задаётся на обёртке, которую рисует сам
   pagination.js (см. комментарий в renderPagination), а не на разметке
   страницы. */
.pagination-bar-frame {
  container-type: inline-size;
  container-name: pagination-bar;
}

.pagination-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem 1rem;
  margin: 0.9rem 0;
  padding: 0.6rem 0.9rem;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.pagination-bar select { margin-left: 0.35rem; }
.pagination-nav { min-height: 1.6rem; display: flex; align-items: center; gap: 0.6rem; }

/* Узкий контейнер — панель стоит в боковой колонке (chats.html,
   seller/dashboard.html: сайдбар со списком переписок,
   minmax(220px,320px)), а не на всю ширину страницы. Запрос идёт по
   ширине САМОГО КОНТЕЙНЕРА панели (container query), а не окна: узкая
   колонка — это узкая колонка независимо от того, насколько широк экран,
   поэтому обычный @media здесь не подходит (дефект 13.09.2026,
   BACKLOG.md #45 — "Показывать по" и "Стр. X из Y" в строке space-between
   переносились и разъезжались по высоте). Ниже 480px переходим на
   вертикальную раскладку: выбор размера страницы сверху, переходы снизу. */
@container pagination-bar (max-width: 480px) {
  .pagination-bar {
    flex-direction: column;
    align-items: stretch;
    gap: 0.5rem;
  }
  .pagination-nav {
    flex-wrap: wrap;
    justify-content: space-between;
  }
}

/* Совсем тесно (реальная ширина колонки на chats.html — от 220px) — стрелки
   и счётчик "Стр. X из Y (всего N)" вместе тоже не помещаются в строку.
   flex-wrap уже переносит их по одному на строку; здесь только центрируем,
   чтобы не липли к левому краю. */
@container pagination-bar (max-width: 260px) {
  .pagination-nav {
    justify-content: center;
    text-align: center;
  }
}

/* ─── Баннер блокировки аккаунта (покупатель/продавец в кабинете) ───────
   Разметка (orders.html, seller/dashboard.html, admin-dashboard.js) задаёт
   инлайново border-color:var(--danger) — насыщенный красный по всей рамке,
   выглядит тревожно для и без того неприятного сообщения. Здесь мы это
   гасим: нейтральная рамка + один акцентный край слева, тёплый (не
   красный) оттенок фона. !important нужен только потому, что переопределяем
   инлайн-стиль в разметке, которую менять нельзя. */
.card[style*="var(--danger"] {
  border-color: var(--border) !important;
  border-left: 4px solid var(--amber-dark) !important;
  background: #fffaf0;
}
.card[style*="var(--danger"] strong {
  display: block;
  margin-bottom: 0.35rem;
  color: var(--navy);
  font-size: var(--fs-md);
}
.card[style*="var(--danger"] p {
  line-height: var(--lh-base);
}

.muted { color: var(--muted); font-size: var(--fs-sm); }
.section { margin-bottom: 2rem; }
.flex-between { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 0.5rem; }

.seller-tabs {
  display: flex;
  gap: 0.35rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 1.5rem;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  /* Подсказка "справа есть ещё вкладки" — мягкая тень-градиент у правого
     края (usability-аудит 2026-09-11, п. 3.1: скроллбар скрыт выше, и без
     подсказки не видно, что список вкладок обрезан — например у админки
     последняя вкладка обрывалась на полуслове). Одобрено владельцем
     2026-09-12. Чистый CSS, без JS и без обработчика скролла — приём
     "scroll shadows": два фоновых слоя с разным background-attachment.
     У слоя-"маски" (background-attachment: local) позиция привязана к
     КОНЦУ прокручиваемого содержимого, а не к видимой области — пока до
     конца списка не докрутили, маска сдвинута за пределы видимой части, и
     под ней виден слой тени (background-attachment: scroll — держится у
     правого края видимой области всегда). Как только докрутили до конца,
     маска встаёт поверх тени цветом страницы (var(--bg)) и скрывает её.
     rgba(247,248,250,…) ниже — это var(--bg) с прозрачностью: значение
     нужно поменять вместе с var(--bg), если тот когда-нибудь изменится. */
  background:
    linear-gradient(to left, var(--bg), rgba(247, 248, 250, 0)) 100% 0 / 28px 100% no-repeat local,
    linear-gradient(to left, rgba(15, 23, 42, 0.16), rgba(15, 23, 42, 0)) 100% 0 / 18px 100% no-repeat scroll;
}
.seller-tabs::-webkit-scrollbar { display: none; }
.seller-tab {
  flex: none;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 0.65rem 0.9rem;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  white-space: nowrap;
}
.seller-tab:hover { color: var(--text); }
.seller-tab.active { color: var(--navy); border-bottom-color: var(--amber); }

/* Вкладки внутри карточки (например "История" покупателя в админке —
   admin-buyer-history-tab-btn) — те же кнопки btn-outline btn-sm, просто
   подсвечивается активная, без отдельной панели вкладок. */
.active-subtab { background: var(--navy); color: #fff; border-color: var(--navy); }

/* ─── Мобильная адаптация ───────────────────────────────────────────────
   Базовые стили выше уже однoколоночные (.grid-form, .search-form auto-fit),
   здесь — то, что не адаптируется само: шапка с навигацией, строки
   результатов поиска, таблицы (кабинет продавца/покупателя). */

.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; margin: 0 -0.1rem; }
.table-wrap .table { min-width: 520px; }

@media (max-width: 700px) {
  .header-inner { height: auto; flex-wrap: wrap; padding: 0.65rem 0; gap: 0.6rem; }
  nav.site-nav {
    width: 100%;
    overflow-x: auto;
    flex-wrap: nowrap;
    gap: 1.1rem;
    padding-bottom: 0.2rem;
    scrollbar-width: none;
  }
  nav.site-nav::-webkit-scrollbar { display: none; }
  nav.site-nav > * { flex: none; white-space: nowrap; }
}

@media (max-width: 480px) {
  main { padding: 1.25rem 1rem 3rem; }
  h1 { font-size: 1.3rem; }
  .card { padding: 0.9rem 1rem; }

  .result-row { flex-wrap: wrap; }
  .result-price { width: 100%; text-align: left; margin-top: 0.35rem; }

  .search-form-footer { flex-direction: column; align-items: stretch; }
  .search-form-footer #search-submit { width: 100%; }
  .search-form-actions { width: 100%; }
  .search-form-actions .btn { flex: 1 1 0; }
}


/* ─── Правовые документы (public/legal/*.html) ──────────────────────────
   Раньше каждая страница носила собственную копию этих правил в локальном
   <style> — почти идентичную, с разбросом по мелочам (0.85rem vs 0.88rem
   и т.п.). Текст документов трогать нельзя, а вот оформление — можно и
   нужно унифицировать; теперь это один источник правды здесь, локальные
   <style>-блоки на страницах documents убраны. Долгий юридический текст
   читают целиком — сюда специально вынесены: ограниченная длина строки
   (--measure), увеличенный межстрочный интервал, отступ между разделами. */
.legal-doc {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.75rem clamp(1.1rem, 4vw, 2.25rem);
  max-width: 880px;
  margin: 0 auto;
}
/* Ограничение ширины — не только у p/li, но и у заголовков: иначе линия
   border-top над h2 тянулась бы на всю ширину карточки (880px), а текст
   под ней обрывался на ~68ch — разделитель визуально "не совпадал" бы с
   колонкой текста. */
.legal-doc h1, .legal-doc h2, .legal-doc h3 { max-width: var(--measure); }
.legal-doc h1 { font-size: 1.4rem; margin-bottom: 0.4rem; }
.legal-doc h2 { font-size: var(--fs-lg); margin-top: 1.75rem; padding-top: 1.1rem; border-top: 1px solid var(--border); }
.legal-doc h2:first-of-type { margin-top: 1.25rem; padding-top: 0; border-top: none; }
.legal-doc h3 { font-size: var(--fs-md); margin-top: 1.25rem; }
.legal-doc .doc-meta { color: var(--muted); font-size: var(--fs-sm); margin: -0.5rem 0 1.25rem; }
.legal-doc blockquote {
  background: var(--bg);
  border: 1px solid var(--border);
  border-left: 3px solid var(--amber-dark);
  padding: 0.85rem 1.1rem;
  border-radius: var(--radius-sm);
  margin: 0 0 1.25rem;
  font-size: var(--fs-base);
  max-width: var(--measure);
}
/* Длина строки ограничена у самого текста (не у контейнера) — так таблицы
   ниже остаются на всю ширину документа и не превращаются в частокол
   переносов. */
.legal-doc p, .legal-doc li { line-height: var(--lh-relaxed); font-size: var(--fs-base); max-width: var(--measure); }
.legal-doc ul, .legal-doc ol { padding-left: 1.4rem; }
.legal-doc li + li { margin-top: 0.35rem; }
.legal-doc hr { border: none; border-top: 1px solid var(--border); margin: 1.5rem 0; }
.legal-doc a { text-underline-offset: 2px; }
/* Находка тестировщика A-13: таблица была одновременно table-layout:fixed
   И max-width:100% — то есть физически не могла стать шире родителя, а
   overflow-wrap:anywhere заставляло переносить любое слово посреди букв,
   как только колонка (на 4-колоночной таблице — не шире ~70px на 375px
   экране) оказывалась ýже слова. Обёртка `<div style="overflow-x:auto">`
   в разметке правовых страниц (её не трогаем) была рабочей всегда — ей
   просто нечему было прокручивать, раз таблица не могла превысить её
   ширину.
   Фикс: min-width задаёт колонкам минимально комфортную ширину (в em —
   от размера шрифта самой таблицы, --fs-base) независимо от узости
   контейнера; на широких экранах width:100% как и раньше растягивает
   таблицу на всю колонку текста. Когда 100% меньше min-width (узкий
   экран), table-layout:fixed делит именно min-width поровну между
   колонками — получаются те самые ~137px на 4-колоночной таблице вместо
   ~70px, и обёртка прокручивает лишнее вбок, не ломая слов. max-width:100%
   убран как раз потому, что раньше отменял всё это (min-width и так
   имеет приоритет над max-width по спецификации, но конфликтующее правило
   рядом только запутывало). */
.legal-table { border-collapse: collapse; width: 100%; min-width: 36em; margin: 0.75rem 0 1.25rem; font-size: var(--fs-base); table-layout: fixed; }
.legal-table th, .legal-table td {
  border: 1px solid var(--border);
  padding: 0.5rem 0.65rem;
  text-align: left;
  vertical-align: top;
  line-height: var(--lh-base);
  /* Подстраховка на случай единичного действительно неразрывного токена
     (длинный URL/идентификатор без пробелов) шире и min-width-колонки —
     обычные слова благодаря min-width выше в этот перенос почти никогда
     не попадают, переносятся по пробелам как в остальном тексте. */
  overflow-wrap: anywhere;
}
.legal-table th { background: var(--bg); font-weight: 600; }

@media (max-width: 480px) {
  .legal-doc { padding: 1.25rem 1rem; }
}

/* Утилита: жёсткое скрытие (переопределяет display:grid/flex и т.п.) */
.hidden-block { display: none !important; }

/* Бейджи-счётчики над пунктами меню (Корзина/Гараж/Мои заказы) */
.nav-item-wrap { position: relative; display: inline-flex; align-items: center; }
.nav-badge {
  display: none;
  align-items: center;
  justify-content: center;
  position: absolute;
  top: -9px;
  right: -12px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--amber);
  color: var(--navy);
  font-size: 0.65rem;
  font-weight: 700;
  line-height: 1;
}

/* Группа чекбоксов (способы оплаты/доставки в форме точки) */
.checkbox-group { display: flex; flex-wrap: wrap; gap: 0.5rem 1.1rem; }
.checkbox-group label { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.88rem; color: var(--text); margin-bottom: 0; cursor: pointer; }
.checkbox-group input { width: auto; }

/* График работы точки (форма точки в кабинете продавца) */
.schedule-editor { display: grid; gap: 0.6rem; padding: 0.75rem; background: var(--bg); border-radius: 8px; }
.schedule-days { display: grid; gap: 0.4rem; transition: opacity 0.15s ease; }
.schedule-day-row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.schedule-day-label { width: 1.8rem; font-weight: 600; font-size: 0.85rem; flex: none; }
.schedule-day-row input[type="time"] { width: auto; }
.schedule-holiday-block { display: grid; gap: 0.4rem; padding-top: 0.4rem; border-top: 1px solid var(--border); }

/* Чат покупатель<->точка (chat-widget.js) */
.chat-messages {
  display: flex; flex-direction: column; gap: 0.5rem;
  max-height: 360px; overflow-y: auto; padding: 0.75rem;
  background: var(--bg); border-radius: 8px; margin-bottom: 0.75rem;
}
.chat-msg { align-self: flex-start; max-width: 80%; }
.chat-msg-own { align-self: flex-end; }
.chat-msg-body {
  background: #fff; border: 1px solid var(--border); border-radius: 10px;
  padding: 0.5rem 0.7rem; font-size: 0.92rem; white-space: pre-wrap; word-break: break-word;
}
.chat-msg-own .chat-msg-body { background: var(--amber); border-color: var(--amber-dark); color: var(--navy); }
.chat-msg-meta { font-size: 0.7rem; color: var(--muted); margin-top: 0.15rem; }
.chat-msg-own .chat-msg-meta { text-align: right; }
.chat-composer { display: flex; gap: 0.5rem; align-items: flex-end; }
.chat-composer textarea {
  flex: 1; resize: vertical; font-family: inherit; padding: 0.5rem 0.7rem;
  border: 1px solid var(--border); border-radius: 6px; font-size: 0.92rem;
}
.chat-thread-list { display: grid; gap: 0.5rem; }
.chat-thread-row {
  display: flex; justify-content: space-between; align-items: center; gap: 0.75rem;
  background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
  padding: 0.75rem 1rem; cursor: pointer; text-align: left; width: 100%; font: inherit; color: inherit;
}
.chat-thread-row:hover { border-color: var(--amber); }
.chat-thread-row.active { border-color: var(--amber); background: #fff9ec; }
.chat-thread-preview { color: var(--muted); font-size: 0.85rem; margin-top: 0.15rem; max-width: 40ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Блок 29 — рекламные блоки (публичный рендер). */
.ad-top-row { display: flex; gap: 0.75rem; margin-bottom: 1.25rem; flex-wrap: wrap; }
.ad-top-row .ad-slot { flex: 1 1 200px; }
.page-with-sides { display: flex; gap: 1rem; align-items: flex-start; }
.page-with-sides .page-main { flex: 1; min-width: 0; }
.ad-side { flex: 0 0 160px; }
.ad-slot { text-align: center; }
.ad-slot img { max-width: 100%; height: auto; display: block; margin: 0 auto; border-radius: 6px; }
.ad-slot a { display: block; }
@media (max-width: 900px) {
  /* align-items:flex-start (нужен в десктопном ряду, чтобы боковые рекламные
     колонки не растягивались на всю высоту .page-main) в колоночном режиме
     превращался в "не растягивать по ширине" — .page-main сжимался до
     ширины содержимого (fit-content) вместо 100% ширины карточки, оставляя
     пустую полосу справа. На мобильном это ЕДИНСТВЕННАЯ колонка, тянуть
     нечего — растягиваем на всю ширину. */
  .page-with-sides { flex-direction: column; align-items: stretch; }
  .ad-side { flex: 0 0 auto; width: 100%; }
}

/* ─── Сортировка: иконка + выпадающее меню (покупатель + продавец) ──────
   Общий визуальный компонент вместо отдельного блока-карточки: иконка в
   правом верхнем углу секции, рядом краткая подпись текущего варианта,
   при клике — выпадающее меню с вариантами и кнопкой-иконкой "очистить". */
.sort-control { position: relative; display: inline-flex; align-items: center; gap: 0.45rem; }
.sort-control-current {
  font-size: 0.82rem;
  color: var(--muted);
  white-space: nowrap;
  max-width: 22ch;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sort-menu {
  position: absolute;
  z-index: 30;
  top: 100%;
  right: 0;
  margin-top: 6px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.14);
  min-width: 250px;
  padding: 0.4rem;
}
.sort-menu-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.15rem 0.4rem 0.4rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.3rem;
}
.sort-menu-title { font-size: 0.78rem; color: var(--muted); font-weight: 600; }
.sort-menu-clear {
  background: none; border: none; cursor: pointer; color: var(--muted);
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; padding: 0; border-radius: 4px;
}
.sort-menu-clear:hover { color: var(--danger); background: var(--bg); }
.sort-menu-clear svg { width: 15px; height: 15px; }
.sort-menu-option {
  display: block; width: 100%; text-align: left; background: none; border: none;
  padding: 0.45rem 0.55rem; border-radius: 6px; cursor: pointer; font-size: 0.88rem; color: var(--text);
}
.sort-menu-option:hover { background: var(--bg); }
.sort-menu-option.active { background: var(--warning-bg); color: var(--amber-dark); font-weight: 600; }

/* ─── Форма поиска покупателя: свёрнутые доп. поля ──────────────────────
   По умолчанию видны только артикул/название + гео-блок (город/точка и
   радиус). Остальные поля (марка/модель/год/бренд/состояние/VIN) скрыты
   за ссылкой "Ещё", появляются под горизонтальной линией. */
.search-form-extra {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 0.6rem;
}
.search-form-extra[hidden] { display: none; }
.search-count-icon { font-weight: 700; }

/* ─── Гео-блок формы поиска (город/область/точный адрес + радиус) ──────*/
.geo-mode-tabs, .condition-tabs { display: flex; gap: 0.35rem; margin-top: 0.45rem; margin-bottom: 0.6rem; flex-wrap: wrap; }
.geo-mode-tab, .condition-tab {
  background: var(--bg); border: 1px solid var(--border); border-radius: 999px;
  padding: 0.25rem 0.7rem; font-size: 0.78rem; cursor: pointer; color: var(--muted);
}
.geo-mode-tab.active, .condition-tab.active { background: var(--navy); color: #fff; border-color: var(--navy); }
.geo-locate-banner {
  display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
  flex-wrap: wrap; background: var(--info-bg); border: 1px solid var(--info-border); border-radius: var(--radius-sm);
  padding: 0.6rem 0.8rem; margin-bottom: 0.75rem; font-size: var(--fs-base);
}
.geo-locate-banner[hidden] { display: none; }

/* ─── Правовые уведомления в разметке (форма заказа/точки/гаража) ───────
   Разметка у них общая, но собрана в public/js/*.js и style.css трогать
   её не может: короткий приглушённый абзац ".muted" с левой амбер-полосой
   (border-left задан инлайново в разметке, см. product.js/cart.js/
   garage.js/seller/dashboard.html). Тут — то, что инлайн НЕ задаёт: фон,
   отступы и типографика самого блока, чтобы он был заметен, но не
   "кричал" на фоне остального текста. Селектор по содержимому style ловит
   именно эти абзацы и не трогает остальные .muted на сайте. */
p.muted[style*="border-left"] {
  background: var(--bg);
  border-top-right-radius: var(--radius-sm);
  border-bottom-right-radius: var(--radius-sm);
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
  padding-right: 0.6rem;
  line-height: var(--lh-base);
}
p.muted[style*="border-left"] a { font-weight: 600; }

/* Значки в шапке — гараж, чаты, уведомления, корзина (BACKLOG.md, блок 3;
   контуры из design/canvas/Main.dc.html). Колокольчик уведомлений (между
   чатами и корзиной) — такая же ссылка-иконка, как и остальные (с
   2026-09-10 открывает /notifications.html, а не выпадающую панель), поэтому
   отдельных стилей под него в этом файле нет — используются общие .nav-icon
   и .nav-badge ниже (см. public/js/api.js notifBellHtml). */
.nav-icon {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #c7cede;
  padding: 0;
  transition: color 0.15s ease;
}
.nav-icon:hover { color: #fff; }
.nav-icon svg { display: block; }

/* Гараж: зелёный, когда машины добавлены; приглушённый, когда пуст.
   Цифры на нём намеренно нет — состояние читается цветом.

   Селектор намеренно включает nav.site-nav: правило сброса навигации выше
   (nav.site-nav a:not(.btn)) специфичнее, чем просто два класса, и
   перебивало цвет — иконка никогда не становилась зелёной, хотя класс
   has-cars проставлялся правильно. Не менять на короткий селектор. */
nav.site-nav a.nav-icon-garage.has-cars { color: #3fbf7f; }
nav.site-nav a.nav-icon-garage.has-cars:hover { color: #5fd39a; }
nav.site-nav a.nav-icon-garage.is-empty { color: #6b7689; }
nav.site-nav a.nav-icon-garage.is-empty:hover { color: #c7cede; }
/* На значке бейдж прижимается ближе, чем на текстовом пункте меню, иначе
   налезает на соседний значок. */
.nav-icon .nav-badge { top: -6px; right: -7px; }

/* ─── Форма регистрации: четыре согласия подряд ─────────────────────────
   Разметка register.html не меняется — используем :has(), чтобы отличить
   обязательные отметки (checked-атрибут required — п. 1.1/1.2 согласия) от
   добровольных (п. 1.3/1.4), не трогая HTML. Обязательные — на светлой
   подложке с акцентом слева (нужно прочитать и принять решение осознанно),
   добровольные — без подложки и чуть более приглушённым текстом, чтобы
   визуально не сливаться со стеной одинаковых чекбоксов. */
#register-form .checkbox-row:has(#terms-consent),
#register-form .checkbox-row:has(#pdn-consent) {
  align-items: flex-start;
  background: var(--bg);
  border-left: 3px solid var(--navy);
  border-radius: var(--radius-sm);
  padding: 0.55rem 0.7rem;
}
#register-form .checkbox-row:has(#terms-consent) input,
#register-form .checkbox-row:has(#pdn-consent) input {
  margin-top: 0.2rem;
}
#register-form .checkbox-row:has(#distribution-consent),
#register-form .checkbox-row:has(#marketing-consent) {
  align-items: flex-start;
  padding: 0 0.1rem;
}
#register-form .checkbox-row:has(#distribution-consent) input,
#register-form .checkbox-row:has(#marketing-consent) input {
  margin-top: 0.2rem;
}
#register-form .checkbox-row:has(#distribution-consent) label,
#register-form .checkbox-row:has(#marketing-consent) label {
  color: var(--muted);
  font-size: var(--fs-sm);
}

/* Форма поиска покупателя (решения владельца 2026-09-10): в верхней строке
   формы — заголовок слева, «Состояние» по центру, сортировка справа. На
   телефоне строка складывается: заголовок, сортировка, затем «Состояние» —
   прямо перед полем «Название детали». */
.search-form-head {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  grid-template-areas: "title condition sort";
  align-items: center;
  gap: 0.6rem 1rem;
}
.search-form-head .search-form-title { grid-area: title; }
.search-form-head .search-condition { grid-area: condition; display: flex; align-items: center; gap: 0.6rem; }
.search-form-head .search-condition > label { margin: 0; }
.search-form-head .condition-tabs { margin: 0; }
.search-form-head .search-sort-row { grid-area: sort; justify-self: end; }
.search-form-footer { justify-content: flex-end; }
@media (max-width: 720px) {
  .search-form-head {
    grid-template-columns: 1fr;
    grid-template-areas: "title" "sort" "condition";
  }
  .search-form-head .search-sort-row { justify-self: stretch; justify-content: space-between; }
  .search-form-head .search-condition { flex-direction: column; align-items: flex-start; gap: 0.35rem; }
}

/* ─── Навигация длинных служебных страниц — public/js/page-nav.js ────────
   Кнопка "Назад" в одной строке с h1, справа; на узких экранах, где ей не
   хватает места рядом с заголовком, flex-wrap переносит её на следующую
   строку — так она не налезает на текст заголовка. Кнопка "Вверх" —
   последним элементом страницы, отдельной центрированной строкой. */
.page-header-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 0.5rem 0.75rem;
}
.page-header-row h1 { margin-bottom: 0; }
.page-back-btn { flex: none; white-space: nowrap; }

.page-top-btn {
  display: block;
  margin: 2rem auto 0;
}

/* ─── login.html / register.html: иконки соцсетей + попап помощи (решение
   владельца 2026-09-11) ──────────────────────────────────────────────────
   Раньше кнопки VK ID/Яндекс ID были текстовыми (.btn.btn-outline.btn-sm),
   теперь — компактный ряд круглых иконок с фирменным цветом сервиса и
   буквенным знаком внутри (VK/OK/@/Я — рисовать точный логотип каждого
   сервиса рискованно, буквенный знак в фирменном круге безопаснее и всё
   равно узнаваем). Поведение кнопок не меняется — public/js/auth.js
   продолжает искать их по классу .oauth-btn и атрибуту data-provider. */
.oauth-icon-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; }
.oauth-icon-label { width: 100%; font-size: var(--fs-sm); color: var(--muted); margin-bottom: 0.1rem; }
.oauth-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  line-height: 0;
  cursor: pointer;
  transition: transform 0.1s ease, box-shadow 0.15s ease;
}
.oauth-icon-btn svg { width: 40px; height: 40px; display: block; border-radius: 50%; }
.oauth-icon-btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.oauth-icon-btn:active { transform: translateY(0); }
.oauth-icon-btn:focus-visible { border-radius: 50%; }
.oauth-icon-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; box-shadow: none; }

/* Иконка помощи — кружок "?" в углу карточки формы входа/регистрации
   (решение владельца 2026-09-11): человеку, которому что-то не ясно, нужен
   явный путь к живому человеку, а не только к автоматике SMS/соцсети.
   .auth-card задаёт position:relative, чтобы кнопка и попап отсчитывались
   от карточки, а не от всей страницы. */
.auth-card { position: relative; }
.help-icon-btn {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1.5px solid var(--navy);
  background: var(--card-bg);
  color: var(--navy);
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 5;
}
.help-icon-btn:hover { background: var(--navy); color: #fff; }
.help-popover {
  position: absolute;
  z-index: 30;
  top: calc(0.75rem + 36px);
  right: 0.75rem;
  width: min(300px, calc(100vw - 2.5rem));
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  padding: 0.9rem 1.75rem 0.9rem 1rem;
}
.help-popover[hidden] { display: none; }
.help-popover-close {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  background: none;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  cursor: pointer;
}
.help-popover-close:hover { background: var(--bg); color: var(--danger); }
.help-popover-text { margin: 0 0 0.6rem; font-size: var(--fs-sm); }
.help-popover-phone { display: block; font-size: var(--fs-lg); font-weight: 700; color: var(--navy); margin-bottom: 0.35rem; }
.help-popover-hours { margin: 0; }
@media (max-width: 480px) {
  .help-icon-btn { top: 0.6rem; right: 0.6rem; }
  .help-popover { top: calc(0.6rem + 34px); right: 0.6rem; }
}

/* ─── Поле пароля с кнопкой-глазом (login.html/register.html/
   reset-password.html, решение владельца 2026-09-11) — иконка справа
   внутри поля, переключает type password/text. padding-right у input не
   даёт тексту заезжать под кнопку. */
.password-field { position: relative; }
.password-field input { padding-right: 2.6rem; }
.password-toggle-btn {
  position: absolute;
  top: 50%;
  right: 0.35rem;
  transform: translateY(-50%);
  width: 30px;
  height: 30px;
  padding: 0;
  border: none;
  background: none;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  cursor: pointer;
}
.password-toggle-btn:hover { color: var(--navy); background: var(--bg); }
.password-toggle-btn:focus-visible { outline: 2px solid var(--amber-dark); outline-offset: 1px; }
.password-toggle-btn svg { display: block; }
.password-toggle-btn svg[hidden] { display: none; }

/* Подсказка под полем "Повторите пароль", когда значения не совпадают
   (решение владельца 2026-09-11) — показывается/скрывается public/js/auth.js,
   тем же приёмом (style.display), что и остальные подсказки на этой
   странице. Поле дополнительно подсвечивается классом is-invalid (см. выше
   в файле). */
.field-hint-error { margin: 0.35rem 0 0; font-size: var(--fs-sm); color: var(--danger); }

/* Предупреждение об удалении аккаунта без подтверждённого номера (решение
   владельца 2026-09-11) — одинаковый текст на экране "аккаунт создан"
   (register.html) и в отказе входа с неподтверждённым номером (login.html). */
.account-deletion-warning { margin: 0.5rem 0; font-size: var(--fs-sm); font-weight: 600; color: var(--danger); }

/* Панель массового изменения товаров и услуг в кабинете продавца (владелец
   2026-09-11: «поля категория и состояние можно же в одну строку, сузив»).
   Общее правило input/select { width:100% } растягивало каждое поле на всю
   строку — здесь поля умеренной ширины и встают в ряд; на телефоне — снова
   на всю ширину. */
.bulk-toolbar select,
.bulk-toolbar input {
  width: auto;
  flex: 0 1 13rem;
  min-width: 9rem;
  padding: 0.4rem 0.55rem;
}
.bulk-toolbar input[type="number"] { flex-basis: 9rem; }
@media (max-width: 560px) {
  .bulk-toolbar select,
  .bulk-toolbar input { flex: 1 1 100%; }
}

/* ─── «Входящие запросы» / «Заказы» в кабинете продавца — вкладки
   «Товары»/«Услуги» с числом + компактная форма поиска (задача владельца
   2026-09-11: «Заказы» отдельным табом, в обоих — по 2 таба, чтобы
   компактнее отображать, и форма поиска, чтобы находить всё нужное).
   Кнопки вкладок — обычные btn-outline btn-sm, активная подсвечивается уже
   существующим .active-subtab (см. выше, admin-buyer-history-tab-btn). */
.kind-subtabs { display: flex; gap: 0.5rem; margin-bottom: 0.75rem; flex-wrap: wrap; }
.kind-subtab-count { font-weight: 400; opacity: 0.85; }

/* Форма поиска — одна-две строки на десктопе, столбиком на телефоне (общее
   правило компактности CLAUDE.md для любого списка сайта). */
.compact-filter-card { display: flex; flex-direction: column; gap: 0.6rem; margin-bottom: 1rem; }
.compact-filter-row { display: flex; flex-wrap: wrap; gap: 0.6rem 0.9rem; align-items: end; }
.compact-filter-row > div { min-width: 8.5rem; flex: 1 1 8.5rem; }
.compact-filter-row label { margin-bottom: 0.25rem; }
.compact-filter-actions { display: flex; gap: 0.5rem; }
@media (max-width: 640px) {
  .compact-filter-row { flex-direction: column; align-items: stretch; }
  .compact-filter-row > div { min-width: 0; }
  .compact-filter-actions { flex-direction: column; }
  .compact-filter-actions .btn { width: 100%; }
}

/* ─── Блок «Аналоги (кроссы)» — карточка товара и результаты поиска
   (задача владельца 2026-09-13, вариант 1 макета: аккордеон групп по
   cross_type). Группы — по ТИПУ кросса (оригинал/заводская замена/аналог/
   не уточнён), НЕ по качеству бренда — справочника брендов ещё нет (см.
   design/mockups/analogs/notes.md). Разметка рассчитана так, чтобы вторая
   ось (качество) могла добавиться позже вторым бейджем в шапке группы или
   вложенной подгруппой — не переделкой .analog-group/.analog-row. */
.analog-block { font-size: 0.92rem; }
.analog-group {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: 0.6rem;
  overflow: hidden;
}
.analog-group-head {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  background: var(--bg);
  border: none;
  padding: 0.6rem 0.85rem;
  cursor: pointer;
  font: inherit;
  text-align: left;
  color: inherit;
}
.analog-group-head:hover { background: #eef0f4; }
.analog-group-head-left { display: flex; align-items: center; gap: 0.55rem; flex-wrap: wrap; }
.analog-group-meta { font-size: var(--fs-sm); color: var(--muted); }
.analog-group-chevron { transition: transform 0.15s ease; flex: none; }
.analog-group-head[aria-expanded="true"] .analog-group-chevron { transform: rotate(180deg); }
.analog-group-body { padding: 0.7rem 0.85rem 0.35rem; }
.analog-group-body[hidden] { display: none; }

.analog-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.55rem 0.8rem;
  margin-bottom: 0.45rem;
  cursor: pointer;
}
.analog-row:last-child { margin-bottom: 0; }
.analog-row:hover, .analog-row:focus-visible { border-color: var(--amber); outline: none; }
.analog-row-main { min-width: 0; }
.analog-row-title { font-weight: 600; }
.analog-row-count { flex: none; text-align: right; display: flex; flex-direction: column; align-items: flex-end; gap: 0.2rem; }
.analog-row-count .count-pill { font-size: var(--fs-sm); color: var(--text); white-space: nowrap; }
.analog-row-count .count-pill b { color: var(--amber-dark); }
.analog-row-count .row-cta { font-size: var(--fs-xs); color: var(--navy); font-weight: 600; white-space: nowrap; }

/* Бейдж «тип кросса» в шапке группы — цвета по терминологии, уже принятой
   в public/js/vin-catalog.js (MATCH_TYPE_LABEL): оригинал — «информация о
   заводе» (--info), заводская замена — «работает как надо» (--success),
   аналог/не уточнён — нейтральный (без нового цвета), чтобы взгляд не
   считывал их как одобрение/неодобрение. */
.badge-cross-original { color: var(--info); background: var(--info-bg); border-color: var(--info-border); }
.badge-cross-replacement { color: var(--success); background: var(--success-bg); border-color: var(--success-border); }
.badge-cross-analog { color: var(--muted); background: var(--bg); border-color: var(--border); }
.badge-cross-unspecified { color: var(--muted); background: var(--bg); border-color: var(--border); border-style: dashed; }

.analog-section-title { font-size: var(--fs-lg); margin: 0 0 0.15rem; }

/* Заголовок «Аналоги X Y» на странице поиска после перехода из блока
   аналогов (public/js/catalog.js, п.5-6 задачи владельца). */
#analog-of-banner h2 { margin: 0 0 0.25rem; font-size: var(--fs-lg); }

@media (max-width: 480px) {
  .analog-row { flex-wrap: wrap; }
  .analog-row-count { flex-direction: row; align-items: center; justify-content: space-between; width: 100%; text-align: left; }
  .analog-group-head { flex-wrap: wrap; row-gap: 0.35rem; }
}

/* "В этом регионе/городе нет ни одной точки" — заявка (блок "Зона работы",
   решение владельца 14.09.2026, см. public/js/catalog.js:
   renderRegionRequestHint). Карточка вместо голого текста "Ничего не
   найдено" — то же оформление, что у остальных информационных блоков
   поиска (.card), только с чуть меньшим отступом сверху у формы. */
.region-request-hint .grid-form { margin-top: 0.75rem; }
.region-request-hint .checkbox-row { margin: 0.5rem 0; }
/* .grid-form и .btn задают свой display той же специфичностью, что и
   встроенное [hidden] { display:none } — тот же приём, что и у
   .search-form-extra[hidden] выше по файлу: без своих правил скрытые форма
   и кнопка "Оставить заявку" остались бы видны. */
#region-request-form[hidden] { display: none; }
#region-request-open[hidden] { display: none; }

/* Находка тестировщика V-7: на экране 375 px плавающая кнопка чата
   (#support-widget-btn, создаётся в public/js/api.js с inline-стилями)
   перекрывала вторую строку чекбокса «Учесть график работы» и последние
   буквы заголовков карточек товара — на самом узком поддерживаемом экране
   кнопка 56 px с отступом 1.25rem занимает заметную долю ширины.

   Правится здесь, а не в api.js: там стиль задан через cssText одной
   строкой, а поведение нужно только на узких экранах. !important — потому
   что inline-стиль иначе выигрывает у любого селектора.

   Отступ снизу у main нужен отдельно: без него последний элемент страницы
   оказывается под кнопкой, и до него нельзя дотянуться пальцем. */
@media (max-width: 480px) {
  #support-widget-btn {
    width: 44px !important;
    height: 44px !important;
    right: 0.6rem !important;
    bottom: 0.6rem !important;
  }
  #support-widget-btn svg { width: 20px; height: 20px; }
  #support-widget-panel {
    right: 0.6rem !important;
    bottom: 3.6rem !important;
  }
  main { padding-bottom: 3.5rem; }
}
